1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-25 22:42:04 +02:00

Bring back cbc in CAdventureAI and rename the rest to cc

This commit is contained in:
Mircea TheHonestCTO
2025-08-16 20:17:18 +02:00
parent 6eb7bb2ca5
commit bf3d5627e0
46 changed files with 319 additions and 317 deletions

View File

@@ -40,7 +40,7 @@ namespace NK2AI
{ {
//one thread may be turn of AI and another will be handling a side effect for AI2 //one thread may be turn of AI and another will be handling a side effect for AI2
thread_local CCallback * cbcTl = nullptr; thread_local CCallback * ccTl = nullptr;
thread_local AIGateway * aiGwTl = nullptr; thread_local AIGateway * aiGwTl = nullptr;
//helper RAII to manage global ai/cb ptrs //helper RAII to manage global ai/cb ptrs
@@ -49,17 +49,17 @@ struct SetGlobalState
SetGlobalState(AIGateway * gateway) SetGlobalState(AIGateway * gateway)
{ {
assert(!aiGwTl); assert(!aiGwTl);
assert(!cbcTl); assert(!ccTl);
aiGwTl = gateway; aiGwTl = gateway;
cbcTl = gateway->cbc.get(); ccTl = gateway->cc.get();
} }
~SetGlobalState() ~SetGlobalState()
{ {
//TODO: how to handle rm? shouldn't be called after ai is destroyed, hopefully //TODO: how to handle rm? shouldn't be called after ai is destroyed, hopefully
//TODO: to ensure that, make rm unique_ptr //TODO: to ensure that, make rm unique_ptr
aiGwTl = nullptr; aiGwTl = nullptr;
cbcTl = nullptr; ccTl = nullptr;
} }
}; };
@@ -97,7 +97,7 @@ void AIGateway::heroMoved(const TryMoveHero & details, bool verbose)
LOG_TRACE(logAi); LOG_TRACE(logAi);
NET_EVENT_HANDLER; NET_EVENT_HANDLER;
auto hero = cbc->getHero(details.id); auto hero = cc->getHero(details.id);
if(!hero) if(!hero)
validateObject(details.id); //enemy hero may have left visible area validateObject(details.id); //enemy hero may have left visible area
@@ -107,8 +107,8 @@ void AIGateway::heroMoved(const TryMoveHero & details, bool verbose)
const int3 from = hero ? hero->convertToVisitablePos(details.start) : (details.start - int3(0,1,0)); const int3 from = hero ? hero->convertToVisitablePos(details.start) : (details.start - int3(0,1,0));
const int3 to = hero ? hero->convertToVisitablePos(details.end) : (details.end - int3(0,1,0)); const int3 to = hero ? hero->convertToVisitablePos(details.end) : (details.end - int3(0,1,0));
const CGObjectInstance * o1 = vstd::frontOrNull(cbc->getVisitableObjs(from, verbose)); const CGObjectInstance * o1 = vstd::frontOrNull(cc->getVisitableObjs(from, verbose));
const CGObjectInstance * o2 = vstd::frontOrNull(cbc->getVisitableObjs(to, verbose)); const CGObjectInstance * o2 = vstd::frontOrNull(cc->getVisitableObjs(to, verbose));
if(details.result == TryMoveHero::TELEPORTATION) if(details.result == TryMoveHero::TELEPORTATION)
{ {
@@ -116,7 +116,7 @@ void AIGateway::heroMoved(const TryMoveHero & details, bool verbose)
auto t2 = dynamic_cast<const CGTeleport *>(o2); auto t2 = dynamic_cast<const CGTeleport *>(o2);
if(t1 && t2) if(t1 && t2)
{ {
if(cbc->isTeleportChannelBidirectional(t1->channel)) if(cc->isTeleportChannelBidirectional(t1->channel))
{ {
if(o1->ID == Obj::SUBTERRANEAN_GATE && o1->ID == o2->ID) // We need to only add subterranean gates in knownSubterraneanGates. Used for features not yet ported to use teleport channels if(o1->ID == Obj::SUBTERRANEAN_GATE && o1->ID == o2->ID) // We need to only add subterranean gates in knownSubterraneanGates. Used for features not yet ported to use teleport channels
{ {
@@ -134,7 +134,7 @@ void AIGateway::heroMoved(const TryMoveHero & details, bool verbose)
{ {
auto boat = dynamic_cast<const CGBoat *>(o1); auto boat = dynamic_cast<const CGBoat *>(o1);
if(boat) if(boat)
memorizeVisitableObj(boat, nullkiller->memory, nullkiller->dangerHitMap, playerID, cbc); memorizeVisitableObj(boat, nullkiller->memory, nullkiller->dangerHitMap, playerID, cc);
} }
} }
@@ -214,7 +214,7 @@ void AIGateway::gameOver(PlayerColor player, const EVictoryLossCheckResult & vic
if(victoryLossCheckResult.victory()) if(victoryLossCheckResult.victory())
{ {
logAi->debug("AIGateway: Player %d (%s) won. I won! Incredible!", player, player.toString()); logAi->debug("AIGateway: Player %d (%s) won. I won! Incredible!", player, player.toString());
logAi->debug("Turn nr %d", cbc->getDate()); logAi->debug("Turn nr %d", cc->getDate());
} }
else else
{ {
@@ -274,7 +274,7 @@ void AIGateway::tileHidden(const FowTilesType & pos)
LOG_TRACE(logAi); LOG_TRACE(logAi);
NET_EVENT_HANDLER; NET_EVENT_HANDLER;
nullkiller->memory->removeInvisibleObjects(cbc.get()); nullkiller->memory->removeInvisibleObjects(cc.get());
} }
void AIGateway::tileRevealed(const FowTilesType & pos) void AIGateway::tileRevealed(const FowTilesType & pos)
@@ -283,8 +283,8 @@ void AIGateway::tileRevealed(const FowTilesType & pos)
NET_EVENT_HANDLER; NET_EVENT_HANDLER;
for(int3 tile : pos) for(int3 tile : pos)
{ {
for(const CGObjectInstance * obj : cbc->getVisitableObjs(tile)) for(const CGObjectInstance * obj : cc->getVisitableObjs(tile))
memorizeVisitableObj(obj, nullkiller->memory, nullkiller->dangerHitMap, playerID, cbc); memorizeVisitableObj(obj, nullkiller->memory, nullkiller->dangerHitMap, playerID, cc);
} }
if (nullkiller->settings->isUpdateHitmapOnTileReveal() && !pos.empty()) if (nullkiller->settings->isUpdateHitmapOnTileReveal() && !pos.empty())
@@ -296,8 +296,8 @@ void AIGateway::heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID her
LOG_TRACE(logAi); LOG_TRACE(logAi);
NET_EVENT_HANDLER; NET_EVENT_HANDLER;
auto firstHero = cbc->getHero(hero1); auto firstHero = cc->getHero(hero1);
auto secondHero = cbc->getHero(hero2); auto secondHero = cc->getHero(hero2);
status.addQuery(query, boost::str(boost::format("Exchange between heroes %s (%d) and %s (%d)") % firstHero->getNameTranslated() % firstHero->tempOwner % secondHero->getNameTranslated() % secondHero->tempOwner)); status.addQuery(query, boost::str(boost::format("Exchange between heroes %s (%d) and %s (%d)") % firstHero->getNameTranslated() % firstHero->tempOwner % secondHero->getNameTranslated() % secondHero->tempOwner));
@@ -306,7 +306,7 @@ void AIGateway::heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID her
auto transferFrom2to1 = [this](const CGHeroInstance * h1, const CGHeroInstance * h2) -> void auto transferFrom2to1 = [this](const CGHeroInstance * h1, const CGHeroInstance * h2) -> void
{ {
this->pickBestCreatures(h1, h2); this->pickBestCreatures(h1, h2);
pickBestArtifacts(cbc, h1, h2); pickBestArtifacts(cc, h1, h2);
}; };
//Do not attempt army or artifacts exchange if we visited ally player //Do not attempt army or artifacts exchange if we visited ally player
@@ -370,7 +370,7 @@ void AIGateway::newObject(const CGObjectInstance * obj)
NET_EVENT_HANDLER; NET_EVENT_HANDLER;
nullkiller->invalidatePathfinderData(); nullkiller->invalidatePathfinderData();
if(obj->isVisitable()) if(obj->isVisitable())
memorizeVisitableObj(obj, nullkiller->memory, nullkiller->dangerHitMap, playerID, cbc); memorizeVisitableObj(obj, nullkiller->memory, nullkiller->dangerHitMap, playerID, cc);
} }
//to prevent AI from accessing objects that got deleted while they became invisible (Cover of Darkness, enemy hero moved etc.) below code allows AI to know deletion of objects out of sight //to prevent AI from accessing objects that got deleted while they became invisible (Cover of Darkness, enemy hero moved etc.) below code allows AI to know deletion of objects out of sight
@@ -393,10 +393,10 @@ void AIGateway::objectRemoved(const CGObjectInstance * obj, const PlayerColor &
if(obj->ID == Obj::HERO && obj->tempOwner == playerID) if(obj->ID == Obj::HERO && obj->tempOwner == playerID)
{ {
lostHero(cbc->getHero(obj->id)); //we can promote, since objectRemoved is called just before actual deletion lostHero(cc->getHero(obj->id)); //we can promote, since objectRemoved is called just before actual deletion
} }
if(obj->ID == Obj::HERO && cbc->getPlayerRelations(obj->tempOwner, playerID) == PlayerRelations::ENEMIES) if(obj->ID == Obj::HERO && cc->getPlayerRelations(obj->tempOwner, playerID) == PlayerRelations::ENEMIES)
nullkiller->dangerHitMap->resetHitmap(); nullkiller->dangerHitMap->resetHitmap();
if(obj->ID == Obj::TOWN) if(obj->ID == Obj::TOWN)
@@ -500,8 +500,8 @@ void AIGateway::objectPropertyChanged(const SetObjectProperty * sop)
NET_EVENT_HANDLER; NET_EVENT_HANDLER;
if(sop->what == ObjProperty::OWNER) if(sop->what == ObjProperty::OWNER)
{ {
auto relations = cbc->getPlayerRelations(playerID, sop->identifier.as<PlayerColor>()); auto relations = cc->getPlayerRelations(playerID, sop->identifier.as<PlayerColor>());
auto obj = cbc->getObj(sop->id, false); auto obj = cc->getObj(sop->id, false);
if(!nullkiller) // crash protection if(!nullkiller) // crash protection
return; return;
@@ -565,7 +565,7 @@ std::optional<BattleAction> AIGateway::makeSurrenderRetreatDecision(const Battle
double fightRatio = ourStrength / (double)battleState.getEnemyStrength(); double fightRatio = ourStrength / (double)battleState.getEnemyStrength();
// if we have no towns - things are already bad, so retreat is not an option. // if we have no towns - things are already bad, so retreat is not an option.
if(cbc->getTownsInfo().size() && ourStrength < nullkiller->settings->getRetreatThresholdAbsolute() && fightRatio < nullkiller->settings->getRetreatThresholdRelative() && battleState.canFlee) if(cc->getTownsInfo().size() && ourStrength < nullkiller->settings->getRetreatThresholdAbsolute() && fightRatio < nullkiller->settings->getRetreatThresholdRelative() && battleState.canFlee)
{ {
return BattleAction::makeRetreat(battleState.ourSide); return BattleAction::makeRetreat(battleState.ourSide);
} }
@@ -574,19 +574,20 @@ std::optional<BattleAction> AIGateway::makeSurrenderRetreatDecision(const Battle
} }
void AIGateway::initGameInterface(std::shared_ptr<Environment> env, std::shared_ptr<CCallback> CB) void AIGateway::initGameInterface(std::shared_ptr<Environment> env, std::shared_ptr<CCallback> callback)
{ {
LOG_TRACE(logAi); LOG_TRACE(logAi);
cbc = CB; cbc = callback;
cc = callback;
this->env = env; this->env = env;
NET_EVENT_HANDLER; NET_EVENT_HANDLER;
playerID = *cbc->getPlayerID(); playerID = *cc->getPlayerID();
cbc->waitTillRealize = true; cc->waitTillRealize = true;
nullkiller->init(CB, this); nullkiller->init(callback, this);
memorizeVisitableObjs(nullkiller->memory, nullkiller->dangerHitMap, playerID, cbc); memorizeVisitableObjs(nullkiller->memory, nullkiller->dangerHitMap, playerID, cc);
} }
void AIGateway::yourTurn(QueryID queryID) void AIGateway::yourTurn(QueryID queryID)
@@ -656,7 +657,7 @@ void AIGateway::showBlockingDialog(const std::string & text, const std::vector<C
{ {
//yes&no -> always answer yes, we are a brave AI :) //yes&no -> always answer yes, we are a brave AI :)
bool answer = true; bool answer = true;
auto objects = cbc->getVisitableObjs(target); auto objects = cc->getVisitableObjs(target);
if(hero.validAndSet() && target.isValid() && objects.size()) if(hero.validAndSet() && target.isValid() && objects.size())
{ {
@@ -676,9 +677,9 @@ void AIGateway::showBlockingDialog(const std::string & text, const std::vector<C
logAi->trace("Query hook: %s(%s) by %s danger ratio %f", target.toString(), topObj->getObjectName(), hero.name(), ratio); logAi->trace("Query hook: %s(%s) by %s danger ratio %f", target.toString(), topObj->getObjectName(), hero.name(), ratio);
if(cbc->getObj(goalObjectID, false)) if(cc->getObj(goalObjectID, false))
{ {
logAi->trace("AI expected %s", cbc->getObj(goalObjectID, false)->getObjectName()); logAi->trace("AI expected %s", cc->getObj(goalObjectID, false)->getObjectName());
} }
if(objType == Obj::BORDERGUARD || objType == Obj::QUEST_GUARD) if(objType == Obj::BORDERGUARD || objType == Obj::QUEST_GUARD)
@@ -753,7 +754,7 @@ void AIGateway::showTeleportDialog(const CGHeroInstance * hero, TeleportChannelI
{ {
// TODO: Implement checking if visiting that teleport will uncovert any FoW // TODO: Implement checking if visiting that teleport will uncovert any FoW
// So far this is the best option to handle decision about probing // So far this is the best option to handle decision about probing
auto obj = cbc->getObj(exit.first, false); auto obj = cc->getObj(exit.first, false);
if(obj == nullptr && !vstd::contains(teleportChannelProbingList, exit.first)) if(obj == nullptr && !vstd::contains(teleportChannelProbingList, exit.first))
{ {
if(exit.first != destinationTeleport) if(exit.first != destinationTeleport)
@@ -781,7 +782,7 @@ void AIGateway::showGarrisonDialog(const CArmedInstance * up, const CGHeroInstan
//you can't request action from action-response thread //you can't request action from action-response thread
executeActionAsync("showGarrisonDialog", [this, up, down, removableUnits, queryID]() executeActionAsync("showGarrisonDialog", [this, up, down, removableUnits, queryID]()
{ {
if(removableUnits && up->tempOwner == down->tempOwner && nullkiller->settings->isGarrisonTroopsUsageAllowed() && !cbc->getStartInfo()->restrictedGarrisonsForAI()) if(removableUnits && up->tempOwner == down->tempOwner && nullkiller->settings->isGarrisonTroopsUsageAllowed() && !cc->getStartInfo()->restrictedGarrisonsForAI())
{ {
pickBestCreatures(down, up); pickBestCreatures(down, up);
} }
@@ -811,7 +812,7 @@ bool AIGateway::makePossibleUpgrades(const CArmedInstance * obj)
UpgradeInfo upgradeInfo(s->getId()); UpgradeInfo upgradeInfo(s->getId());
do do
{ {
cbc->fillUpgradeInfo(obj, SlotID(i), upgradeInfo); cc->fillUpgradeInfo(obj, SlotID(i), upgradeInfo);
if(upgradeInfo.hasUpgrades()) if(upgradeInfo.hasUpgrades())
{ {
@@ -826,7 +827,7 @@ bool AIGateway::makePossibleUpgrades(const CArmedInstance * obj)
if(newValue > oldValue && nullkiller->getFreeResources().canAfford(upgradeInfo.getUpgradeCostsFor(upgID) * s->getCount())) if(newValue > oldValue && nullkiller->getFreeResources().canAfford(upgradeInfo.getUpgradeCostsFor(upgID) * s->getCount()))
{ {
cbc->upgradeCreature(obj, SlotID(i), upgID); cc->upgradeCreature(obj, SlotID(i), upgID);
upgraded = true; upgraded = true;
logAi->debug("Upgraded %d %s to %s", s->getCount(), upgradeInfo.oldID.toCreature()->getNamePluralTranslated(), logAi->debug("Upgraded %d %s to %s", s->getCount(), upgradeInfo.oldID.toCreature()->getNamePluralTranslated(),
upgradeInfo.getUpgrade().toCreature()->getNamePluralTranslated()); upgradeInfo.getUpgrade().toCreature()->getNamePluralTranslated());
@@ -846,21 +847,21 @@ void AIGateway::makeTurn()
{ {
MAKING_TURN; MAKING_TURN;
auto day = cbc->getDate(Date::DAY); auto day = cc->getDate(Date::DAY);
logAi->info("Player %d (%s) starting turn, day %d", playerID, playerID.toString(), day); logAi->info("Player %d (%s) starting turn, day %d", playerID, playerID.toString(), day);
std::shared_lock gsLock(CGameState::mutex); std::shared_lock gsLock(CGameState::mutex);
cheatMapReveal(nullkiller); cheatMapReveal(nullkiller);
memorizeVisitableObjs(nullkiller->memory, nullkiller->dangerHitMap, playerID, cbc); memorizeVisitableObjs(nullkiller->memory, nullkiller->dangerHitMap, playerID, cc);
memorizeRevisitableObjs(nullkiller->memory, playerID, cbc); memorizeRevisitableObjs(nullkiller->memory, playerID, cc);
try try
{ {
nullkiller->makeTurn(); nullkiller->makeTurn();
// for debug purpose // for debug purpose
for (const auto *h : cbc->getHeroesInfo()) for (const auto *h : cc->getHeroesInfo())
{ {
if (h->movementPointsRemaining()) if (h->movementPointsRemaining())
logAi->info("Hero %s has %d MP left", h->getNameTranslated(), h->movementPointsRemaining()); logAi->info("Hero %s has %d MP left", h->getNameTranslated(), h->movementPointsRemaining());
@@ -905,7 +906,7 @@ void AIGateway::performObjectInteraction(const CGObjectInstance * obj, HeroPtr h
&& nullkiller->getFreeGold() >= GameConstants::SPELLBOOK_GOLD_COST) && nullkiller->getFreeGold() >= GameConstants::SPELLBOOK_GOLD_COST)
{ {
if(h->getVisitedTown()->hasBuilt(BuildingID::MAGES_GUILD_1)) if(h->getVisitedTown()->hasBuilt(BuildingID::MAGES_GUILD_1))
cbc->buyArtifact(h.get(), ArtifactID::SPELLBOOK); cc->buyArtifact(h.get(), ArtifactID::SPELLBOOK);
} }
} }
break; break;
@@ -930,14 +931,14 @@ void AIGateway::pickBestCreatures(const CArmedInstance * destinationArmy, const
const CArmedInstance * armies[] = {destinationArmy, source}; const CArmedInstance * armies[] = {destinationArmy, source};
auto bestArmy = nullkiller->armyManager->getBestArmy(destinationArmy, destinationArmy, source, cbc->getTile(source->visitablePos())->getTerrainID()); auto bestArmy = nullkiller->armyManager->getBestArmy(destinationArmy, destinationArmy, source, cc->getTile(source->visitablePos())->getTerrainID());
for(auto army : armies) for(auto army : armies)
{ {
// move first stack at first slot if empty to avoid can not take away last creature // move first stack at first slot if empty to avoid can not take away last creature
if(!army->hasStackAtSlot(SlotID(0)) && army->stacksCount() > 0) if(!army->hasStackAtSlot(SlotID(0)) && army->stacksCount() > 0)
{ {
cbc->mergeOrSwapStacks( cc->mergeOrSwapStacks(
army, army,
army, army,
SlotID(0), SlotID(0),
@@ -958,12 +959,12 @@ void AIGateway::pickBestCreatures(const CArmedInstance * destinationArmy, const
if(targetSlot.validSlot()) if(targetSlot.validSlot())
{ {
// remove unwanted creatures // remove unwanted creatures
cbc->mergeOrSwapStacks(destinationArmy, source, i, targetSlot); cc->mergeOrSwapStacks(destinationArmy, source, i, targetSlot);
} }
else if(destinationArmy->getStack(i).getPower() < destinationArmy->getArmyStrength() / 100) else if(destinationArmy->getStack(i).getPower() < destinationArmy->getArmyStrength() / 100)
{ {
// dismiss creatures if the amount is small // dismiss creatures if the amount is small
cbc->dismissCreature(destinationArmy, i); cc->dismissCreature(destinationArmy, i);
} }
} }
@@ -984,7 +985,7 @@ void AIGateway::pickBestCreatures(const CArmedInstance * destinationArmy, const
&& source->stacksCount() == 1 && source->stacksCount() == 1
&& (!destinationArmy->hasStackAtSlot(i) || destinationArmy->getCreature(i) == targetCreature)) && (!destinationArmy->hasStackAtSlot(i) || destinationArmy->getCreature(i) == targetCreature))
{ {
auto weakest = nullkiller->armyManager->getBestUnitForScout(bestArmy, cbc->getTile(source->visitablePos())->getTerrainID()); auto weakest = nullkiller->armyManager->getBestUnitForScout(bestArmy, cc->getTile(source->visitablePos())->getTerrainID());
if(weakest->creature == targetCreature) if(weakest->creature == targetCreature)
{ {
@@ -992,7 +993,7 @@ void AIGateway::pickBestCreatures(const CArmedInstance * destinationArmy, const
break; break;
// move all except 1 of weakest creature from source to destination // move all except 1 of weakest creature from source to destination
cbc->splitStack( cc->splitStack(
source, source,
destinationArmy, destinationArmy,
j, j,
@@ -1004,7 +1005,7 @@ void AIGateway::pickBestCreatures(const CArmedInstance * destinationArmy, const
else else
{ {
// Source last stack is not weakest. Move 1 of weakest creature from destination to source // Source last stack is not weakest. Move 1 of weakest creature from destination to source
cbc->splitStack( cc->splitStack(
destinationArmy, destinationArmy,
source, source,
destinationArmy->getSlotFor(weakest->creature), destinationArmy->getSlotFor(weakest->creature),
@@ -1013,7 +1014,7 @@ void AIGateway::pickBestCreatures(const CArmedInstance * destinationArmy, const
} }
} }
cbc->mergeOrSwapStacks(armyPtr, destinationArmy, j, i); cc->mergeOrSwapStacks(armyPtr, destinationArmy, j, i);
} }
} }
} }
@@ -1044,7 +1045,7 @@ void AIGateway::recruitCreatures(const CGDwelling * d, const CArmedInstance * re
if(duplicatingSlot != stack.first) if(duplicatingSlot != stack.first)
{ {
cbc->mergeStacks(recruiter, recruiter, stack.first, duplicatingSlot); cc->mergeStacks(recruiter, recruiter, stack.first, duplicatingSlot);
break; break;
} }
} }
@@ -1055,9 +1056,9 @@ void AIGateway::recruitCreatures(const CGDwelling * d, const CArmedInstance * re
} }
} }
vstd::amin(count, cbc->getResourceAmount() / creID.toCreature()->getFullRecruitCost()); vstd::amin(count, cc->getResourceAmount() / creID.toCreature()->getFullRecruitCost());
if(count > 0) if(count > 0)
cbc->recruitCreatures(d, recruiter, creID, count, i); cc->recruitCreatures(d, recruiter, creID, count, i);
} }
} }
@@ -1066,7 +1067,7 @@ void AIGateway::battleStart(const BattleID & battleID, const CCreatureSet * army
NET_EVENT_HANDLER; NET_EVENT_HANDLER;
assert(!playerID.isValidPlayer() || status.getBattle() == UPCOMING_BATTLE); assert(!playerID.isValidPlayer() || status.getBattle() == UPCOMING_BATTLE);
status.setBattle(ONGOING_BATTLE); status.setBattle(ONGOING_BATTLE);
const CGObjectInstance * presumedEnemy = vstd::backOrNull(cbc->getVisitableObjs(tile)); //may be nullptr in some very are cases -> eg. visited monolith and fighting with an enemy at the FoW covered exit const CGObjectInstance * presumedEnemy = vstd::backOrNull(cc->getVisitableObjs(tile)); //may be nullptr in some very are cases -> eg. visited monolith and fighting with an enemy at the FoW covered exit
battlename = boost::str(boost::format("Starting battle of %s attacking %s at %s") % (hero1 ? hero1->getNameTranslated() : "a army") % (presumedEnemy ? presumedEnemy->getObjectName() : "unknown enemy") % tile.toString()); battlename = boost::str(boost::format("Starting battle of %s attacking %s at %s") % (hero1 ? hero1->getNameTranslated() : "a army") % (presumedEnemy ? presumedEnemy->getObjectName() : "unknown enemy") % tile.toString());
CAdventureAI::battleStart(battleID, army1, army2, tile, hero1, hero2, side, replayAllowed); CAdventureAI::battleStart(battleID, army1, army2, tile, hero1, hero2, side, replayAllowed);
} }
@@ -1076,14 +1077,14 @@ void AIGateway::battleEnd(const BattleID & battleID, const BattleResult * br, Qu
NET_EVENT_HANDLER; NET_EVENT_HANDLER;
assert(status.getBattle() == ONGOING_BATTLE); assert(status.getBattle() == ONGOING_BATTLE);
status.setBattle(ENDING_BATTLE); status.setBattle(ENDING_BATTLE);
bool won = br->winner == cbc->getBattle(battleID)->battleGetMySide(); bool won = br->winner == cc->getBattle(battleID)->battleGetMySide();
logAi->debug("Player %d (%s): I %s the %s!", playerID, playerID.toString(), (won ? "won" : "lost"), battlename); logAi->debug("Player %d (%s): I %s the %s!", playerID, playerID.toString(), (won ? "won" : "lost"), battlename);
battlename.clear(); battlename.clear();
CAdventureAI::battleEnd(battleID, br, queryID); CAdventureAI::battleEnd(battleID, br, queryID);
// gosolo // gosolo
if(queryID != QueryID::NONE && cbc->getPlayerState(playerID)->isHuman()) if(queryID != QueryID::NONE && cc->getPlayerState(playerID)->isHuman())
{ {
status.addQuery(queryID, "Confirm battle query"); status.addQuery(queryID, "Confirm battle query");
@@ -1115,7 +1116,7 @@ bool AIGateway::moveHeroToTile(int3 dst, HeroPtr h)
{ {
if(h->isGarrisoned() && h->getVisitedTown()) if(h->isGarrisoned() && h->getVisitedTown())
{ {
cbc->swapGarrisonHero(h->getVisitedTown()); cc->swapGarrisonHero(h->getVisitedTown());
moveCreaturesToHero(h->getVisitedTown()); moveCreaturesToHero(h->getVisitedTown());
} }
@@ -1141,7 +1142,7 @@ bool AIGateway::moveHeroToTile(int3 dst, HeroPtr h)
{ {
//FIXME: this assertion fails also if AI moves onto defeated guarded object //FIXME: this assertion fails also if AI moves onto defeated guarded object
//assert(cb->getVisitableObjs(dst).size() > 1); //there's no point in revisiting tile where there is no visitable object //assert(cb->getVisitableObjs(dst).size() > 1); //there's no point in revisiting tile where there is no visitable object
cbc->moveHero(*h, h->convertFromVisitablePos(dst), false); cc->moveHero(*h, h->convertFromVisitablePos(dst), false);
afterMovementCheck(); // TODO: is it feasible to hero get killed there if game work properly? afterMovementCheck(); // TODO: is it feasible to hero get killed there if game work properly?
// If revisiting, teleport probing is never done, and so the entries into the list would remain unused and uncleared // If revisiting, teleport probing is never done, and so the entries into the list would remain unused and uncleared
teleportChannelProbingList.clear(); teleportChannelProbingList.clear();
@@ -1161,9 +1162,9 @@ bool AIGateway::moveHeroToTile(int3 dst, HeroPtr h)
auto getObj = [&](int3 coord, bool ignoreHero) auto getObj = [&](int3 coord, bool ignoreHero)
{ {
auto tile = cbc->getTile(coord, false); auto tile = cc->getTile(coord, false);
assert(tile); assert(tile);
return cbc->getObj(tile->topVisitableObj(ignoreHero), false); return cc->getObj(tile->topVisitableObj(ignoreHero), false);
}; };
auto isTeleportAction = [&](EPathNodeAction action) -> bool auto isTeleportAction = [&](EPathNodeAction action) -> bool
@@ -1194,12 +1195,12 @@ bool AIGateway::moveHeroToTile(int3 dst, HeroPtr h)
auto doMovement = [&](int3 dst, bool transit) auto doMovement = [&](int3 dst, bool transit)
{ {
cbc->moveHero(*h, h->convertFromVisitablePos(dst), transit); cc->moveHero(*h, h->convertFromVisitablePos(dst), transit);
}; };
auto doTeleportMovement = [&](ObjectInstanceID exitId, int3 exitPos) auto doTeleportMovement = [&](ObjectInstanceID exitId, int3 exitPos)
{ {
if(cbc->getObj(exitId) && cbc->getObj(exitId)->ID == Obj::WHIRLPOOL) if(cc->getObj(exitId) && cc->getObj(exitId)->ID == Obj::WHIRLPOOL)
{ {
nullkiller->armyFormation->rearrangeArmyForWhirlpool(*h); nullkiller->armyFormation->rearrangeArmyForWhirlpool(*h);
} }
@@ -1207,7 +1208,7 @@ bool AIGateway::moveHeroToTile(int3 dst, HeroPtr h)
destinationTeleport = exitId; destinationTeleport = exitId;
if(exitPos.isValid()) if(exitPos.isValid())
destinationTeleportPos = exitPos; destinationTeleportPos = exitPos;
cbc->moveHero(*h, h->pos, false); cc->moveHero(*h, h->pos, false);
destinationTeleport = ObjectInstanceID(); destinationTeleport = ObjectInstanceID();
destinationTeleportPos = int3(-1); destinationTeleportPos = int3(-1);
afterMovementCheck(); afterMovementCheck();
@@ -1311,7 +1312,7 @@ bool AIGateway::moveHeroToTile(int3 dst, HeroPtr h)
} }
if(h) if(h)
{ {
if(auto visitedObject = vstd::frontOrNull(cbc->getVisitableObjs(h->visitablePos()))) //we stand on something interesting if(auto visitedObject = vstd::frontOrNull(cc->getVisitableObjs(h->visitablePos()))) //we stand on something interesting
{ {
if(visitedObject != *h) if(visitedObject != *h)
{ {
@@ -1338,7 +1339,7 @@ void AIGateway::buildStructure(const CGTownInstance * t, BuildingID building)
{ {
auto name = t->getTown()->buildings.at(building)->getNameTranslated(); auto name = t->getTown()->buildings.at(building)->getNameTranslated();
logAi->debug("Player %d will build %s in town of %s at %s", aiGwTl->playerID, name, t->getNameTranslated(), t->anchorPos().toString()); logAi->debug("Player %d will build %s in town of %s at %s", aiGwTl->playerID, name, t->getNameTranslated(), t->anchorPos().toString());
cbc->buildBuilding(t, building); //just do this; cc->buildBuilding(t, building); //just do this;
} }
void AIGateway::tryRealize(Goals::DigAtTile & g) void AIGateway::tryRealize(Goals::DigAtTile & g)
@@ -1346,7 +1347,7 @@ void AIGateway::tryRealize(Goals::DigAtTile & g)
assert(g.hero->visitablePos() == g.tile); //surely we want to crash here? assert(g.hero->visitablePos() == g.tile); //surely we want to crash here?
if(g.hero->diggingStatus() == EDiggingStatus::CAN_DIG) if(g.hero->diggingStatus() == EDiggingStatus::CAN_DIG)
{ {
cbc->dig(g.hero); cc->dig(g.hero);
} }
else else
{ {
@@ -1356,15 +1357,15 @@ void AIGateway::tryRealize(Goals::DigAtTile & g)
void AIGateway::tryRealize(Goals::Trade & g) //trade void AIGateway::tryRealize(Goals::Trade & g) //trade
{ {
if(cbc->getResourceAmount(GameResID(g.resID)) >= g.value) //goal is already fulfilled. Why we need this check, anyway? if(cc->getResourceAmount(GameResID(g.resID)) >= g.value) //goal is already fulfilled. Why we need this check, anyway?
throw goalFulfilledException(sptr(g)); throw goalFulfilledException(sptr(g));
int acquiredResources = 0; int acquiredResources = 0;
if(const CGObjectInstance * obj = cbc->getObj(ObjectInstanceID(g.objid), false)) if(const CGObjectInstance * obj = cc->getObj(ObjectInstanceID(g.objid), false))
{ {
if(const auto * m = dynamic_cast<const IMarket*>(obj)) if(const auto * m = dynamic_cast<const IMarket*>(obj))
{ {
auto freeRes = cbc->getResourceAmount(); //trade only resources which are not reserved auto freeRes = cc->getResourceAmount(); //trade only resources which are not reserved
for(auto it = ResourceSet::nziterator(freeRes); it.valid(); it++) for(auto it = ResourceSet::nziterator(freeRes); it.valid(); it++)
{ {
auto res = it->resType; auto res = it->resType;
@@ -1378,11 +1379,11 @@ void AIGateway::tryRealize(Goals::Trade & g) //trade
//TODO trade only as much as needed //TODO trade only as much as needed
if (toGive) //don't try to sell 0 resources if (toGive) //don't try to sell 0 resources
{ {
cbc->trade(m->getObjInstanceID(), EMarketMode::RESOURCE_RESOURCE, res, GameResID(g.resID), toGive); cc->trade(m->getObjInstanceID(), EMarketMode::RESOURCE_RESOURCE, res, GameResID(g.resID), toGive);
acquiredResources = static_cast<int>(toGet * (it->resVal / toGive)); acquiredResources = static_cast<int>(toGet * (it->resVal / toGive));
logAi->debug("Traded %d of %s for %d of %s at %s", toGive, res, acquiredResources, g.resID, obj->getObjectName()); logAi->debug("Traded %d of %s for %d of %s at %s", toGive, res, acquiredResources, g.resID, obj->getObjectName());
} }
if (cbc->getResourceAmount(GameResID(g.resID))) if (cc->getResourceAmount(GameResID(g.resID)))
throw goalFulfilledException(sptr(g)); //we traded all we needed throw goalFulfilledException(sptr(g)); //we traded all we needed
} }
@@ -1407,9 +1408,9 @@ void AIGateway::endTurn()
logAi->error("Not having turn at the end of turn???"); logAi->error("Not having turn at the end of turn???");
} }
logAi->debug("Resources at the end of turn: %s", cbc->getResourceAmount().toString()); logAi->debug("Resources at the end of turn: %s", cc->getResourceAmount().toString());
if(cbc->getPlayerStatus(playerID) != EPlayerStatus::INGAME) if(cc->getPlayerStatus(playerID) != EPlayerStatus::INGAME)
{ {
logAi->info("Ending turn is not needed because we already lost"); logAi->info("Ending turn is not needed because we already lost");
return; return;
@@ -1417,7 +1418,7 @@ void AIGateway::endTurn()
do do
{ {
cbc->endTurn(); cc->endTurn();
} }
while(status.haveTurn()); //for some reasons, our request may fail -> stop requesting end of turn only after we've received a confirmation that it's over while(status.haveTurn()); //for some reasons, our request may fail -> stop requesting end of turn only after we've received a confirmation that it's over
@@ -1468,7 +1469,7 @@ void AIGateway::answerQuery(QueryID queryID, int selection)
logAi->debug("I'll answer the query %d giving the choice %d", queryID, selection); logAi->debug("I'll answer the query %d giving the choice %d", queryID, selection);
if(queryID != QueryID(-1)) if(queryID != QueryID(-1))
{ {
cbc->selectionMade(selection, queryID); cc->selectionMade(selection, queryID);
} }
else else
{ {
@@ -1679,11 +1680,11 @@ void AIGateway::invalidatePaths()
void AIGateway::cheatMapReveal(const std::unique_ptr<Nullkiller> & nullkiller) void AIGateway::cheatMapReveal(const std::unique_ptr<Nullkiller> & nullkiller)
{ {
if(nullkiller->cbc->getDate(Date::DAY) == 1) // No need to execute every day, only the first time if(nullkiller->cc->getDate(Date::DAY) == 1) // No need to execute every day, only the first time
{ {
if(nullkiller->isOpenMap()) if(nullkiller->isOpenMap())
{ {
nullkiller->cbc->sendMessage("vcmieagles"); nullkiller->cc->sendMessage("vcmieagles");
} }
} }
} }
@@ -1691,14 +1692,14 @@ void AIGateway::cheatMapReveal(const std::unique_ptr<Nullkiller> & nullkiller)
void AIGateway::memorizeVisitableObjs(const std::unique_ptr<AIMemory> & memory, void AIGateway::memorizeVisitableObjs(const std::unique_ptr<AIMemory> & memory,
const std::unique_ptr<DangerHitMapAnalyzer> & dangerHitMap, const std::unique_ptr<DangerHitMapAnalyzer> & dangerHitMap,
const PlayerColor & playerID, const PlayerColor & playerID,
const std::shared_ptr<CCallback> & cbc) const std::shared_ptr<CCallback> & cc)
{ {
foreach_tile_pos([&](const int3 & pos) foreach_tile_pos([&](const int3 & pos)
{ {
// TODO: Inspect what not visible means when using verbose true // TODO: Inspect what not visible means when using verbose true
for(const CGObjectInstance * obj : cbc->getVisitableObjs(pos, false)) for(const CGObjectInstance * obj : cc->getVisitableObjs(pos, false))
{ {
memorizeVisitableObj(obj, memory, dangerHitMap, playerID, cbc); memorizeVisitableObj(obj, memory, dangerHitMap, playerID, cc);
} }
}); });
} }
@@ -1707,22 +1708,22 @@ void AIGateway::memorizeVisitableObj(const CGObjectInstance * obj,
const std::unique_ptr<AIMemory> & memory, const std::unique_ptr<AIMemory> & memory,
const std::unique_ptr<DangerHitMapAnalyzer> & dangerHitMap, const std::unique_ptr<DangerHitMapAnalyzer> & dangerHitMap,
const PlayerColor & playerID, const PlayerColor & playerID,
const std::shared_ptr<CCallback> & cbc) const std::shared_ptr<CCallback> & cc)
{ {
if(obj->ID == Obj::EVENT) if(obj->ID == Obj::EVENT)
return; return;
memory->addVisitableObject(obj); memory->addVisitableObject(obj);
if(obj->ID == Obj::HERO && cbc->getPlayerRelations(obj->tempOwner, playerID) == PlayerRelations::ENEMIES) if(obj->ID == Obj::HERO && cc->getPlayerRelations(obj->tempOwner, playerID) == PlayerRelations::ENEMIES)
{ {
dangerHitMap->resetHitmap(); dangerHitMap->resetHitmap();
} }
} }
void AIGateway::memorizeRevisitableObjs(const std::unique_ptr<AIMemory> & memory, const PlayerColor & playerID, const std::shared_ptr<CCallback> & cbc) void AIGateway::memorizeRevisitableObjs(const std::unique_ptr<AIMemory> & memory, const PlayerColor & playerID, const std::shared_ptr<CCallback> & cc)
{ {
if(cbc->getDate(Date::DAY_OF_WEEK) == 1) if(cc->getDate(Date::DAY_OF_WEEK) == 1)
{ {
for(const CGObjectInstance * obj : memory->visitableObjs) for(const CGObjectInstance * obj : memory->visitableObjs)
{ {
@@ -1734,9 +1735,9 @@ void AIGateway::memorizeRevisitableObjs(const std::unique_ptr<AIMemory> & memory
} }
} }
void AIGateway::pickBestArtifacts(const std::shared_ptr<CCallback> & cbc, const CGHeroInstance * h, const CGHeroInstance * other) void AIGateway::pickBestArtifacts(const std::shared_ptr<CCallback> & cc, const CGHeroInstance * h, const CGHeroInstance * other)
{ {
auto equipBest = [cbc](const CGHeroInstance * h, const CGHeroInstance * otherh, bool giveStuffToFirstHero) -> void auto equipBest = [cc](const CGHeroInstance * h, const CGHeroInstance * otherh, bool giveStuffToFirstHero) -> void
{ {
bool changeMade = false; bool changeMade = false;
std::set<std::pair<ArtifactInstanceID, ArtifactInstanceID> > swappedSet; std::set<std::pair<ArtifactInstanceID, ArtifactInstanceID> > swappedSet;
@@ -1783,7 +1784,7 @@ void AIGateway::pickBestArtifacts(const std::shared_ptr<CCallback> & cbc, const
if(location.slot == ArtifactPosition::MACH4) // don't attempt to move catapult if(location.slot == ArtifactPosition::MACH4) // don't attempt to move catapult
continue; continue;
auto artHolder = cbc->getHero(location.artHolder); auto artHolder = cc->getHero(location.artHolder);
auto s = artHolder->getSlot(location.slot); auto s = artHolder->getSlot(location.slot);
if(!s || s->locked) //we can't move locks if(!s || s->locked) //we can't move locks
continue; continue;
@@ -1798,7 +1799,7 @@ void AIGateway::pickBestArtifacts(const std::shared_ptr<CCallback> & cbc, const
if(target->isPositionFree(slot) && artifact->canBePutAt(target, slot, true)) //combined artifacts are not always allowed to move if(target->isPositionFree(slot) && artifact->canBePutAt(target, slot, true)) //combined artifacts are not always allowed to move
{ {
ArtifactLocation destLocation(target->id, slot); ArtifactLocation destLocation(target->id, slot);
cbc->swapArtifacts(location, destLocation); //just put into empty slot cc->swapArtifacts(location, destLocation); //just put into empty slot
emptySlotFound = true; emptySlotFound = true;
changeMade = true; changeMade = true;
break; break;
@@ -1839,12 +1840,12 @@ void AIGateway::pickBestArtifacts(const std::shared_ptr<CCallback> & cbc, const
ArtifactLocation destLocation(target->id, slot); ArtifactLocation destLocation(target->id, slot);
ArtifactLocation backpack(artHolder->id, ArtifactPosition::BACKPACK_START); ArtifactLocation backpack(artHolder->id, ArtifactPosition::BACKPACK_START);
cbc->swapArtifacts(destLocation, backpack); cc->swapArtifacts(destLocation, backpack);
cbc->swapArtifacts(location, destLocation); cc->swapArtifacts(location, destLocation);
} }
else else
{ {
cbc->swapArtifacts(location, ArtifactLocation(target->id, target->getArtPos(otherSlot->getArt()))); cc->swapArtifacts(location, ArtifactLocation(target->id, target->getArtPos(otherSlot->getArt())));
} }
changeMade = true; changeMade = true;

View File

@@ -74,7 +74,8 @@ public:
AIStatus status; AIStatus status;
std::string battlename; std::string battlename;
std::shared_ptr<CCallback> cbc; /// Same instance as in cbc. cbc is used to keep CAdventureAI simpler without unnecessary class requirements
std::shared_ptr<CCallback> cc;
std::unique_ptr<AsyncRunner> asyncTasks; std::unique_ptr<AsyncRunner> asyncTasks;
ObjectInstanceID selectedObject; ObjectInstanceID selectedObject;
@@ -90,7 +91,7 @@ public:
std::string getBattleAIName() const override; std::string getBattleAIName() const override;
void initGameInterface(std::shared_ptr<Environment> env, std::shared_ptr<CCallback> CB) override; void initGameInterface(std::shared_ptr<Environment> env, std::shared_ptr<CCallback> callback) override;
void yourTurn(QueryID queryID) override; void yourTurn(QueryID queryID) override;
void heroGotLevel(const CGHeroInstance * hero, PrimarySkill pskill, std::vector<SecondarySkill> & skills, QueryID queryID) override; //pskill is gained primary skill, interface has to choose one of given skills and call callback with selection id void heroGotLevel(const CGHeroInstance * hero, PrimarySkill pskill, std::vector<SecondarySkill> & skills, QueryID queryID) override; //pskill is gained primary skill, interface has to choose one of given skills and call callback with selection id
@@ -183,12 +184,12 @@ public:
static void cheatMapReveal(const std::unique_ptr<Nullkiller>& nullkiller); static void cheatMapReveal(const std::unique_ptr<Nullkiller>& nullkiller);
static void memorizeVisitableObj(const CGObjectInstance* obj, const std::unique_ptr<AIMemory>& memory, const std::unique_ptr<DangerHitMapAnalyzer>& static void memorizeVisitableObj(const CGObjectInstance* obj, const std::unique_ptr<AIMemory>& memory, const std::unique_ptr<DangerHitMapAnalyzer>&
dangerHitMap, const PlayerColor& playerID, const std::shared_ptr<CCallback>& cbc); dangerHitMap, const PlayerColor& playerID, const std::shared_ptr<CCallback>& cc);
static void memorizeVisitableObjs(const std::unique_ptr<AIMemory>& memory, const std::unique_ptr<DangerHitMapAnalyzer>& dangerHitMap, const PlayerColor& static void memorizeVisitableObjs(const std::unique_ptr<AIMemory>& memory, const std::unique_ptr<DangerHitMapAnalyzer>& dangerHitMap, const PlayerColor&
playerID, const std::shared_ptr<CCallback>& cbc); playerID, const std::shared_ptr<CCallback>& cc);
static void memorizeRevisitableObjs(const std::unique_ptr<AIMemory>& memory, const PlayerColor& playerID, const std::shared_ptr<CCallback>& cbc); static void memorizeRevisitableObjs(const std::unique_ptr<AIMemory>& memory, const PlayerColor& playerID, const std::shared_ptr<CCallback>& cc);
static void pickBestArtifacts(const std::shared_ptr<CCallback> & cbc, const CGHeroInstance * h, const CGHeroInstance * other = nullptr); static void pickBestArtifacts(const std::shared_ptr<CCallback> & cc, const CGHeroInstance * h, const CGHeroInstance * other = nullptr);
}; };
} }

View File

@@ -30,17 +30,17 @@ namespace NK2AI
const CGObjectInstance * ObjectIdRef::operator->() const const CGObjectInstance * ObjectIdRef::operator->() const
{ {
return cbcTl->getObj(id, false); return ccTl->getObj(id, false);
} }
ObjectIdRef::operator const CGObjectInstance *() const ObjectIdRef::operator const CGObjectInstance *() const
{ {
return cbcTl->getObj(id, false); return ccTl->getObj(id, false);
} }
ObjectIdRef::operator bool() const ObjectIdRef::operator bool() const
{ {
return cbcTl->getObj(id, false); return ccTl->getObj(id, false);
} }
ObjectIdRef::ObjectIdRef(ObjectInstanceID _id) ObjectIdRef::ObjectIdRef(ObjectInstanceID _id)
@@ -101,7 +101,7 @@ std::string HeroPtr::name() const
const CGHeroInstance * HeroPtr::get(bool doWeExpectNull) const const CGHeroInstance * HeroPtr::get(bool doWeExpectNull) const
{ {
return get(cbcTl, doWeExpectNull); return get(ccTl, doWeExpectNull);
} }
const CGHeroInstance * HeroPtr::get(const CPlayerSpecificInfoCallback * cb, bool doWeExpectNull) const const CGHeroInstance * HeroPtr::get(const CPlayerSpecificInfoCallback * cb, bool doWeExpectNull) const
@@ -203,7 +203,7 @@ bool canBeEmbarkmentPoint(const TerrainTile * t, bool fromWater)
} }
else if(!fromWater) // do not try to board when in water sector else if(!fromWater) // do not try to board when in water sector
{ {
if(t->visitableObjects.size() == 1 && cbcTl->getObjInstance(t->topVisitableObj())->ID == Obj::BOAT) if(t->visitableObjects.size() == 1 && ccTl->getObjInstance(t->topVisitableObj())->ID == Obj::BOAT)
return true; return true;
} }
return false; return false;
@@ -211,7 +211,7 @@ bool canBeEmbarkmentPoint(const TerrainTile * t, bool fromWater)
bool isObjectPassable(const Nullkiller * aiNk, const CGObjectInstance * obj) bool isObjectPassable(const Nullkiller * aiNk, const CGObjectInstance * obj)
{ {
return isObjectPassable(obj, aiNk->playerID, aiNk->cbc->getPlayerRelations(obj->tempOwner, aiNk->playerID)); return isObjectPassable(obj, aiNk->playerID, aiNk->cc->getPlayerRelations(obj->tempOwner, aiNk->playerID));
} }
// Pathfinder internal helper // Pathfinder internal helper
@@ -234,7 +234,7 @@ bool isObjectPassable(const CGObjectInstance * obj, PlayerColor playerColor, Pla
bool isBlockVisitObj(const int3 & pos) bool isBlockVisitObj(const int3 & pos)
{ {
if(auto obj = cbcTl->getTopObj(pos)) if(auto obj = ccTl->getTopObj(pos))
{ {
if(obj->isBlockedVisitable()) //we can't stand on that object if(obj->isBlockedVisitable()) //we can't stand on that object
return true; return true;
@@ -646,7 +646,7 @@ int getDuplicatingSlots(const CArmedInstance * army)
// todo: move to obj manager // todo: move to obj manager
bool shouldVisit(const Nullkiller * aiNk, const CGHeroInstance * h, const CGObjectInstance * obj) bool shouldVisit(const Nullkiller * aiNk, const CGHeroInstance * h, const CGObjectInstance * obj)
{ {
auto relations = aiNk->cbc->getPlayerRelations(obj->tempOwner, h->tempOwner); auto relations = aiNk->cc->getPlayerRelations(obj->tempOwner, h->tempOwner);
switch(obj->ID) switch(obj->ID)
{ {
@@ -656,7 +656,7 @@ bool shouldVisit(const Nullkiller * aiNk, const CGHeroInstance * h, const CGObje
case Obj::BORDER_GATE: case Obj::BORDER_GATE:
{ {
for(auto q : aiNk->cbc->getMyQuests()) for(auto q : aiNk->cc->getMyQuests())
{ {
if(q.obj == obj->id) if(q.obj == obj->id)
{ {
@@ -669,11 +669,11 @@ bool shouldVisit(const Nullkiller * aiNk, const CGHeroInstance * h, const CGObje
return (dynamic_cast<const CGKeys *>(obj))->wasMyColorVisited(aiNk->playerID); return (dynamic_cast<const CGKeys *>(obj))->wasMyColorVisited(aiNk->playerID);
case Obj::SEER_HUT: case Obj::SEER_HUT:
{ {
for(auto q : aiNk->cbc->getMyQuests()) for(auto q : aiNk->cc->getMyQuests())
{ {
if(q.obj == obj->id) if(q.obj == obj->id)
{ {
if(q.getQuest(aiNk->cbc.get())->checkQuest(h)) if(q.getQuest(aiNk->cc.get())->checkQuest(h))
return true; //we completed the quest return true; //we completed the quest
else else
return false; //we can't complete this quest return false; //we can't complete this quest
@@ -698,7 +698,7 @@ bool shouldVisit(const Nullkiller * aiNk, const CGHeroInstance * h, const CGObje
{ {
if(level.first if(level.first
&& (h->getSlotFor(CreatureID(c)) != SlotID() || duplicatingSlotsCount > 0) && (h->getSlotFor(CreatureID(c)) != SlotID() || duplicatingSlotsCount > 0)
&& aiNk->cbc->getResourceAmount().canAfford(c.toCreature()->getFullRecruitCost())) && aiNk->cc->getResourceAmount().canAfford(c.toCreature()->getFullRecruitCost()))
{ {
return true; return true;
} }

View File

@@ -62,7 +62,7 @@ const int WOOD_ORE_MINE_PRODUCTION = 2;
const int RESOURCE_MINE_PRODUCTION = 1; const int RESOURCE_MINE_PRODUCTION = 1;
const int ACTUAL_RESOURCE_COUNT = 7; const int ACTUAL_RESOURCE_COUNT = 7;
extern thread_local CCallback * cbcTl; extern thread_local CCallback * ccTl;
enum HeroRole enum HeroRole
{ {
@@ -148,7 +148,7 @@ void foreach_tile_pos(const Func & foo)
{ {
// some micro-optimizations since this function gets called a LOT // some micro-optimizations since this function gets called a LOT
// callback pointer is thread-specific and slow to retrieve -> read map size only once // callback pointer is thread-specific and slow to retrieve -> read map size only once
int3 mapSize = cbcTl->getMapSize(); int3 mapSize = ccTl->getMapSize();
for(int z = 0; z < mapSize.z; z++) for(int z = 0; z < mapSize.z; z++)
{ {
for(int x = 0; x < mapSize.x; x++) for(int x = 0; x < mapSize.x; x++)
@@ -180,7 +180,7 @@ void foreach_tile_pos(TCallback * cbp, const Func & foo) // avoid costly retriev
template<class Func> template<class Func>
void foreach_neighbour(const int3 & pos, const Func & foo) void foreach_neighbour(const int3 & pos, const Func & foo)
{ {
CCallback * cbp = cbcTl; // avoid costly retrieval of thread-specific pointer CCallback * cbp = ccTl; // avoid costly retrieval of thread-specific pointer
for(const int3 & dir : int3::getDirs()) for(const int3 & dir : int3::getDirs())
{ {
const int3 n = pos + dir; const int3 n = pos + dir;

View File

@@ -77,7 +77,7 @@ std::vector<SlotInfo> ArmyManager::toSlotInfo(std::vector<creInfo> army) const
uint64_t ArmyManager::howManyReinforcementsCanGet(const CGHeroInstance * hero, const CCreatureSet * source) const uint64_t ArmyManager::howManyReinforcementsCanGet(const CGHeroInstance * hero, const CCreatureSet * source) const
{ {
return howManyReinforcementsCanGet(hero, hero, source, aiNk->cbc->getTile(hero->visitablePos())->getTerrainID()); return howManyReinforcementsCanGet(hero, hero, source, aiNk->cc->getTile(hero->visitablePos())->getTerrainID());
} }
std::vector<SlotInfo> ArmyManager::getSortedSlots(const CCreatureSet * target, const CCreatureSet * source) const std::vector<SlotInfo> ArmyManager::getSortedSlots(const CCreatureSet * target, const CCreatureSet * source) const

View File

@@ -42,12 +42,12 @@ void BuildAnalyzer::update()
{ {
logAi->trace("Start BuildAnalyzer::update"); logAi->trace("Start BuildAnalyzer::update");
reset(); reset();
const auto towns = aiNk->cbc->getTownsInfo(); const auto towns = aiNk->cc->getTownsInfo();
float economyDevelopmentCost = 0; float economyDevelopmentCost = 0;
for(const CGTownInstance * town : towns) for(const CGTownInstance * town : towns)
{ {
if(town->built >= cbcTl->getSettings().getInteger(EGameSettings::TOWNS_BUILDINGS_PER_TURN_CAP)) if(town->built >= ccTl->getSettings().getInteger(EGameSettings::TOWNS_BUILDINGS_PER_TURN_CAP))
continue; // Not much point in trying anything - can't built in this town anymore today continue; // Not much point in trying anything - can't built in this town anymore today
#if NKAI_TRACE_LEVEL >= 1 #if NKAI_TRACE_LEVEL >= 1
@@ -57,8 +57,8 @@ void BuildAnalyzer::update()
developmentInfos.push_back(TownDevelopmentInfo(town)); developmentInfos.push_back(TownDevelopmentInfo(town));
TownDevelopmentInfo & tdi = developmentInfos.back(); TownDevelopmentInfo & tdi = developmentInfos.back();
updateCreatureBuildings(tdi, aiNk->armyManager, aiNk->cbc); updateCreatureBuildings(tdi, aiNk->armyManager, aiNk->cc);
updateOtherBuildings(tdi, aiNk->armyManager, aiNk->cbc); updateOtherBuildings(tdi, aiNk->armyManager, aiNk->cc);
requiredResources += tdi.requiredResources; requiredResources += tdi.requiredResources;
totalDevelopmentCost += tdi.townDevelopmentCost; totalDevelopmentCost += tdi.townDevelopmentCost;
@@ -83,7 +83,7 @@ void BuildAnalyzer::update()
return val1 > val2; return val1 > val2;
}); });
dailyIncome = calculateDailyIncome(aiNk->cbc->getMyObjects(), aiNk->cbc->getTownsInfo()); dailyIncome = calculateDailyIncome(aiNk->cc->getMyObjects(), aiNk->cc->getTownsInfo());
goldPressure = calculateGoldPressure(aiNk->getLockedResources()[EGameResID::GOLD], goldPressure = calculateGoldPressure(aiNk->getLockedResources()[EGameResID::GOLD],
static_cast<float>(armyCost[EGameResID::GOLD]), static_cast<float>(armyCost[EGameResID::GOLD]),
economyDevelopmentCost, economyDevelopmentCost,

View File

@@ -70,8 +70,8 @@ void DangerHitMapAnalyzer::updateHitMap()
hitMapUpToDate = true; hitMapUpToDate = true;
auto start = std::chrono::high_resolution_clock::now(); auto start = std::chrono::high_resolution_clock::now();
auto cb = aiNk->cbc.get(); auto cb = aiNk->cc.get();
auto mapSize = aiNk->cbc->getMapSize(); auto mapSize = aiNk->cc->getMapSize();
if(hitMap.shape()[0] != mapSize.x || hitMap.shape()[1] != mapSize.y || hitMap.shape()[2] != mapSize.z) if(hitMap.shape()[0] != mapSize.x || hitMap.shape()[1] != mapSize.y || hitMap.shape()[2] != mapSize.z)
hitMap.resize(boost::extents[mapSize.x][mapSize.y][mapSize.z]); hitMap.resize(boost::extents[mapSize.x][mapSize.y][mapSize.z]);
@@ -114,7 +114,7 @@ void DangerHitMapAnalyzer::updateHitMap()
if(!pair.first.isValidPlayer()) if(!pair.first.isValidPlayer())
continue; continue;
if(aiNk->cbc->getPlayerRelations(aiNk->playerID, pair.first) != PlayerRelations::ENEMIES) if(aiNk->cc->getPlayerRelations(aiNk->playerID, pair.first) != PlayerRelations::ENEMIES)
continue; continue;
PathfinderSettings ps; PathfinderSettings ps;
@@ -203,8 +203,8 @@ void DangerHitMapAnalyzer::calculateTileOwners()
tileOwnersUpToDate = true; tileOwnersUpToDate = true;
auto cb = aiNk->cbc.get(); auto cb = aiNk->cc.get();
auto mapSize = aiNk->cbc->getMapSize(); auto mapSize = aiNk->cc->getMapSize();
if(hitMap.shape()[0] != mapSize.x || hitMap.shape()[1] != mapSize.y || hitMap.shape()[2] != mapSize.z) if(hitMap.shape()[0] != mapSize.x || hitMap.shape()[1] != mapSize.y || hitMap.shape()[2] != mapSize.z)
hitMap.resize(boost::extents[mapSize.x][mapSize.y][mapSize.z]); hitMap.resize(boost::extents[mapSize.x][mapSize.y][mapSize.z]);

View File

@@ -290,7 +290,7 @@ const CGHeroInstance * HeroManager::findHeroWithGrail() const
const CGHeroInstance * HeroManager::findWeakHeroToDismiss(uint64_t armyLimit, const CGTownInstance* townToSpare) const const CGHeroInstance * HeroManager::findWeakHeroToDismiss(uint64_t armyLimit, const CGTownInstance* townToSpare) const
{ {
const CGHeroInstance * weakestHero = nullptr; const CGHeroInstance * weakestHero = nullptr;
auto myHeroes = aiNk->cbc->getHeroesInfo(); auto myHeroes = aiNk->cc->getHeroesInfo();
for(auto existingHero : myHeroes) for(auto existingHero : myHeroes)
{ {

View File

@@ -69,12 +69,12 @@ std::vector<const CGObjectInstance *> ObjectCluster::getObjects(const CPlayerSpe
std::vector<const CGObjectInstance *> ObjectClusterizer::getNearbyObjects() const std::vector<const CGObjectInstance *> ObjectClusterizer::getNearbyObjects() const
{ {
return nearObjects.getObjects(aiNk->cbc.get()); return nearObjects.getObjects(aiNk->cc.get());
} }
std::vector<const CGObjectInstance *> ObjectClusterizer::getFarObjects() const std::vector<const CGObjectInstance *> ObjectClusterizer::getFarObjects() const
{ {
return farObjects.getObjects(aiNk->cbc.get()); return farObjects.getObjects(aiNk->cc.get());
} }
std::vector<std::shared_ptr<ObjectCluster>> ObjectClusterizer::getLockedClusters() const std::vector<std::shared_ptr<ObjectCluster>> ObjectClusterizer::getLockedClusters() const
@@ -95,14 +95,14 @@ std::optional<const CGObjectInstance *> ObjectClusterizer::getBlocker(const AIPa
if(node.layer == EPathfindingLayer::LAND || node.layer == EPathfindingLayer::SAIL) if(node.layer == EPathfindingLayer::LAND || node.layer == EPathfindingLayer::SAIL)
{ {
auto guardPos = aiNk->cbc->getGuardingCreaturePosition(node.coord); auto guardPos = aiNk->cc->getGuardingCreaturePosition(node.coord);
if (aiNk->cbc->isVisible(node.coord)) if (aiNk->cc->isVisible(node.coord))
blockers = aiNk->cbc->getVisitableObjs(node.coord); blockers = aiNk->cc->getVisitableObjs(node.coord);
if(guardPos.isValid() && aiNk->cbc->isVisible(guardPos)) if(guardPos.isValid() && aiNk->cc->isVisible(guardPos))
{ {
auto guard = aiNk->cbc->getTopObj(aiNk->cbc->getGuardingCreaturePosition(node.coord)); auto guard = aiNk->cc->getTopObj(aiNk->cc->getGuardingCreaturePosition(node.coord));
if(guard) if(guard)
{ {
@@ -190,7 +190,7 @@ void ObjectClusterizer::validateObjects()
{ {
for(auto & pair : cluster.objects) for(auto & pair : cluster.objects)
{ {
if(!aiNk->cbc->getObj(pair.first, false)) if(!aiNk->cc->getObj(pair.first, false))
toRemove.push_back(pair.first); toRemove.push_back(pair.first);
} }
}; };
@@ -200,7 +200,7 @@ void ObjectClusterizer::validateObjects()
for(auto & pair : blockedObjects) for(auto & pair : blockedObjects)
{ {
if(!aiNk->cbc->getObj(pair.first, false) || pair.second->objects.empty()) if(!aiNk->cc->getObj(pair.first, false) || pair.second->objects.empty())
toRemove.push_back(pair.first); toRemove.push_back(pair.first);
else else
scanRemovedObjects(*pair.second); scanRemovedObjects(*pair.second);
@@ -248,7 +248,7 @@ bool ObjectClusterizer::shouldVisitObject(const CGObjectInstance * obj) const
return false; return false;
} }
auto playerRelations = aiNk->cbc->getPlayerRelations(aiNk->playerID, obj->tempOwner); auto playerRelations = aiNk->cc->getPlayerRelations(aiNk->playerID, obj->tempOwner);
if(playerRelations != PlayerRelations::ENEMIES && !isWeeklyRevisitable(aiNk->playerID, obj)) if(playerRelations != PlayerRelations::ENEMIES && !isWeeklyRevisitable(aiNk->playerID, obj))
{ {
@@ -258,12 +258,12 @@ bool ObjectClusterizer::shouldVisitObject(const CGObjectInstance * obj) const
//it may be hero visiting this obj //it may be hero visiting this obj
//we don't try visiting object on which allied or owned hero stands //we don't try visiting object on which allied or owned hero stands
// -> it will just trigger exchange windows and AI will be confused that obj behind doesn't get visited // -> it will just trigger exchange windows and AI will be confused that obj behind doesn't get visited
const CGObjectInstance * topObj = aiNk->cbc->getTopObj(pos); const CGObjectInstance * topObj = aiNk->cc->getTopObj(pos);
if(!topObj) if(!topObj)
return false; // partly visible obj but its visitable pos is not visible. return false; // partly visible obj but its visitable pos is not visible.
if(topObj->ID == Obj::HERO && aiNk->cbc->getPlayerRelations(aiNk->playerID, topObj->tempOwner) != PlayerRelations::ENEMIES) if(topObj->ID == Obj::HERO && aiNk->cc->getPlayerRelations(aiNk->playerID, topObj->tempOwner) != PlayerRelations::ENEMIES)
return false; return false;
else else
return true; //all of the following is met return true; //all of the following is met
@@ -310,7 +310,7 @@ void ObjectClusterizer::clusterize()
{ {
for(auto id : invalidated) for(auto id : invalidated)
{ {
auto obj = cbcTl->getObj(id, false); auto obj = ccTl->getObj(id, false);
if(obj) if(obj)
{ {
@@ -338,7 +338,7 @@ void ObjectClusterizer::clusterize()
tbb::blocked_range<size_t> r(0, objs.size()); tbb::blocked_range<size_t> r(0, objs.size());
#endif #endif
auto priorityEvaluator = aiNk->priorityEvaluators->acquire(); auto priorityEvaluator = aiNk->priorityEvaluators->acquire();
auto heroes = aiNk->cbc->getHeroesInfo(); auto heroes = aiNk->cc->getHeroesInfo();
std::vector<AIPath> pathCache; std::vector<AIPath> pathCache;
for(int i = r.begin(); i != r.end(); i++) for(int i = r.begin(); i != r.end(); i++)
@@ -354,12 +354,12 @@ void ObjectClusterizer::clusterize()
for(auto pair : blockedObjects) for(auto pair : blockedObjects)
{ {
auto blocker = cbcTl->getObj(pair.first); auto blocker = ccTl->getObj(pair.first);
logAi->trace("Cluster %s %s count: %i", blocker->getObjectName(), blocker->visitablePos().toString(), pair.second->objects.size()); logAi->trace("Cluster %s %s count: %i", blocker->getObjectName(), blocker->visitablePos().toString(), pair.second->objects.size());
#if NKAI_TRACE_LEVEL >= 1 #if NKAI_TRACE_LEVEL >= 1
for(auto obj : pair.second->getObjects(aiNk->cbc.get())) for(auto obj : pair.second->getObjects(aiNk->cc.get()))
{ {
logAi->trace("Object %s %s", obj->getObjectName(), obj->visitablePos().toString()); logAi->trace("Object %s %s", obj->getObjectName(), obj->visitablePos().toString());
} }

View File

@@ -28,7 +28,7 @@ Goals::TGoalVec BuyArmyBehavior::decompose(const Nullkiller * aiNk) const
{ {
Goals::TGoalVec tasks; Goals::TGoalVec tasks;
auto heroes = cbcTl->getHeroesInfo(); auto heroes = ccTl->getHeroesInfo();
if(heroes.empty()) if(heroes.empty())
{ {
@@ -37,11 +37,11 @@ Goals::TGoalVec BuyArmyBehavior::decompose(const Nullkiller * aiNk) const
aiNk->dangerHitMap->updateHitMap(); aiNk->dangerHitMap->updateHitMap();
for(auto town : cbcTl->getTownsInfo()) for(auto town : ccTl->getTownsInfo())
{ {
uint8_t closestThreat = aiNk->dangerHitMap->getTileThreat(town->visitablePos()).fastestDanger.turn; uint8_t closestThreat = aiNk->dangerHitMap->getTileThreat(town->visitablePos()).fastestDanger.turn;
if (closestThreat >=2 && aiNk->buildAnalyzer->isGoldPressureOverMax() && !town->hasBuilt(BuildingID::CITY_HALL) && cbcTl->canBuildStructure(town, BuildingID::CITY_HALL) != EBuildingState::FORBIDDEN) if (closestThreat >=2 && aiNk->buildAnalyzer->isGoldPressureOverMax() && !town->hasBuilt(BuildingID::CITY_HALL) && ccTl->canBuildStructure(town, BuildingID::CITY_HALL) != EBuildingState::FORBIDDEN)
{ {
return tasks; return tasks;
} }

View File

@@ -41,7 +41,7 @@ Goals::TGoalVec ClusterBehavior::decompose(const Nullkiller * aiNk) const
Goals::TGoalVec ClusterBehavior::decomposeCluster(const Nullkiller * aiNk, std::shared_ptr<ObjectCluster> cluster) const Goals::TGoalVec ClusterBehavior::decomposeCluster(const Nullkiller * aiNk, std::shared_ptr<ObjectCluster> cluster) const
{ {
auto center = cluster->calculateCenter(aiNk->cbc.get()); auto center = cluster->calculateCenter(aiNk->cc.get());
auto paths = aiNk->pathfinder->getPathInfo(center->visitablePos(), aiNk->isObjectGraphAllowed()); auto paths = aiNk->pathfinder->getPathInfo(center->visitablePos(), aiNk->isObjectGraphAllowed());
auto blockerPos = cluster->blocker->visitablePos(); auto blockerPos = cluster->blocker->visitablePos();
@@ -83,7 +83,7 @@ Goals::TGoalVec ClusterBehavior::decomposeCluster(const Nullkiller * aiNk, std::
{ {
clonedPath.nodes.insert(clonedPath.nodes.begin(), *node); clonedPath.nodes.insert(clonedPath.nodes.begin(), *node);
if(node->coord == blockerPos || aiNk->cbc->getGuardingCreaturePosition(node->coord) == blockerPos) if(node->coord == blockerPos || aiNk->cc->getGuardingCreaturePosition(node->coord) == blockerPos)
break; break;
} }

View File

@@ -38,7 +38,7 @@ Goals::TGoalVec DefenceBehavior::decompose(const Nullkiller * aiNk) const
{ {
Goals::TGoalVec tasks; Goals::TGoalVec tasks;
for(auto town : aiNk->cbc->getTownsInfo()) for(auto town : aiNk->cc->getTownsInfo())
{ {
evaluateDefence(tasks, town, aiNk); evaluateDefence(tasks, town, aiNk);
} }
@@ -48,7 +48,7 @@ Goals::TGoalVec DefenceBehavior::decompose(const Nullkiller * aiNk) const
bool isThreatUnderControl(const CGTownInstance * town, const HitMapInfo & threat, const Nullkiller * aiNk, const std::vector<AIPath> & paths) bool isThreatUnderControl(const CGTownInstance * town, const HitMapInfo & threat, const Nullkiller * aiNk, const std::vector<AIPath> & paths)
{ {
int dayOfWeek = aiNk->cbc->getDate(Date::DAY_OF_WEEK); int dayOfWeek = aiNk->cc->getDate(Date::DAY_OF_WEEK);
for(const AIPath & path : paths) for(const AIPath & path : paths)
{ {
@@ -121,7 +121,7 @@ bool handleGarrisonHeroFromPreviousTurn(const CGTownInstance * town, Goals::TGoa
if(!town->getVisitingHero()) if(!town->getVisitingHero())
{ {
if(aiNk->cbc->getHeroCount(aiNk->playerID, false) < GameConstants::MAX_HEROES_PER_PLAYER) if(aiNk->cc->getHeroCount(aiNk->playerID, false) < GameConstants::MAX_HEROES_PER_PLAYER)
{ {
logAi->trace( logAi->trace(
"Extracting hero %s from garrison of town %s", "Extracting hero %s from garrison of town %s",
@@ -429,9 +429,9 @@ void DefenceBehavior::evaluateRecruitingHero(Goals::TGoalVec & tasks, const HitM
return; return;
if(town->hasBuilt(BuildingID::TAVERN) if(town->hasBuilt(BuildingID::TAVERN)
&& aiNk->cbc->getResourceAmount(EGameResID::GOLD) > GameConstants::HERO_GOLD_COST) && aiNk->cc->getResourceAmount(EGameResID::GOLD) > GameConstants::HERO_GOLD_COST)
{ {
auto heroesInTavern = aiNk->cbc->getAvailableHeroes(town); auto heroesInTavern = aiNk->cc->getAvailableHeroes(town);
for(auto hero : heroesInTavern) for(auto hero : heroesInTavern)
{ {
@@ -453,7 +453,7 @@ void DefenceBehavior::evaluateRecruitingHero(Goals::TGoalVec & tasks, const HitM
if (heroAlreadyHiredInOtherTown) if (heroAlreadyHiredInOtherTown)
continue; continue;
auto myHeroes = aiNk->cbc->getHeroesInfo(); auto myHeroes = aiNk->cc->getHeroesInfo();
#if NKAI_TRACE_LEVEL >= 1 #if NKAI_TRACE_LEVEL >= 1
logAi->trace("Hero %s can be recruited to defend %s", hero->getObjectName(), town->getObjectName()); logAi->trace("Hero %s can be recruited to defend %s", hero->getObjectName(), town->getObjectName());

View File

@@ -51,11 +51,11 @@ Goals::TGoalVec ExplorationBehavior::decompose(const Nullkiller * aiNk) const
case Obj::WHIRLPOOL: case Obj::WHIRLPOOL:
{ {
auto tObj = dynamic_cast<const CGTeleport*>(obj); auto tObj = dynamic_cast<const CGTeleport*>(obj);
for (auto exit : cbcTl->getTeleportChannelExits(tObj->channel)) for (auto exit : ccTl->getTeleportChannelExits(tObj->channel))
{ {
if (exit != tObj->id) if (exit != tObj->id)
{ {
if (!cbcTl->isVisible(cbcTl->getObjInstance(exit))) if (!ccTl->isVisible(ccTl->getObjInstance(exit)))
tasks.push_back(sptr(Composition().addNext(ExplorationPoint(obj->visitablePos(), 50)).addNext(CaptureObject(obj)))); tasks.push_back(sptr(Composition().addNext(ExplorationPoint(obj->visitablePos(), 50)).addNext(CaptureObject(obj))));
} }
} }
@@ -63,7 +63,7 @@ Goals::TGoalVec ExplorationBehavior::decompose(const Nullkiller * aiNk) const
} }
} }
auto heroes = aiNk->cbc->getHeroesInfo(); auto heroes = aiNk->cc->getHeroesInfo();
for(const CGHeroInstance * hero : heroes) for(const CGHeroInstance * hero : heroes)
{ {

View File

@@ -34,7 +34,7 @@ Goals::TGoalVec GatherArmyBehavior::decompose(const Nullkiller * aiNk) const
{ {
Goals::TGoalVec tasks; Goals::TGoalVec tasks;
auto heroes = aiNk->cbc->getHeroesInfo(); auto heroes = aiNk->cc->getHeroesInfo();
if(heroes.empty()) if(heroes.empty())
{ {
@@ -49,7 +49,7 @@ Goals::TGoalVec GatherArmyBehavior::decompose(const Nullkiller * aiNk) const
} }
} }
auto towns = aiNk->cbc->getTownsInfo(); auto towns = aiNk->cc->getTownsInfo();
for(const CGTownInstance * town : towns) for(const CGTownInstance * town : towns)
{ {
@@ -314,7 +314,7 @@ Goals::TGoalVec GatherArmyBehavior::upgradeArmy(const Nullkiller * aiNk, const C
&& aiNk->heroManager->canRecruitHero(upgrader) && aiNk->heroManager->canRecruitHero(upgrader)
&& path.turn() < aiNk->settings->getScoutHeroTurnDistanceLimit()) && path.turn() < aiNk->settings->getScoutHeroTurnDistanceLimit())
{ {
for(auto hero : cbcTl->getAvailableHeroes(upgrader)) for(auto hero : ccTl->getAvailableHeroes(upgrader))
{ {
auto scoutReinforcement = aiNk->armyManager->howManyReinforcementsCanGet(hero, upgrader); auto scoutReinforcement = aiNk->armyManager->howManyReinforcementsCanGet(hero, upgrader);

View File

@@ -27,7 +27,7 @@ std::string RecruitHeroBehavior::toString() const
Goals::TGoalVec RecruitHeroBehavior::decompose(const Nullkiller * aiNk) const Goals::TGoalVec RecruitHeroBehavior::decompose(const Nullkiller * aiNk) const
{ {
Goals::TGoalVec tasks; Goals::TGoalVec tasks;
auto towns = aiNk->cbc->getTownsInfo(); auto towns = aiNk->cc->getTownsInfo();
auto ourHeroes = aiNk->heroManager->getHeroRoles(); auto ourHeroes = aiNk->heroManager->getHeroRoles();
auto minScoreToHireMain = std::numeric_limits<float>::max(); auto minScoreToHireMain = std::numeric_limits<float>::max();
@@ -78,7 +78,7 @@ Goals::TGoalVec RecruitHeroBehavior::decompose(const Nullkiller * aiNk) const
} }
if(aiNk->heroManager->canRecruitHero(town)) if(aiNk->heroManager->canRecruitHero(town))
{ {
auto availableHeroes = aiNk->cbc->getAvailableHeroes(town); auto availableHeroes = aiNk->cc->getAvailableHeroes(town);
for (auto obj : aiNk->objectClusterizer->getNearbyObjects()) for (auto obj : aiNk->objectClusterizer->getNearbyObjects())
{ {
@@ -128,8 +128,8 @@ Goals::TGoalVec RecruitHeroBehavior::decompose(const Nullkiller * aiNk) const
} }
if (bestHeroToHire && bestTownToHireFrom) if (bestHeroToHire && bestTownToHireFrom)
{ {
if (aiNk->cbc->getHeroesInfo().size() == 0 if (aiNk->cc->getHeroesInfo().size() == 0
|| treasureSourcesCount > aiNk->cbc->getHeroesInfo().size() * 5 || treasureSourcesCount > aiNk->cc->getHeroesInfo().size() * 5
|| (bestHeroToHire->getArmyCost() > GameConstants::HERO_GOLD_COST / 2.0 && (bestClosestThreat < 1 || !aiNk->buildAnalyzer->isGoldPressureOverMax())) || (bestHeroToHire->getArmyCost() > GameConstants::HERO_GOLD_COST / 2.0 && (bestClosestThreat < 1 || !aiNk->buildAnalyzer->isGoldPressureOverMax()))
|| (aiNk->getFreeResources()[EGameResID::GOLD] > 10000 && !aiNk->buildAnalyzer->isGoldPressureOverMax() && haveCapitol) || (aiNk->getFreeResources()[EGameResID::GOLD] > 10000 && !aiNk->buildAnalyzer->isGoldPressureOverMax() && haveCapitol)
|| (aiNk->getFreeResources()[EGameResID::GOLD] > 30000 && !aiNk->buildAnalyzer->isGoldPressureOverMax())) || (aiNk->getFreeResources()[EGameResID::GOLD] > 30000 && !aiNk->buildAnalyzer->isGoldPressureOverMax()))

View File

@@ -97,21 +97,21 @@ bool needToRecruitHero(const Nullkiller * aiNk, const CGTownInstance * startupTo
} }
} }
auto basicCount = cbcTl->getTownsInfo().size() + 2; auto basicCount = ccTl->getTownsInfo().size() + 2;
auto boost = std::min( auto boost = std::min(
(int)std::floor(std::pow(1 + (cbcTl->getMapSize().x / 50), 2)), (int)std::floor(std::pow(1 + (ccTl->getMapSize().x / 50), 2)),
treasureSourcesCount / 2); treasureSourcesCount / 2);
logAi->trace("Treasure sources found %d", treasureSourcesCount); logAi->trace("Treasure sources found %d", treasureSourcesCount);
logAi->trace("Startup allows %d+%d heroes", basicCount, boost); logAi->trace("Startup allows %d+%d heroes", basicCount, boost);
return cbcTl->getHeroCount(aiNk->playerID, true) < basicCount + boost; return ccTl->getHeroCount(aiNk->playerID, true) < basicCount + boost;
} }
Goals::TGoalVec StartupBehavior::decompose(const Nullkiller * aiNk) const Goals::TGoalVec StartupBehavior::decompose(const Nullkiller * aiNk) const
{ {
Goals::TGoalVec tasks; Goals::TGoalVec tasks;
auto towns = aiNk->cbc->getTownsInfo(); auto towns = aiNk->cc->getTownsInfo();
if(!towns.size()) if(!towns.size())
return tasks; return tasks;
@@ -135,7 +135,7 @@ Goals::TGoalVec StartupBehavior::decompose(const Nullkiller * aiNk) const
} }
if(!startupTown->hasBuilt(BuildingID::TAVERN) if(!startupTown->hasBuilt(BuildingID::TAVERN)
&& aiNk->cbc->canBuildStructure(startupTown, BuildingID::TAVERN) == EBuildingState::ALLOWED) && aiNk->cc->canBuildStructure(startupTown, BuildingID::TAVERN) == EBuildingState::ALLOWED)
{ {
tasks.push_back(Goals::sptr(Goals::BuildThis(BuildingID::TAVERN, startupTown).setpriority(100))); tasks.push_back(Goals::sptr(Goals::BuildThis(BuildingID::TAVERN, startupTown).setpriority(100)));

View File

@@ -30,7 +30,7 @@ std::string StayAtTownBehavior::toString() const
Goals::TGoalVec StayAtTownBehavior::decompose(const Nullkiller * aiNk) const Goals::TGoalVec StayAtTownBehavior::decompose(const Nullkiller * aiNk) const
{ {
Goals::TGoalVec tasks; Goals::TGoalVec tasks;
auto towns = aiNk->cbc->getTownsInfo(); auto towns = aiNk->cc->getTownsInfo();
if(!towns.size()) if(!towns.size())
return tasks; return tasks;

View File

@@ -146,8 +146,8 @@ bool isEquivalentGoals(TSubgoal goal1, TSubgoal goal2)
if(goal1->goalType == Goals::CAPTURE_OBJECT && goal2->goalType == Goals::CAPTURE_OBJECT) if(goal1->goalType == Goals::CAPTURE_OBJECT && goal2->goalType == Goals::CAPTURE_OBJECT)
{ {
auto o1 = cbcTl->getObj(ObjectInstanceID(goal1->objid)); auto o1 = ccTl->getObj(ObjectInstanceID(goal1->objid));
auto o2 = cbcTl->getObj(ObjectInstanceID(goal2->objid)); auto o2 = ccTl->getObj(ObjectInstanceID(goal2->objid));
return o1->ID == Obj::SHIPYARD && o1->ID == o2->ID; return o1->ID == Obj::SHIPYARD && o1->ID == o2->ID;
} }

View File

@@ -21,7 +21,7 @@ namespace NK2AI
ui64 FuzzyHelper::evaluateDanger(const int3 & tile, const CGHeroInstance * visitor, bool checkGuards) ui64 FuzzyHelper::evaluateDanger(const int3 & tile, const CGHeroInstance * visitor, bool checkGuards)
{ {
auto cb = aiNk->cbc.get(); auto cb = aiNk->cc.get();
const TerrainTile * t = cb->getTile(tile, false); const TerrainTile * t = cb->getTile(tile, false);
if(!t) //we can know about guard but can't check its tile (the edge of fow) if(!t) //we can know about guard but can't check its tile (the edge of fow)
return 190000000; //MUCH return 190000000; //MUCH
@@ -109,7 +109,7 @@ ui64 FuzzyHelper::evaluateDanger(const int3 & tile, const CGHeroInstance * visit
ui64 FuzzyHelper::evaluateDanger(const CGObjectInstance * obj) ui64 FuzzyHelper::evaluateDanger(const CGObjectInstance * obj)
{ {
auto cb = aiNk->cbc.get(); auto cb = aiNk->cc.get();
if(obj->tempOwner.isValidPlayer() && cb->getPlayerRelations(obj->tempOwner, aiNk->playerID) != PlayerRelations::ENEMIES) //owned or allied objects don't pose any threat if(obj->tempOwner.isValidPlayer() && cb->getPlayerRelations(obj->tempOwner, aiNk->playerID) != PlayerRelations::ENEMIES) //owned or allied objects don't pose any threat
return 0; return 0;

View File

@@ -68,7 +68,7 @@ bool canUseOpenMap(std::shared_ptr<CCallback> cb, PlayerColor playerID)
void Nullkiller::init(std::shared_ptr<CCallback> cb, AIGateway * aiGw) void Nullkiller::init(std::shared_ptr<CCallback> cb, AIGateway * aiGw)
{ {
this->cbc = cb; this->cc = cb;
this->aiGw = aiGw; this->aiGw = aiGw;
this->playerID = aiGw->playerID; this->playerID = aiGw->playerID;
@@ -264,7 +264,7 @@ void Nullkiller::updateState(bool partialUpdate)
if(!partialUpdate && pathfinderInvalidated) if(!partialUpdate && pathfinderInvalidated)
{ {
memory->removeInvisibleObjects(cbc.get()); memory->removeInvisibleObjects(cc.get());
dangerHitMap->updateHitMap(); dangerHitMap->updateHitMap();
dangerHitMap->calculateTileOwners(); dangerHitMap->calculateTileOwners();
@@ -276,7 +276,7 @@ void Nullkiller::updateState(bool partialUpdate)
std::map<const CGHeroInstance *, HeroRole> activeHeroes; std::map<const CGHeroInstance *, HeroRole> activeHeroes;
for(auto hero : cbc->getHeroesInfo()) for(auto hero : cc->getHeroesInfo())
{ {
if(getHeroLockedReason(hero) == HeroLockedReason::DEFENCE) if(getHeroLockedReason(hero) == HeroLockedReason::DEFENCE)
continue; continue;
@@ -368,7 +368,7 @@ void Nullkiller::makeTurn()
Goals::TGoalVec tasks; Goals::TGoalVec tasks;
tracePlayerStatus(true); tracePlayerStatus(true);
for(int i = 1; i <= settings->getMaxPass() && cbc->getPlayerStatus(playerID) == EPlayerStatus::INGAME; i++) for(int i = 1; i <= settings->getMaxPass() && cc->getPlayerStatus(playerID) == EPlayerStatus::INGAME; i++)
{ {
updateState(); updateState();
@@ -407,7 +407,7 @@ void Nullkiller::makeTurn()
bool hasAnySuccess = false; bool hasAnySuccess = false;
for(const auto& selectedTask : selectedTasks) for(const auto& selectedTask : selectedTasks)
{ {
if(cbc->getPlayerStatus(playerID) != EPlayerStatus::INGAME) if(cc->getPlayerStatus(playerID) != EPlayerStatus::INGAME)
return; return;
if(!areAffectedObjectsPresent(selectedTask)) if(!areAffectedObjectsPresent(selectedTask))
@@ -437,7 +437,7 @@ void Nullkiller::makeTurn()
if((settings->isUseFuzzy() && selectedTask->priority < MIN_PRIORITY) || (!settings->isUseFuzzy() && selectedTask->priority <= 0)) if((settings->isUseFuzzy() && selectedTask->priority < MIN_PRIORITY) || (!settings->isUseFuzzy() && selectedTask->priority <= 0))
{ {
auto heroes = cbc->getHeroesInfo(); auto heroes = cc->getHeroesInfo();
const auto hasMp = vstd::contains_if(heroes, [](const CGHeroInstance * h) -> bool const auto hasMp = vstd::contains_if(heroes, [](const CGHeroInstance * h) -> bool
{ {
return h->movementPointsRemaining() > 100; return h->movementPointsRemaining() > 100;
@@ -481,8 +481,8 @@ void Nullkiller::makeTurn()
return; return;
} }
for (const auto *heroInfo : cbc->getHeroesInfo()) for (const auto *heroInfo : cc->getHeroesInfo())
AIGateway::pickBestArtifacts(cbc, heroInfo); AIGateway::pickBestArtifacts(cc, heroInfo);
if(i == settings->getMaxPass()) if(i == settings->getMaxPass())
{ {
@@ -494,7 +494,7 @@ void Nullkiller::makeTurn()
bool Nullkiller::makeTurnHelperPriorityPass(Goals::TGoalVec & tempResults, int passIndex) bool Nullkiller::makeTurnHelperPriorityPass(Goals::TGoalVec & tempResults, int passIndex)
{ {
Goals::TTask bestPrioPassTask = taskptr(Goals::Invalid()); Goals::TTask bestPrioPassTask = taskptr(Goals::Invalid());
for(int i = 1; i <= settings->getMaxPriorityPass() && cbc->getPlayerStatus(playerID) == EPlayerStatus::INGAME; i++) for(int i = 1; i <= settings->getMaxPriorityPass() && cc->getPlayerStatus(playerID) == EPlayerStatus::INGAME; i++)
{ {
tempResults.clear(); tempResults.clear();
@@ -534,7 +534,7 @@ bool Nullkiller::areAffectedObjectsPresent(Goals::TTask task) const
for(auto oid : affectedObjs) for(auto oid : affectedObjs)
{ {
if(!cbc->getObj(oid, false)) if(!cc->getObj(oid, false))
return false; return false;
} }
@@ -581,7 +581,7 @@ bool Nullkiller::executeTask(Goals::TTask task)
TResources Nullkiller::getFreeResources() const TResources Nullkiller::getFreeResources() const
{ {
auto freeRes = cbc->getResourceAmount() - lockedResources; auto freeRes = cc->getResourceAmount() - lockedResources;
freeRes.positive(); freeRes.positive();
@@ -598,7 +598,7 @@ bool Nullkiller::handleTrading()
bool haveTraded = false; bool haveTraded = false;
bool shouldTryToTrade = true; bool shouldTryToTrade = true;
ObjectInstanceID marketId; ObjectInstanceID marketId;
for (auto town : cbc->getTownsInfo()) for (auto town : cc->getTownsInfo())
{ {
if (town->hasBuiltSomeTradeBuilding()) if (town->hasBuiltSomeTradeBuilding())
{ {
@@ -607,7 +607,7 @@ bool Nullkiller::handleTrading()
} }
if (!marketId.hasValue()) if (!marketId.hasValue())
return false; return false;
if (const CGObjectInstance* obj = cbc->getObj(marketId, false)) if (const CGObjectInstance* obj = cc->getObj(marketId, false))
{ {
if (const auto* m = dynamic_cast<const IMarket*>(obj)) if (const auto* m = dynamic_cast<const IMarket*>(obj))
{ {
@@ -617,7 +617,7 @@ bool Nullkiller::handleTrading()
buildAnalyzer->update(); buildAnalyzer->update();
TResources required = buildAnalyzer->getTotalResourcesRequired(); TResources required = buildAnalyzer->getTotalResourcesRequired();
TResources income = buildAnalyzer->getDailyIncome(); TResources income = buildAnalyzer->getDailyIncome();
TResources available = cbc->getResourceAmount(); TResources available = cc->getResourceAmount();
#if NKAI_TRACE_LEVEL >= 2 #if NKAI_TRACE_LEVEL >= 2
logAi->debug("Available %s", available.toString()); logAi->debug("Available %s", available.toString());
logAi->debug("Required %s", required.toString()); logAi->debug("Required %s", required.toString());
@@ -678,7 +678,7 @@ bool Nullkiller::handleTrading()
//TODO trade only as much as needed //TODO trade only as much as needed
if (toGive && toGive <= available[mostExpendable]) //don't try to sell 0 resources if (toGive && toGive <= available[mostExpendable]) //don't try to sell 0 resources
{ {
cbc->trade(m->getObjInstanceID(), EMarketMode::RESOURCE_RESOURCE, GameResID(mostExpendable), GameResID(mostWanted), toGive); cc->trade(m->getObjInstanceID(), EMarketMode::RESOURCE_RESOURCE, GameResID(mostExpendable), GameResID(mostWanted), toGive);
#if NKAI_TRACE_LEVEL >= 2 #if NKAI_TRACE_LEVEL >= 2
logAi->info("Traded %d of %s for %d of %s at %s", toGive, mostExpendable, toGet, mostWanted, obj->getObjectName()); logAi->info("Traded %d of %s for %d of %s at %s", toGive, mostExpendable, toGet, mostWanted, obj->getObjectName());
#endif #endif
@@ -706,17 +706,17 @@ void Nullkiller::tracePlayerStatus(bool beginning) const
#if NKAI_TRACE_LEVEL >= 1 #if NKAI_TRACE_LEVEL >= 1
float totalHeroesStrength = 0; float totalHeroesStrength = 0;
int totalTownsLevel = 0; int totalTownsLevel = 0;
for (const auto *heroInfo : cbc->getHeroesInfo()) for (const auto *heroInfo : cc->getHeroesInfo())
{ {
totalHeroesStrength += heroInfo->getTotalStrength(); totalHeroesStrength += heroInfo->getTotalStrength();
} }
for (const auto *townInfo : cbc->getTownsInfo()) for (const auto *townInfo : cc->getTownsInfo())
{ {
totalTownsLevel += townInfo->getTownLevel(); totalTownsLevel += townInfo->getTownLevel();
} }
const auto *firstWord = beginning ? "Beginning:" : "End:"; const auto *firstWord = beginning ? "Beginning:" : "End:";
logAi->info("%s totalHeroesStrength: %f, totalTownsLevel: %d, resources: %s", firstWord, totalHeroesStrength, totalTownsLevel, cbc->getResourceAmount().toString()); logAi->info("%s totalHeroesStrength: %f, totalTownsLevel: %d, resources: %s", firstWord, totalHeroesStrength, totalTownsLevel, cc->getResourceAmount().toString());
#endif #endif
} }

View File

@@ -107,7 +107,7 @@ public:
std::unique_ptr<Settings> settings; std::unique_ptr<Settings> settings;
/// Same value as AIGateway->playerID /// Same value as AIGateway->playerID
PlayerColor playerID; PlayerColor playerID;
std::shared_ptr<CCallback> cbc; std::shared_ptr<CCallback> cc;
std::mutex aiStateMutex; std::mutex aiStateMutex;
mutable ThreadInterruption makingTurnInterrupption; mutable ThreadInterruption makingTurnInterrupption;

View File

@@ -227,7 +227,7 @@ uint64_t RewardEvaluator::getArmyReward(
{ {
const float enemyArmyEliminationRewardRatio = 0.5f; const float enemyArmyEliminationRewardRatio = 0.5f;
auto relations = aiNk->cbc->getPlayerRelations(target->tempOwner, aiNk->playerID); auto relations = aiNk->cc->getPlayerRelations(target->tempOwner, aiNk->playerID);
if(!target) if(!target)
return 0; return 0;
@@ -235,12 +235,12 @@ uint64_t RewardEvaluator::getArmyReward(
switch(target->ID) switch(target->ID)
{ {
case Obj::HILL_FORT: case Obj::HILL_FORT:
return aiNk->armyManager->calculateCreaturesUpgrade(army, target, aiNk->cbc->getResourceAmount()).upgradeValue; return aiNk->armyManager->calculateCreaturesUpgrade(army, target, aiNk->cc->getResourceAmount()).upgradeValue;
case Obj::CREATURE_GENERATOR1: case Obj::CREATURE_GENERATOR1:
case Obj::CREATURE_GENERATOR2: case Obj::CREATURE_GENERATOR2:
case Obj::CREATURE_GENERATOR3: case Obj::CREATURE_GENERATOR3:
case Obj::CREATURE_GENERATOR4: case Obj::CREATURE_GENERATOR4:
return getDwellingArmyValue(aiNk->cbc.get(), target, checkGold); return getDwellingArmyValue(aiNk->cc.get(), target, checkGold);
case Obj::SPELL_SCROLL: case Obj::SPELL_SCROLL:
return evaluateSpellScrollArmyValue(dynamic_cast<const CGArtifact *>(target)->getArtifactInstance()->getScrollSpellID()); return evaluateSpellScrollArmyValue(dynamic_cast<const CGArtifact *>(target)->getArtifactInstance()->getScrollSpellID());
case Obj::ARTIFACT: case Obj::ARTIFACT:
@@ -296,7 +296,7 @@ uint64_t RewardEvaluator::getArmyGrowth(
if(!target) if(!target)
return 0; return 0;
auto relations = aiNk->cbc->getPlayerRelations(target->tempOwner, hero->tempOwner); auto relations = aiNk->cc->getPlayerRelations(target->tempOwner, hero->tempOwner);
if(relations != PlayerRelations::ENEMIES) if(relations != PlayerRelations::ENEMIES)
return 0; return 0;
@@ -308,7 +308,7 @@ uint64_t RewardEvaluator::getArmyGrowth(
auto town = dynamic_cast<const CGTownInstance *>(target); auto town = dynamic_cast<const CGTownInstance *>(target);
auto fortLevel = town->fortLevel(); auto fortLevel = town->fortLevel();
auto neutral = !town->getOwner().isValidPlayer(); auto neutral = !town->getOwner().isValidPlayer();
auto booster = isAnotherAi(town, *aiNk->cbc) || neutral ? 1 : 2; auto booster = isAnotherAi(town, *aiNk->cc) || neutral ? 1 : 2;
if(fortLevel < CGTownInstance::CITADEL) if(fortLevel < CGTownInstance::CITADEL)
return town->hasFort() ? booster * 500 : 0; return town->hasFort() ? booster * 500 : 0;
@@ -320,7 +320,7 @@ uint64_t RewardEvaluator::getArmyGrowth(
case Obj::CREATURE_GENERATOR2: case Obj::CREATURE_GENERATOR2:
case Obj::CREATURE_GENERATOR3: case Obj::CREATURE_GENERATOR3:
case Obj::CREATURE_GENERATOR4: case Obj::CREATURE_GENERATOR4:
return getDwellingArmyGrowth(aiNk->cbc.get(), target, hero->getOwner()); return getDwellingArmyGrowth(aiNk->cc.get(), target, hero->getOwner());
case Obj::ARTIFACT: case Obj::ARTIFACT:
// it is not supported now because hero will not sit in town on 7th day but later parts of legion may be counted as army growth as well. // it is not supported now because hero will not sit in town on 7th day but later parts of legion may be counted as army growth as well.
return 0; return 0;
@@ -343,7 +343,7 @@ int RewardEvaluator::getGoldCost(const CGObjectInstance * target, const CGHeroIn
switch(target->ID) switch(target->ID)
{ {
case Obj::HILL_FORT: case Obj::HILL_FORT:
return aiNk->armyManager->calculateCreaturesUpgrade(army, target, aiNk->cbc->getResourceAmount()).upgradeCost[EGameResID::GOLD]; return aiNk->armyManager->calculateCreaturesUpgrade(army, target, aiNk->cc->getResourceAmount()).upgradeCost[EGameResID::GOLD];
case Obj::SCHOOL_OF_MAGIC: case Obj::SCHOOL_OF_MAGIC:
case Obj::SCHOOL_OF_WAR: case Obj::SCHOOL_OF_WAR:
return 1000; return 1000;
@@ -499,7 +499,7 @@ float RewardEvaluator::getStrategicalValue(const CGObjectInstance * target, cons
} }
auto fortLevel = town->fortLevel(); auto fortLevel = town->fortLevel();
auto booster = isAnotherAi(town, *aiNk->cbc) ? 0.4f : 1.0f; auto booster = isAnotherAi(town, *aiNk->cc) ? 0.4f : 1.0f;
if(town->hasCapitol()) if(town->hasCapitol())
return booster * 1.5; return booster * 1.5;
@@ -511,7 +511,7 @@ float RewardEvaluator::getStrategicalValue(const CGObjectInstance * target, cons
} }
case Obj::HERO: case Obj::HERO:
return aiNk->cbc->getPlayerRelations(target->tempOwner, aiNk->playerID) == PlayerRelations::ENEMIES return aiNk->cc->getPlayerRelations(target->tempOwner, aiNk->playerID) == PlayerRelations::ENEMIES
? getEnemyHeroStrategicalValue(dynamic_cast<const CGHeroInstance *>(target)) ? getEnemyHeroStrategicalValue(dynamic_cast<const CGHeroInstance *>(target))
: 0; : 0;
@@ -575,7 +575,7 @@ float RewardEvaluator::getConquestValue(const CGObjectInstance* target) const
} }
case Obj::HERO: case Obj::HERO:
return aiNk->cbc->getPlayerRelations(target->tempOwner, aiNk->playerID) == PlayerRelations::ENEMIES return aiNk->cc->getPlayerRelations(target->tempOwner, aiNk->playerID) == PlayerRelations::ENEMIES
? getEnemyHeroStrategicalValue(dynamic_cast<const CGHeroInstance*>(target)) ? getEnemyHeroStrategicalValue(dynamic_cast<const CGHeroInstance*>(target))
: 0; : 0;
@@ -595,7 +595,7 @@ float RewardEvaluator::evaluateWitchHutSkillScore(const CGObjectInstance * hut,
return role == HeroRole::SCOUT ? 2 : 0; return role == HeroRole::SCOUT ? 2 : 0;
if(hero->getSecSkillLevel(skill) != MasteryLevel::NONE if(hero->getSecSkillLevel(skill) != MasteryLevel::NONE
|| static_cast<int>(hero->secSkills.size()) >= cbcTl->getSettings().getInteger(EGameSettings::HEROES_SKILL_PER_HERO)) || static_cast<int>(hero->secSkills.size()) >= ccTl->getSettings().getInteger(EGameSettings::HEROES_SKILL_PER_HERO))
return 0; return 0;
auto score = aiNk->heroManager->evaluateSecSkill(skill, hero); auto score = aiNk->heroManager->evaluateSecSkill(skill, hero);
@@ -639,7 +639,7 @@ float RewardEvaluator::getSkillReward(const CGObjectInstance * target, const CGH
//Can contains experience, spells, or skills (only on custom maps) //Can contains experience, spells, or skills (only on custom maps)
return 2.5f; return 2.5f;
case Obj::HERO: case Obj::HERO:
return aiNk->cbc->getPlayerRelations(target->tempOwner, aiNk->playerID) == PlayerRelations::ENEMIES return aiNk->cc->getPlayerRelations(target->tempOwner, aiNk->playerID) == PlayerRelations::ENEMIES
? enemyHeroEliminationSkillRewardRatio * dynamic_cast<const CGHeroInstance *>(target)->level ? enemyHeroEliminationSkillRewardRatio * dynamic_cast<const CGHeroInstance *>(target)->level
: 0; : 0;
@@ -719,7 +719,7 @@ int32_t RewardEvaluator::getGoldReward(const CGObjectInstance * target, const CG
if(!target) if(!target)
return 0; return 0;
auto relations = aiNk->cbc->getPlayerRelations(target->tempOwner, hero->tempOwner); auto relations = aiNk->cc->getPlayerRelations(target->tempOwner, hero->tempOwner);
const int dailyIncomeMultiplier = 5; const int dailyIncomeMultiplier = 5;
const float enemyArmyEliminationGoldRewardRatio = 0.2f; const float enemyArmyEliminationGoldRewardRatio = 0.2f;
@@ -737,7 +737,7 @@ int32_t RewardEvaluator::getGoldReward(const CGObjectInstance * target, const CG
case Obj::WATER_WHEEL: case Obj::WATER_WHEEL:
return 1000; return 1000;
case Obj::TOWN: case Obj::TOWN:
return dailyIncomeMultiplier * estimateTownIncome(aiNk->cbc.get(), target, hero); return dailyIncomeMultiplier * estimateTownIncome(aiNk->cc.get(), target, hero);
case Obj::MINE: case Obj::MINE:
case Obj::ABANDONED_MINE: case Obj::ABANDONED_MINE:
{ {
@@ -824,7 +824,7 @@ public:
int tilesDiscovered = task->value; int tilesDiscovered = task->value;
evaluationContext.addNonCriticalStrategicalValue(0.03f * tilesDiscovered); evaluationContext.addNonCriticalStrategicalValue(0.03f * tilesDiscovered);
for (auto obj : evaluationContext.evaluator.aiNk->cbc->getVisitableObjs(task->tile)) for (auto obj : evaluationContext.evaluator.aiNk->cc->getVisitableObjs(task->tile))
{ {
switch (obj->ID.num) switch (obj->ID.num)
{ {
@@ -839,7 +839,7 @@ public:
break; break;
} }
} }
if(evaluationContext.evaluator.aiNk->cbc->getTile(task->tile)->roadType != RoadId::NO_ROAD) if(evaluationContext.evaluator.aiNk->cc->getTile(task->tile)->roadType != RoadId::NO_ROAD)
evaluationContext.explorePriority = 1; evaluationContext.explorePriority = 1;
if (evaluationContext.explorePriority == 0) if (evaluationContext.explorePriority == 0)
evaluationContext.explorePriority = 3; evaluationContext.explorePriority = 3;
@@ -910,7 +910,7 @@ public:
if(defendTown.getTurn() > 0 && defendTown.isCounterAttack()) if(defendTown.getTurn() > 0 && defendTown.isCounterAttack())
{ {
auto ourSpeed = defendTown.hero->movementPointsLimit(true); auto ourSpeed = defendTown.hero->movementPointsLimit(true);
auto enemySpeed = threat.hero.get(evaluationContext.evaluator.aiNk->cbc.get())->movementPointsLimit(true); auto enemySpeed = threat.hero.get(evaluationContext.evaluator.aiNk->cc.get())->movementPointsLimit(true);
if(enemySpeed > ourSpeed) multiplier *= 0.7f; if(enemySpeed > ourSpeed) multiplier *= 0.7f;
} }
@@ -986,7 +986,7 @@ public:
bool checkGold = evaluationContext.danger == 0; bool checkGold = evaluationContext.danger == 0;
auto army = path.heroArmy; auto army = path.heroArmy;
const CGObjectInstance * target = aiNk->cbc->getObj((ObjectInstanceID)task->objid, false); const CGObjectInstance * target = aiNk->cc->getObj((ObjectInstanceID)task->objid, false);
auto heroRole = evaluationContext.evaluator.aiNk->heroManager->getHeroRole(hero); auto heroRole = evaluationContext.evaluator.aiNk->heroManager->getHeroRole(hero);
if(heroRole == HeroRole::MAIN) if(heroRole == HeroRole::MAIN)
@@ -1038,7 +1038,7 @@ public:
evaluationContext.conquestValue += evaluationContext.evaluator.getConquestValue(target); evaluationContext.conquestValue += evaluationContext.evaluator.getConquestValue(target);
if (target->ID == Obj::HERO) if (target->ID == Obj::HERO)
evaluationContext.isHero = true; evaluationContext.isHero = true;
if (target->getOwner().isValidPlayer() && aiNk->cbc->getPlayerRelations(aiNk->playerID, target->getOwner()) == PlayerRelations::ENEMIES) if (target->getOwner().isValidPlayer() && aiNk->cc->getPlayerRelations(aiNk->playerID, target->getOwner()) == PlayerRelations::ENEMIES)
evaluationContext.isEnemy = true; evaluationContext.isEnemy = true;
if (target->ID == Obj::TOWN) if (target->ID == Obj::TOWN)
evaluationContext.defenseValue = dynamic_cast<const CGTownInstance*>(target)->fortLevel(); evaluationContext.defenseValue = dynamic_cast<const CGTownInstance*>(target)->fortLevel();
@@ -1081,7 +1081,7 @@ public:
for(auto & objInfo : objects) for(auto & objInfo : objects)
{ {
auto target = evaluationContext.evaluator.aiNk->cbc->getObj(objInfo.first); auto target = evaluationContext.evaluator.aiNk->cc->getObj(objInfo.first);
bool checkGold = objInfo.second.danger == 0; bool checkGold = objInfo.second.danger == 0;
auto army = hero; auto army = hero;
@@ -1118,7 +1118,7 @@ public:
logAi->trace("buildEvaluationContext ExchangeSwapTownHeroesContextBuilder %s affected objects: %d", swapCommand.toString(), swapCommand.getAffectedObjects().size()); logAi->trace("buildEvaluationContext ExchangeSwapTownHeroesContextBuilder %s affected objects: %d", swapCommand.toString(), swapCommand.getAffectedObjects().size());
for (auto obj : swapCommand.getAffectedObjects()) for (auto obj : swapCommand.getAffectedObjects())
{ {
logAi->trace("affected object: %s", evaluationContext.evaluator.aiNk->cbc->getObj(obj)->getObjectName()); logAi->trace("affected object: %s", evaluationContext.evaluator.aiNk->cc->getObj(obj)->getObjectName());
} }
if (garrisonHero) if (garrisonHero)
logAi->debug("with %s and %d", garrisonHero->getNameTranslated(), int(swapCommand.getLockingReason())); logAi->debug("with %s and %d", garrisonHero->getNameTranslated(), int(swapCommand.getLockingReason()));
@@ -1184,13 +1184,13 @@ public:
bool alreadyOwn = false; bool alreadyOwn = false;
int highestMageGuildPossible = BuildingID::MAGES_GUILD_3; int highestMageGuildPossible = BuildingID::MAGES_GUILD_3;
for (auto town : evaluationContext.evaluator.aiNk->cbc->getTownsInfo()) for (auto town : evaluationContext.evaluator.aiNk->cc->getTownsInfo())
{ {
if (town->hasBuilt(bi.id)) if (town->hasBuilt(bi.id))
alreadyOwn = true; alreadyOwn = true;
if (evaluationContext.evaluator.aiNk->cbc->canBuildStructure(town, BuildingID::MAGES_GUILD_5) != EBuildingState::FORBIDDEN) if (evaluationContext.evaluator.aiNk->cc->canBuildStructure(town, BuildingID::MAGES_GUILD_5) != EBuildingState::FORBIDDEN)
highestMageGuildPossible = BuildingID::MAGES_GUILD_5; highestMageGuildPossible = BuildingID::MAGES_GUILD_5;
else if (evaluationContext.evaluator.aiNk->cbc->canBuildStructure(town, BuildingID::MAGES_GUILD_4) != EBuildingState::FORBIDDEN) else if (evaluationContext.evaluator.aiNk->cc->canBuildStructure(town, BuildingID::MAGES_GUILD_4) != EBuildingState::FORBIDDEN)
highestMageGuildPossible = BuildingID::MAGES_GUILD_4; highestMageGuildPossible = BuildingID::MAGES_GUILD_4;
} }
@@ -1231,9 +1231,9 @@ public:
else if(bi.id >= BuildingID::MAGES_GUILD_1 && bi.id <= BuildingID::MAGES_GUILD_5) else if(bi.id >= BuildingID::MAGES_GUILD_1 && bi.id <= BuildingID::MAGES_GUILD_5)
{ {
evaluationContext.skillReward += 2 * bi.id.getMagesGuildLevel(); evaluationContext.skillReward += 2 * bi.id.getMagesGuildLevel();
if (!alreadyOwn && evaluationContext.evaluator.aiNk->cbc->canBuildStructure(buildThis.town, highestMageGuildPossible) != EBuildingState::FORBIDDEN) if (!alreadyOwn && evaluationContext.evaluator.aiNk->cc->canBuildStructure(buildThis.town, highestMageGuildPossible) != EBuildingState::FORBIDDEN)
{ {
for (auto hero : evaluationContext.evaluator.aiNk->cbc->getHeroesInfo()) for (auto hero : evaluationContext.evaluator.aiNk->cc->getHeroesInfo())
{ {
if(hero->getPrimSkillLevel(PrimarySkill::SPELL_POWER) + hero->getPrimSkillLevel(PrimarySkill::KNOWLEDGE) > hero->getPrimSkillLevel(PrimarySkill::ATTACK) + hero->getPrimSkillLevel(PrimarySkill::DEFENSE) if(hero->getPrimSkillLevel(PrimarySkill::SPELL_POWER) + hero->getPrimSkillLevel(PrimarySkill::KNOWLEDGE) > hero->getPrimSkillLevel(PrimarySkill::ATTACK) + hero->getPrimSkillLevel(PrimarySkill::DEFENSE)
&& hero->manaLimit() > 30) && hero->manaLimit() > 30)
@@ -1242,7 +1242,7 @@ public:
} }
} }
int sameTownBonus = 0; int sameTownBonus = 0;
for (auto town : evaluationContext.evaluator.aiNk->cbc->getTownsInfo()) for (auto town : evaluationContext.evaluator.aiNk->cc->getTownsInfo())
{ {
if (buildThis.town->getFaction() == town->getFaction()) if (buildThis.town->getFaction() == town->getFaction())
sameTownBonus += town->getTownLevel(); sameTownBonus += town->getTownLevel();
@@ -1382,14 +1382,14 @@ float PriorityEvaluator::evaluate(Goals::TSubgoal task, int priorityTier)
#endif #endif
return 0; return 0;
} }
const bool amIInDanger = aiNk->cbc->getTownsInfo().empty(); const bool amIInDanger = aiNk->cc->getTownsInfo().empty();
// Shouldn't it default to 0 instead of 1.0 in the end? // Shouldn't it default to 0 instead of 1.0 in the end?
const float maxWillingToLose = amIInDanger ? 1 : aiNk->settings->getMaxArmyLossTarget() * evaluationContext.powerRatio > 0 ? aiNk->settings->getMaxArmyLossTarget() * evaluationContext.powerRatio : 1.0; const float maxWillingToLose = amIInDanger ? 1 : aiNk->settings->getMaxArmyLossTarget() * evaluationContext.powerRatio > 0 ? aiNk->settings->getMaxArmyLossTarget() * evaluationContext.powerRatio : 1.0;
float dangerThreshold = 1; float dangerThreshold = 1;
dangerThreshold *= evaluationContext.powerRatio > 0 ? evaluationContext.powerRatio : 1.0; dangerThreshold *= evaluationContext.powerRatio > 0 ? evaluationContext.powerRatio : 1.0;
bool arriveNextWeek = false; bool arriveNextWeek = false;
if (aiNk->cbc->getDate(Date::DAY_OF_WEEK) + evaluationContext.turn > 7 && priorityTier < PriorityTier::FAR_KILL) if (aiNk->cc->getDate(Date::DAY_OF_WEEK) + evaluationContext.turn > 7 && priorityTier < PriorityTier::FAR_KILL)
arriveNextWeek = true; arriveNextWeek = true;
#if NKAI_TRACE_LEVEL >= 2 #if NKAI_TRACE_LEVEL >= 2
@@ -1435,7 +1435,7 @@ float PriorityEvaluator::evaluate(Goals::TSubgoal task, int priorityTier)
return 0; return 0;
if(evaluationContext.conquestValue > 0) if(evaluationContext.conquestValue > 0)
score = evaluationContext.armyInvolvement; score = evaluationContext.armyInvolvement;
if (vstd::isAlmostZero(score) || (evaluationContext.enemyHeroDangerRatio > dangerThreshold && (evaluationContext.turn > 0 || evaluationContext.isExchange) && !aiNk->cbc->getTownsInfo().empty())) if (vstd::isAlmostZero(score) || (evaluationContext.enemyHeroDangerRatio > dangerThreshold && (evaluationContext.turn > 0 || evaluationContext.isExchange) && !aiNk->cc->getTownsInfo().empty()))
return 0; return 0;
if (maxWillingToLose - evaluationContext.armyLossRatio < 0) if (maxWillingToLose - evaluationContext.armyLossRatio < 0)
return 0; return 0;
@@ -1485,7 +1485,7 @@ float PriorityEvaluator::evaluate(Goals::TSubgoal task, int priorityTier)
return 0; return 0;
if (evaluationContext.conquestValue > 0) if (evaluationContext.conquestValue > 0)
score = evaluationContext.armyInvolvement; score = evaluationContext.armyInvolvement;
if (vstd::isAlmostZero(score) || (evaluationContext.enemyHeroDangerRatio > dangerThreshold && (evaluationContext.turn > 0 || evaluationContext.isExchange) && !aiNk->cbc->getTownsInfo().empty())) if (vstd::isAlmostZero(score) || (evaluationContext.enemyHeroDangerRatio > dangerThreshold && (evaluationContext.turn > 0 || evaluationContext.isExchange) && !aiNk->cc->getTownsInfo().empty()))
return 0; return 0;
if (maxWillingToLose - evaluationContext.armyLossRatio < 0) if (maxWillingToLose - evaluationContext.armyLossRatio < 0)
return 0; return 0;
@@ -1607,7 +1607,7 @@ float PriorityEvaluator::evaluate(Goals::TSubgoal task, int priorityTier)
if (!evaluationContext.isTradeBuilding && aiNk->getFreeResources()[EGameResID::WOOD] - evaluationContext.buildingCost[EGameResID::WOOD] < 5 && aiNk->buildAnalyzer->getDailyIncome()[EGameResID::WOOD] < 1) if (!evaluationContext.isTradeBuilding && aiNk->getFreeResources()[EGameResID::WOOD] - evaluationContext.buildingCost[EGameResID::WOOD] < 5 && aiNk->buildAnalyzer->getDailyIncome()[EGameResID::WOOD] < 1)
{ {
logAi->trace("Should make sure to build market-place instead of %s", task->toString()); logAi->trace("Should make sure to build market-place instead of %s", task->toString());
for (auto town : aiNk->cbc->getTownsInfo()) for (auto town : aiNk->cc->getTownsInfo())
{ {
if (!town->hasBuiltSomeTradeBuilding()) if (!town->hasBuiltSomeTradeBuilding())
return 0; return 0;

View File

@@ -47,7 +47,7 @@ std::string AbstractGoal::toString() const
break; break;
case TRADE: case TRADE:
{ {
auto obj = cbcTl->getObjInstance(ObjectInstanceID(objid)); auto obj = ccTl->getObjInstance(ObjectInstanceID(objid));
if (obj) if (obj)
desc = (boost::format("TRADE %d of %s at %s") % value % GameConstants::RESOURCE_NAMES[resID] % obj->getObjectName()).str(); desc = (boost::format("TRADE %d of %s at %s") % value % GameConstants::RESOURCE_NAMES[resID] % obj->getObjectName()).str();
} }

View File

@@ -49,7 +49,7 @@ void AdventureSpellCast::accept(AIGateway * aiGw)
if(town->getVisitingHero() && town->tempOwner == aiGw->playerID && !town->getUpperArmy()->stacksCount()) if(town->getVisitingHero() && town->tempOwner == aiGw->playerID && !town->getUpperArmy()->stacksCount())
{ {
aiGw->cbc->swapGarrisonHero(town); aiGw->cc->swapGarrisonHero(town);
} }
if(town->getVisitingHero()) if(town->getVisitingHero())
@@ -57,12 +57,12 @@ void AdventureSpellCast::accept(AIGateway * aiGw)
} }
if (hero->isGarrisoned()) if (hero->isGarrisoned())
aiGw->cbc->swapGarrisonHero(hero->getVisitedTown()); aiGw->cc->swapGarrisonHero(hero->getVisitedTown());
auto wait = cbcTl->waitTillRealize; auto wait = ccTl->waitTillRealize;
cbcTl->waitTillRealize = true; ccTl->waitTillRealize = true;
cbcTl->castSpell(hero, spellID, tile); ccTl->castSpell(hero, spellID, tile);
if(town && townPortalEffect) if(town && townPortalEffect)
{ {
@@ -70,7 +70,7 @@ void AdventureSpellCast::accept(AIGateway * aiGw)
aiGw->moveHeroToTile(town->visitablePos(), hero); aiGw->moveHeroToTile(town->visitablePos(), hero);
} }
cbcTl->waitTillRealize = wait; ccTl->waitTillRealize = wait;
throw goalFulfilledException(sptr(*this)); throw goalFulfilledException(sptr(*this));
} }

View File

@@ -45,12 +45,12 @@ void BuildBoat::accept(AIGateway * aiGw)
TResources boatCost; TResources boatCost;
shipyard->getBoatCost(boatCost); shipyard->getBoatCost(boatCost);
if(!cbcTl->getResourceAmount().canAfford(boatCost)) if(!ccTl->getResourceAmount().canAfford(boatCost))
{ {
throw cannotFulfillGoalException("Can not afford boat"); throw cannotFulfillGoalException("Can not afford boat");
} }
if(cbcTl->getPlayerRelations(aiGw->playerID, shipyard->getObject()->getOwner()) == PlayerRelations::ENEMIES) if(ccTl->getPlayerRelations(aiGw->playerID, shipyard->getObject()->getOwner()) == PlayerRelations::ENEMIES)
{ {
throw cannotFulfillGoalException("Can not build boat in enemy shipyard"); throw cannotFulfillGoalException("Can not build boat in enemy shipyard");
} }
@@ -65,7 +65,7 @@ void BuildBoat::accept(AIGateway * aiGw)
shipyard->getObject()->visitablePos().toString(), shipyard->getObject()->visitablePos().toString(),
shipyard->bestLocation().toString()); shipyard->bestLocation().toString());
cbcTl->buildBoat(shipyard); ccTl->buildBoat(shipyard);
throw goalFulfilledException(sptr(*this)); throw goalFulfilledException(sptr(*this));
} }

View File

@@ -52,11 +52,11 @@ void BuildThis::accept(AIGateway * aiGw)
if(town) if(town)
{ {
if(cbcTl->canBuildStructure(town, b) == EBuildingState::ALLOWED) if(ccTl->canBuildStructure(town, b) == EBuildingState::ALLOWED)
{ {
logAi->debug("Player %d will build %s in town of %s at %s", logAi->debug("Player %d will build %s in town of %s at %s",
aiGw->playerID, town->getTown()->buildings.at(b)->getNameTranslated(), town->getNameTranslated(), town->anchorPos().toString()); aiGw->playerID, town->getTown()->buildings.at(b)->getNameTranslated(), town->getNameTranslated(), town->anchorPos().toString());
cbcTl->buildBuilding(town, b); ccTl->buildBuilding(town, b);
return; return;
} }

View File

@@ -48,7 +48,7 @@ void BuyArmy::accept(AIGateway * aiGw)
for(int i = 0; valueBought < value && i < armyToBuy.size(); i++) for(int i = 0; valueBought < value && i < armyToBuy.size(); i++)
{ {
auto res = cbcTl->getResourceAmount(); auto res = ccTl->getResourceAmount();
auto & ci = armyToBuy[i]; auto & ci = armyToBuy[i];
if(objid != CreatureID::NONE && ci.creID.getNum() != objid) if(objid != CreatureID::NONE && ci.creID.getNum() != objid)
@@ -81,12 +81,12 @@ void BuyArmy::accept(AIGateway * aiGw)
} }
if (lowestValueSlot.validSlot()) if (lowestValueSlot.validSlot())
{ {
cbcTl->dismissCreature(town->getUpperArmy(), lowestValueSlot); ccTl->dismissCreature(town->getUpperArmy(), lowestValueSlot);
} }
} }
if (town->getUpperArmy()->stacksCount() < GameConstants::ARMY_SIZE || town->getUpperArmy()->getSlotFor(ci.creID).validSlot()) //It is possible we don't scrap despite we wanted to due to not scrapping stacks that fit our faction if (town->getUpperArmy()->stacksCount() < GameConstants::ARMY_SIZE || town->getUpperArmy()->getSlotFor(ci.creID).validSlot()) //It is possible we don't scrap despite we wanted to due to not scrapping stacks that fit our faction
{ {
cbcTl->recruitCreatures(town, town->getUpperArmy(), ci.creID, ci.count, ci.level); ccTl->recruitCreatures(town, town->getUpperArmy(), ci.creID, ci.count, ci.level);
} }
valueBought += ci.count * ci.creID.toCreature()->getAIValue(); valueBought += ci.count * ci.creID.toCreature()->getAIValue();
} }

View File

@@ -37,7 +37,7 @@ std::string CaptureObject::toString() const
TGoalVec CaptureObject::decompose(const Nullkiller * aiNk) const TGoalVec CaptureObject::decompose(const Nullkiller * aiNk) const
{ {
return CaptureObjectsBehavior(aiNk->cbc->getObj(ObjectInstanceID(objid))).decompose(aiNk); return CaptureObjectsBehavior(aiNk->cc->getObj(ObjectInstanceID(objid))).decompose(aiNk);
} }
} }

View File

@@ -22,7 +22,7 @@ using namespace Goals;
bool isKeyMaster(const QuestInfo & q) bool isKeyMaster(const QuestInfo & q)
{ {
auto object = q.getObject(cbcTl); auto object = q.getObject(ccTl);
return object && (object->ID == Obj::BORDER_GATE || object->ID == Obj::BORDERGUARD); return object && (object->ID == Obj::BORDER_GATE || object->ID == Obj::BORDERGUARD);
} }
@@ -39,7 +39,7 @@ TGoalVec CompleteQuest::decompose(const Nullkiller * ai) const
} }
logAi->debug("Trying to realize quest: %s", questToString()); logAi->debug("Trying to realize quest: %s", questToString());
auto quest = q.getQuest(cbcTl); auto quest = q.getQuest(ccTl);
if(!quest->mission.artifacts.empty()) if(!quest->mission.artifacts.empty())
return missionArt(ai); return missionArt(ai);
@@ -70,52 +70,52 @@ bool CompleteQuest::operator==(const CompleteQuest & other) const
{ {
if(isKeyMaster(q)) if(isKeyMaster(q))
{ {
return isKeyMaster(other.q) && q.getObject(cbcTl)->subID == other.q.getObject(cbcTl)->subID; return isKeyMaster(other.q) && q.getObject(ccTl)->subID == other.q.getObject(ccTl)->subID;
} }
else if(isKeyMaster(other.q)) else if(isKeyMaster(other.q))
{ {
return false; return false;
} }
return q.getQuest(cbcTl) == other.q.getQuest(cbcTl); return q.getQuest(ccTl) == other.q.getQuest(ccTl);
} }
uint64_t CompleteQuest::getHash() const uint64_t CompleteQuest::getHash() const
{ {
if(isKeyMaster(q)) if(isKeyMaster(q))
{ {
return q.getObject(cbcTl)->subID; return q.getObject(ccTl)->subID;
} }
return q.getObject(cbcTl)->id.getNum(); return q.getObject(ccTl)->id.getNum();
} }
std::string CompleteQuest::questToString() const std::string CompleteQuest::questToString() const
{ {
if(isKeyMaster(q)) if(isKeyMaster(q))
{ {
return "find " + LIBRARY->generaltexth->tentColors[q.getObject(cbcTl)->subID] + " keymaster tent"; return "find " + LIBRARY->generaltexth->tentColors[q.getObject(ccTl)->subID] + " keymaster tent";
} }
if(q.getQuest(cbcTl)->questName == CQuest::missionName(EQuestMission::NONE)) if(q.getQuest(ccTl)->questName == CQuest::missionName(EQuestMission::NONE))
return "inactive quest"; return "inactive quest";
MetaString ms; MetaString ms;
q.getQuest(cbcTl)->getRolloverText(cbcTl, ms, false); q.getQuest(ccTl)->getRolloverText(ccTl, ms, false);
return ms.toString(); return ms.toString();
} }
TGoalVec CompleteQuest::tryCompleteQuest(const Nullkiller * aiNk) const TGoalVec CompleteQuest::tryCompleteQuest(const Nullkiller * aiNk) const
{ {
auto paths = aiNk->pathfinder->getPathInfo(q.getObject(cbcTl)->visitablePos()); auto paths = aiNk->pathfinder->getPathInfo(q.getObject(ccTl)->visitablePos());
vstd::erase_if(paths, [&](const AIPath & path) -> bool vstd::erase_if(paths, [&](const AIPath & path) -> bool
{ {
return !q.getQuest(cbcTl)->checkQuest(path.targetHero); return !q.getQuest(ccTl)->checkQuest(path.targetHero);
}); });
return CaptureObjectsBehavior::getVisitGoals(paths, aiNk, q.getObject(cbcTl)); return CaptureObjectsBehavior::getVisitGoals(paths, aiNk, q.getObject(ccTl));
} }
TGoalVec CompleteQuest::missionArt(const Nullkiller * ai) const TGoalVec CompleteQuest::missionArt(const Nullkiller * ai) const
@@ -127,7 +127,7 @@ TGoalVec CompleteQuest::missionArt(const Nullkiller * ai) const
CaptureObjectsBehavior findArts; CaptureObjectsBehavior findArts;
for(auto art : q.getQuest(cbcTl)->mission.artifacts) for(auto art : q.getQuest(ccTl)->mission.artifacts)
{ {
solutions.push_back(sptr(CaptureObjectsBehavior().ofType(Obj::ARTIFACT, art.getNum()))); solutions.push_back(sptr(CaptureObjectsBehavior().ofType(Obj::ARTIFACT, art.getNum())));
} }
@@ -150,14 +150,14 @@ TGoalVec CompleteQuest::missionHero(const Nullkiller * ai) const
TGoalVec CompleteQuest::missionArmy(const Nullkiller * aiNk) const TGoalVec CompleteQuest::missionArmy(const Nullkiller * aiNk) const
{ {
auto paths = aiNk->pathfinder->getPathInfo(q.getObject(cbcTl)->visitablePos()); auto paths = aiNk->pathfinder->getPathInfo(q.getObject(ccTl)->visitablePos());
vstd::erase_if(paths, [&](const AIPath & path) -> bool vstd::erase_if(paths, [&](const AIPath & path) -> bool
{ {
return !CQuest::checkMissionArmy(q.getQuest(cbcTl), path.heroArmy); return !CQuest::checkMissionArmy(q.getQuest(ccTl), path.heroArmy);
}); });
return CaptureObjectsBehavior::getVisitGoals(paths, aiNk, q.getObject(cbcTl)); return CaptureObjectsBehavior::getVisitGoals(paths, aiNk, q.getObject(ccTl));
} }
TGoalVec CompleteQuest::missionIncreasePrimaryStat(const Nullkiller * ai) const TGoalVec CompleteQuest::missionIncreasePrimaryStat(const Nullkiller * ai) const
@@ -172,13 +172,13 @@ TGoalVec CompleteQuest::missionLevel(const Nullkiller * ai) const
TGoalVec CompleteQuest::missionKeymaster(const Nullkiller * ai) const TGoalVec CompleteQuest::missionKeymaster(const Nullkiller * ai) const
{ {
if(isObjectPassable(ai, q.getObject(cbcTl))) if(isObjectPassable(ai, q.getObject(ccTl)))
{ {
return CaptureObjectsBehavior(q.getObject(cbcTl)).decompose(ai); return CaptureObjectsBehavior(q.getObject(ccTl)).decompose(ai);
} }
else else
{ {
return CaptureObjectsBehavior().ofType(Obj::KEYMASTER, q.getObject(cbcTl)->subID).decompose(ai); return CaptureObjectsBehavior().ofType(Obj::KEYMASTER, q.getObject(ccTl)->subID).decompose(ai);
} }
} }
@@ -190,12 +190,12 @@ TGoalVec CompleteQuest::missionResources(const Nullkiller * ai) const
TGoalVec CompleteQuest::missionDestroyObj(const Nullkiller * aiNk) const TGoalVec CompleteQuest::missionDestroyObj(const Nullkiller * aiNk) const
{ {
auto obj = aiNk->cbc->getObj(q.getQuest(cbcTl)->killTarget); auto obj = aiNk->cc->getObj(q.getQuest(ccTl)->killTarget);
if(!obj) if(!obj)
return CaptureObjectsBehavior(q.getObject(cbcTl)).decompose(aiNk); return CaptureObjectsBehavior(q.getObject(ccTl)).decompose(aiNk);
auto relations = aiNk->cbc->getPlayerRelations(aiNk->playerID, obj->tempOwner); auto relations = aiNk->cc->getPlayerRelations(aiNk->playerID, obj->tempOwner);
//if(relations == PlayerRelations::SAME_PLAYER) //if(relations == PlayerRelations::SAME_PLAYER)
//{ //{

View File

@@ -26,7 +26,7 @@ void DismissHero::accept(AIGateway * aiGw)
if(!hero) if(!hero)
throw cannotFulfillGoalException("Invalid hero!"); throw cannotFulfillGoalException("Invalid hero!");
cbcTl->dismissHero(hero); ccTl->dismissHero(hero);
throw goalFulfilledException(sptr(*this)); throw goalFulfilledException(sptr(*this));
} }

View File

@@ -65,7 +65,7 @@ void ExchangeSwapTownHeroes::accept(AIGateway * aiGw)
if(!currentGarrisonHero) if(!currentGarrisonHero)
throw cannotFulfillGoalException("Invalid configuration. There is no hero in town garrison."); throw cannotFulfillGoalException("Invalid configuration. There is no hero in town garrison.");
cbcTl->swapGarrisonHero(town); ccTl->swapGarrisonHero(town);
if(currentGarrisonHero != town->getVisitingHero()) if(currentGarrisonHero != town->getVisitingHero())
{ {
@@ -81,7 +81,7 @@ void ExchangeSwapTownHeroes::accept(AIGateway * aiGw)
} }
if(town->getVisitingHero() && town->getVisitingHero() != getGarrisonHero()) if(town->getVisitingHero() && town->getVisitingHero() != getGarrisonHero())
cbcTl->swapGarrisonHero(town); ccTl->swapGarrisonHero(town);
aiGw->makePossibleUpgrades(town); aiGw->makePossibleUpgrades(town);
aiGw->moveHeroToTile(town->visitablePos(), getGarrisonHero()); aiGw->moveHeroToTile(town->visitablePos(), getGarrisonHero());
@@ -94,12 +94,12 @@ void ExchangeSwapTownHeroes::accept(AIGateway * aiGw)
{ {
while (upperArmy->stacksCount() != 0) while (upperArmy->stacksCount() != 0)
{ {
cbcTl->dismissCreature(upperArmy, upperArmy->Slots().begin()->first); ccTl->dismissCreature(upperArmy, upperArmy->Slots().begin()->first);
} }
} }
} }
cbcTl->swapGarrisonHero(town); ccTl->swapGarrisonHero(town);
if(lockingReason != HeroLockedReason::NOT_LOCKED) if(lockingReason != HeroLockedReason::NOT_LOCKED)
{ {

View File

@@ -88,11 +88,11 @@ void ExecuteHeroChain::accept(AIGateway * aiGw)
aiGw->nullkiller->setTargetObject(objid); aiGw->nullkiller->setTargetObject(objid);
aiGw->nullkiller->objectClusterizer->reset(); aiGw->nullkiller->objectClusterizer->reset();
auto targetObject = aiGw->cbc->getObj(static_cast<ObjectInstanceID>(objid), false); auto targetObject = aiGw->cc->getObj(static_cast<ObjectInstanceID>(objid), false);
if(chainPath.turn() == 0 && targetObject && targetObject->ID == Obj::TOWN) if(chainPath.turn() == 0 && targetObject && targetObject->ID == Obj::TOWN)
{ {
auto relations = aiGw->cbc->getPlayerRelations(aiGw->playerID, targetObject->getOwner()); auto relations = aiGw->cc->getPlayerRelations(aiGw->playerID, targetObject->getOwner());
if(relations == PlayerRelations::ENEMIES) if(relations == PlayerRelations::ENEMIES)
{ {
@@ -200,7 +200,7 @@ void ExecuteHeroChain::accept(AIGateway * aiGw)
auto findWhirlpool = [&aiGw](const int3 & pos) -> ObjectInstanceID auto findWhirlpool = [&aiGw](const int3 & pos) -> ObjectInstanceID
{ {
auto objs = aiGw->cbc->getVisitableObjs(pos); auto objs = aiGw->cc->getVisitableObjs(pos);
auto whirlpool = std::find_if(objs.begin(), objs.end(), [](const CGObjectInstance * o)->bool auto whirlpool = std::find_if(objs.begin(), objs.end(), [](const CGObjectInstance * o)->bool
{ {
return o->ID == Obj::WHIRLPOOL; return o->ID == Obj::WHIRLPOOL;
@@ -296,7 +296,7 @@ std::string ExecuteHeroChain::toString() const
bool ExecuteHeroChain::moveHeroToTile(AIGateway * aiGw, const CGHeroInstance * hero, const int3 & tile) bool ExecuteHeroChain::moveHeroToTile(AIGateway * aiGw, const CGHeroInstance * hero, const int3 & tile)
{ {
if(tile == hero->visitablePos() && aiGw->cbc->getVisitableObjs(hero->visitablePos()).size() < 2) if(tile == hero->visitablePos() && aiGw->cc->getVisitableObjs(hero->visitablePos()).size() < 2)
{ {
logAi->warn("Why do I want to move hero %s to tile %s? Already standing on that tile! ", hero->getNameTranslated(), tile.toString()); logAi->warn("Why do I want to move hero %s to tile %s? Already standing on that tile! ", hero->getNameTranslated(), tile.toString());

View File

@@ -28,7 +28,7 @@ void ExploreNeighbourTile::accept(AIGateway * aiGw)
{ {
ExplorationHelper h(hero, aiGw->nullkiller.get(), true); ExplorationHelper h(hero, aiGw->nullkiller.get(), true);
for(int i = 0; i < tilesToExplore && aiGw->cbc->getObj(hero->id, false) && hero->movementPointsRemaining() > 0; i++) for(int i = 0; i < tilesToExplore && aiGw->cc->getObj(hero->id, false) && hero->movementPointsRemaining() > 0; i++)
{ {
int3 pos = hero->visitablePos(); int3 pos = hero->visitablePos();
float value = 0; float value = 0;

View File

@@ -38,7 +38,7 @@ void RecruitHero::accept(AIGateway * aiGw)
logAi->debug("Trying to recruit a hero in %s at %s", t->getNameTranslated(), t->visitablePos().toString()); logAi->debug("Trying to recruit a hero in %s at %s", t->getNameTranslated(), t->visitablePos().toString());
auto heroes = cbcTl->getAvailableHeroes(t); auto heroes = ccTl->getAvailableHeroes(t);
if(!heroes.size()) if(!heroes.size())
{ {
@@ -61,13 +61,13 @@ void RecruitHero::accept(AIGateway * aiGw)
if(t->getVisitingHero()) if(t->getVisitingHero())
{ {
cbcTl->swapGarrisonHero(t); ccTl->swapGarrisonHero(t);
} }
if(t->getVisitingHero()) if(t->getVisitingHero())
throw cannotFulfillGoalException("Town " + t->nodeName() + " is occupied. Cannot recruit hero!"); throw cannotFulfillGoalException("Town " + t->nodeName() + " is occupied. Cannot recruit hero!");
cbcTl->recruitHero(t, heroToHire); ccTl->recruitHero(t, heroToHire);
{ {
std::unique_lock lockGuard(aiGw->nullkiller->aiStateMutex); std::unique_lock lockGuard(aiGw->nullkiller->aiStateMutex);

View File

@@ -25,9 +25,9 @@ namespace NK2AI
using namespace Goals; using namespace Goals;
ExplorationHelper::ExplorationHelper(const CGHeroInstance * hero, const Nullkiller * aiNk, bool useCPathfinderAccessibility) ExplorationHelper::ExplorationHelper(const CGHeroInstance * hero, const Nullkiller * aiNk, bool useCPathfinderAccessibility)
:aiNk(aiNk), cbc(aiNk->cbc.get()), hero(hero), useCPathfinderAccessibility(useCPathfinderAccessibility) :aiNk(aiNk), cc(aiNk->cc.get()), hero(hero), useCPathfinderAccessibility(useCPathfinderAccessibility)
{ {
ts = cbc->getPlayerTeam(aiNk->playerID); ts = cc->getPlayerTeam(aiNk->playerID);
sightRadius = hero->getSightRadius(); sightRadius = hero->getSightRadius();
bestGoal = sptr(Goals::Invalid()); bestGoal = sptr(Goals::Invalid());
bestValue = 0; bestValue = 0;
@@ -55,7 +55,7 @@ bool ExplorationHelper::scanSector(int scanRadius)
{ {
for(tile.y = ourPos.y - scanRadius; tile.y <= ourPos.y + scanRadius; tile.y++) for(tile.y = ourPos.y - scanRadius; tile.y <= ourPos.y + scanRadius; tile.y++)
{ {
if(cbc->isInTheMap(tile) && slice[tile.x][tile.y]) if(cc->isInTheMap(tile) && slice[tile.x][tile.y])
{ {
scanTile(tile); scanTile(tile);
} }
@@ -67,7 +67,7 @@ bool ExplorationHelper::scanSector(int scanRadius)
bool ExplorationHelper::scanMap() bool ExplorationHelper::scanMap()
{ {
int3 mapSize = cbc->getMapSize(); int3 mapSize = cc->getMapSize();
int perimeter = 2 * sightRadius * (mapSize.x + mapSize.y); int perimeter = 2 * sightRadius * (mapSize.x + mapSize.y);
std::vector<int3> edgeTiles; std::vector<int3> edgeTiles;
@@ -79,7 +79,7 @@ bool ExplorationHelper::scanMap()
{ {
bool hasInvisibleNeighbor = false; bool hasInvisibleNeighbor = false;
foreach_neighbour(cbc, pos, [&](CCallback * cbp, int3 neighbour) foreach_neighbour(cc, pos, [&](CCallback * cbp, int3 neighbour)
{ {
if(!ts->fogOfWarMap[neighbour.z][neighbour.x][neighbour.y]) if(!ts->fogOfWarMap[neighbour.z][neighbour.x][neighbour.y])
{ {
@@ -120,7 +120,7 @@ bool ExplorationHelper::scanMap()
for(const int3 & tile : tilesToExploreFrom) for(const int3 & tile : tilesToExploreFrom)
{ {
foreach_neighbour(cbc, tile, [&](CCallback * cbp, int3 neighbour) foreach_neighbour(cc, tile, [&](CCallback * cbp, int3 neighbour)
{ {
if(potentialTiles[neighbour.z][neighbour.x][neighbour.y]) if(potentialTiles[neighbour.z][neighbour.x][neighbour.y])
{ {
@@ -143,7 +143,7 @@ bool ExplorationHelper::scanMap()
void ExplorationHelper::scanTile(const int3 & tile) void ExplorationHelper::scanTile(const int3 & tile)
{ {
if(tile == ourPos if(tile == ourPos
|| !aiNk->cbc->getTile(tile, false) || !aiNk->cc->getTile(tile, false)
|| !aiNk->pathfinder->isTileAccessible(hero, tile)) //shouldn't happen, but it does || !aiNk->pathfinder->isTileAccessible(hero, tile)) //shouldn't happen, but it does
return; return;
@@ -152,7 +152,7 @@ void ExplorationHelper::scanTile(const int3 & tile)
return; return;
auto paths = aiNk->pathfinder->getPathInfo(tile); auto paths = aiNk->pathfinder->getPathInfo(tile);
auto waysToVisit = CaptureObjectsBehavior::getVisitGoals(paths, aiNk, aiNk->cbc->getTopObj(tile)); auto waysToVisit = CaptureObjectsBehavior::getVisitGoals(paths, aiNk, aiNk->cc->getTopObj(tile));
for(int i = 0; i != paths.size(); i++) for(int i = 0; i != paths.size(); i++)
{ {
@@ -166,7 +166,7 @@ void ExplorationHelper::scanTile(const int3 & tile)
if(ourValue > bestValue) //avoid costly checks of tiles that don't reveal much if(ourValue > bestValue) //avoid costly checks of tiles that don't reveal much
{ {
auto obj = cbc->getTopObj(tile); auto obj = cc->getTopObj(tile);
// picking up resources does not yield any exploration at all. // picking up resources does not yield any exploration at all.
// if it blocks the way to some explorable tile AIPathfinder will take care of it // if it blocks the way to some explorable tile AIPathfinder will take care of it
@@ -197,7 +197,7 @@ int ExplorationHelper::howManyTilesWillBeDiscovered(const int3 & pos) const
{ {
for(npos.y = pos.y - sightRadius; npos.y <= pos.y + sightRadius; npos.y++) for(npos.y = pos.y - sightRadius; npos.y <= pos.y + sightRadius; npos.y++)
{ {
if(cbc->isInTheMap(npos) if(cc->isInTheMap(npos)
&& pos.dist2d(npos) - 0.5 < sightRadius && pos.dist2d(npos) - 0.5 < sightRadius
&& !slice[npos.x][npos.y]) && !slice[npos.x][npos.y])
{ {
@@ -220,7 +220,7 @@ bool ExplorationHelper::hasReachableNeighbor(const int3 & pos) const
for(const int3 & dir : int3::getDirs()) for(const int3 & dir : int3::getDirs())
{ {
int3 tile = pos + dir; int3 tile = pos + dir;
if(cbc->isInTheMap(tile)) if(cc->isInTheMap(tile))
{ {
auto isAccessible = useCPathfinderAccessibility auto isAccessible = useCPathfinderAccessibility
? aiNk->getPathsInfo(hero)->getPathInfo(tile)->reachable() ? aiNk->getPathsInfo(hero)->getPathInfo(tile)->reachable()

View File

@@ -28,7 +28,7 @@ private:
int3 bestTile; int3 bestTile;
int bestTilesDiscovered; int bestTilesDiscovered;
const Nullkiller * aiNk; const Nullkiller * aiNk;
CCallback * cbc; CCallback * cc;
const TeamState * ts; const TeamState * ts;
int3 ourPos; int3 ourPos;
bool allowDeadEndCancellation; bool allowDeadEndCancellation;

View File

@@ -103,7 +103,7 @@ int AINodeStorage::getBucketSize() const
} }
AINodeStorage::AINodeStorage(const Nullkiller * aiNk, const int3 & Sizes) AINodeStorage::AINodeStorage(const Nullkiller * aiNk, const int3 & Sizes)
: sizes(Sizes), aiNk(aiNk), cbc(aiNk->cbc.get()), nodes(Sizes, aiNk->settings->getPathfinderBucketSize() * aiNk->settings->getPathfinderBucketsCount()) : sizes(Sizes), aiNk(aiNk), cc(aiNk->cc.get()), nodes(Sizes, aiNk->settings->getPathfinderBucketSize() * aiNk->settings->getPathfinderBucketsCount())
{ {
accessibility = std::make_unique<boost::multi_array<EPathAccessibility, 4>>( accessibility = std::make_unique<boost::multi_array<EPathAccessibility, 4>>(
boost::extents[sizes.z][sizes.x][sizes.y][EPathfindingLayer::NUM_LAYERS]); boost::extents[sizes.z][sizes.x][sizes.y][EPathfindingLayer::NUM_LAYERS]);
@@ -1162,11 +1162,11 @@ void AINodeStorage::calculateTownPortal(
const std::vector<CGPathNode *> & initialNodes, const std::vector<CGPathNode *> & initialNodes,
TVector & output) TVector & output)
{ {
auto towns = cbc->getTownsInfo(false); auto towns = cc->getTownsInfo(false);
vstd::erase_if(towns, [&](const CGTownInstance * t) -> bool vstd::erase_if(towns, [&](const CGTownInstance * t) -> bool
{ {
return cbc->getPlayerRelations(actor->hero->tempOwner, t->tempOwner) == PlayerRelations::ENEMIES; return cc->getPlayerRelations(actor->hero->tempOwner, t->tempOwner) == PlayerRelations::ENEMIES;
}); });
if(!towns.size()) if(!towns.size())
@@ -1457,7 +1457,7 @@ void AINodeStorage::calculateChainInfo(std::vector<AIPath> & paths, const int3 &
} }
int fortLevel = 0; int fortLevel = 0;
auto visitableObjects = cbc->getVisitableObjs(pos); auto visitableObjects = cc->getVisitableObjs(pos);
for (auto obj : visitableObjects) for (auto obj : visitableObjects)
{ {
if (objWithID<Obj::TOWN>(obj)) if (objWithID<Obj::TOWN>(obj))

View File

@@ -165,7 +165,7 @@ private:
std::unique_ptr<boost::multi_array<EPathAccessibility, 4>> accessibility; std::unique_ptr<boost::multi_array<EPathAccessibility, 4>> accessibility;
const CPlayerSpecificInfoCallback * cbc; const CPlayerSpecificInfoCallback * cc;
const Nullkiller * aiNk; const Nullkiller * aiNk;
AISharedStorage nodes; AISharedStorage nodes;
std::vector<std::shared_ptr<ChainActor>> actors; std::vector<std::shared_ptr<ChainActor>> actors;

View File

@@ -29,7 +29,7 @@ namespace AIPathfinding
Goals::TSubgoal BuildBoatAction::decompose(const Nullkiller * aiNk, const CGHeroInstance * hero) const Goals::TSubgoal BuildBoatAction::decompose(const Nullkiller * aiNk, const CGHeroInstance * hero) const
{ {
if(cbc->getPlayerRelations(aiNk->playerID, shipyard->getObject()->getOwner()) == PlayerRelations::ENEMIES) if(cpsic->getPlayerRelations(aiNk->playerID, shipyard->getObject()->getOwner()) == PlayerRelations::ENEMIES)
{ {
return Goals::sptr(Goals::CaptureObject(targetObject())); return Goals::sptr(Goals::CaptureObject(targetObject()));
} }
@@ -39,7 +39,7 @@ namespace AIPathfinding
bool BuildBoatAction::canAct(const Nullkiller * ai, const CGHeroInstance * hero, const TResources & reservedResources) const bool BuildBoatAction::canAct(const Nullkiller * ai, const CGHeroInstance * hero, const TResources & reservedResources) const
{ {
if(cbc->getPlayerRelations(hero->tempOwner, shipyard->getObject()->getOwner()) == PlayerRelations::ENEMIES) if(cpsic->getPlayerRelations(hero->tempOwner, shipyard->getObject()->getOwner()) == PlayerRelations::ENEMIES)
{ {
#if NKAI_TRACE_LEVEL > 1 #if NKAI_TRACE_LEVEL > 1
logAi->trace("Can not build a boat. Shipyard is enemy."); logAi->trace("Can not build a boat. Shipyard is enemy.");
@@ -51,7 +51,7 @@ namespace AIPathfinding
shipyard->getBoatCost(boatCost); shipyard->getBoatCost(boatCost);
if(!cbc->getResourceAmount().canAfford(reservedResources + boatCost)) if(!cpsic->getResourceAmount().canAfford(reservedResources + boatCost))
{ {
#if NKAI_TRACE_LEVEL > 1 #if NKAI_TRACE_LEVEL > 1
logAi->trace("Can not build a boat. Not enough resources."); logAi->trace("Can not build a boat. Not enough resources.");
@@ -87,7 +87,7 @@ namespace AIPathfinding
std::shared_ptr<SpecialAction> BuildBoatActionFactory::create(const Nullkiller * aiNk) std::shared_ptr<SpecialAction> BuildBoatActionFactory::create(const Nullkiller * aiNk)
{ {
return std::make_shared<BuildBoatAction>(aiNk->cbc.get(), dynamic_cast<const IShipyard * >(aiNk->cbc->getObj(shipyard))); return std::make_shared<BuildBoatAction>(aiNk->cc.get(), dynamic_cast<const IShipyard * >(aiNk->cc->getObj(shipyard)));
} }
void SummonBoatAction::execute(AIGateway * aiGw, const CGHeroInstance * hero) const void SummonBoatAction::execute(AIGateway * aiGw, const CGHeroInstance * hero) const

View File

@@ -54,11 +54,11 @@ namespace AIPathfinding
{ {
private: private:
const IShipyard * shipyard; const IShipyard * shipyard;
const CPlayerSpecificInfoCallback * cbc; const CPlayerSpecificInfoCallback * cpsic;
public: public:
BuildBoatAction(const CPlayerSpecificInfoCallback * cbc, const IShipyard * shipyard) BuildBoatAction(const CPlayerSpecificInfoCallback * cpsic, const IShipyard * shipyard)
: cbc(cbc), shipyard(shipyard) : cpsic(cpsic), shipyard(shipyard)
{ {
} }

View File

@@ -31,8 +31,8 @@ namespace AIPathfinding
bool QuestAction::canAct(const Nullkiller * aiNk, const CGHeroInstance * hero) const bool QuestAction::canAct(const Nullkiller * aiNk, const CGHeroInstance * hero) const
{ {
auto object = questInfo.getObject(aiNk->cbc.get()); auto object = questInfo.getObject(aiNk->cc.get());
auto quest = questInfo.getQuest(aiNk->cbc.get()); auto quest = questInfo.getQuest(aiNk->cc.get());
if(object->ID == Obj::BORDER_GATE || object->ID == Obj::BORDERGUARD) if(object->ID == Obj::BORDER_GATE || object->ID == Obj::BORDERGUARD)
{ {
return dynamic_cast<const IQuestObject *>(object)->checkQuest(hero); return dynamic_cast<const IQuestObject *>(object)->checkQuest(hero);
@@ -52,7 +52,7 @@ namespace AIPathfinding
void QuestAction::execute(AIGateway * aiGw, const CGHeroInstance * hero) const void QuestAction::execute(AIGateway * aiGw, const CGHeroInstance * hero) const
{ {
aiGw->moveHeroToTile(questInfo.getObject(aiGw->cbc.get())->visitablePos(), hero); aiGw->moveHeroToTile(questInfo.getObject(aiGw->cc.get())->visitablePos(), hero);
} }
std::string QuestAction::toString() const std::string QuestAction::toString() const

View File

@@ -260,7 +260,7 @@ ExchangeResult HeroExchangeMap::tryExchangeNoLock(const ChainActor * other)
if(actor->allowSpellCast || other->allowSpellCast) if(actor->allowSpellCast || other->allowSpellCast)
return result; return result;
TResources resources = aiNk->cbc->getResourceAmount(); TResources resources = aiNk->cc->getResourceAmount();
if(!resources.canAfford(actor->armyCost + other->armyCost)) if(!resources.canAfford(actor->armyCost + other->armyCost))
{ {
@@ -367,7 +367,7 @@ HeroExchangeArmy * HeroExchangeMap::tryUpgrade(
if(upgrader->ID == Obj::TOWN) if(upgrader->ID == Obj::TOWN)
{ {
auto buyArmy = aiNk->armyManager->getArmyAvailableToBuy(target, aiNk->cbc->getTown(upgrader->id), resources); auto buyArmy = aiNk->armyManager->getArmyAvailableToBuy(target, aiNk->cc->getTown(upgrader->id), resources);
for(auto & creatureToBuy : buyArmy) for(auto & creatureToBuy : buyArmy)
{ {
@@ -394,7 +394,7 @@ HeroExchangeArmy * HeroExchangeMap::tryUpgrade(
HeroExchangeArmy * HeroExchangeMap::pickBestCreatures(const CCreatureSet * army1, const CCreatureSet * army2) const HeroExchangeArmy * HeroExchangeMap::pickBestCreatures(const CCreatureSet * army1, const CCreatureSet * army2) const
{ {
auto * target = new HeroExchangeArmy(); auto * target = new HeroExchangeArmy();
auto bestArmy = aiNk->armyManager->getBestArmy(actor->hero, army1, army2, aiNk->cbc->getTile(actor->hero->visitablePos())->getTerrainID()); auto bestArmy = aiNk->armyManager->getBestArmy(actor->hero, army1, army2, aiNk->cc->getTile(actor->hero->visitablePos())->getTerrainID());
for(auto & slotInfo : bestArmy) for(auto & slotInfo : bestArmy)
{ {

View File

@@ -122,7 +122,7 @@ void GraphPaths::calculatePaths(const CGHeroInstance * targetHero, const Nullkil
if(targetGraphNode.objID.hasValue()) if(targetGraphNode.objID.hasValue())
{ {
targetNode.obj = aiNk->cbc->getObj(targetGraphNode.objID, false); targetNode.obj = aiNk->cc->getObj(targetGraphNode.objID, false);
if(targetNode.obj && targetNode.obj->ID == Obj::HERO) if(targetNode.obj && targetNode.obj->ID == Obj::HERO)
return; return;

View File

@@ -86,7 +86,7 @@ void ObjectGraph::removeObject(const CGObjectInstance * obj)
{ {
vstd::erase_if(nodes[obj->visitablePos()].connections, [&](const std::pair<int3, ObjectLink> & link) -> bool vstd::erase_if(nodes[obj->visitablePos()].connections, [&](const std::pair<int3, ObjectLink> & link) -> bool
{ {
auto tile = cbcTl->getTile(link.first, false); auto tile = ccTl->getTile(link.first, false);
return tile && tile->isWater(); return tile && tile->isWater();
}); });

View File

@@ -35,7 +35,7 @@ void ObjectGraphCalculator::setGraphObjects()
} }
} }
for(auto town : aiNk->cbc->getTownsInfo()) for(auto town : aiNk->cc->getTownsInfo())
{ {
addObjectActor(town); addObjectActor(town);
} }
@@ -47,7 +47,7 @@ void ObjectGraphCalculator::calculateConnections()
std::vector<AIPath> pathCache; std::vector<AIPath> pathCache;
foreach_tile_pos(aiNk->cbc.get(), [this, &pathCache](const CPlayerSpecificInfoCallback * cb, const int3 & pos) foreach_tile_pos(aiNk->cc.get(), [this, &pathCache](const CPlayerSpecificInfoCallback * cb, const int3 & pos)
{ {
calculateConnections(pos, pathCache); calculateConnections(pos, pathCache);
}); });
@@ -65,7 +65,7 @@ float ObjectGraphCalculator::getNeighborConnectionsCost(const int3 & pos, std::v
} }
foreach_neighbour( foreach_neighbour(
aiNk->cbc.get(), aiNk->cc.get(),
pos, pos,
[this, &neighborCost, &pathCache](const CPlayerSpecificInfoCallback * cb, const int3 & neighbor) [this, &neighborCost, &pathCache](const CPlayerSpecificInfoCallback * cb, const int3 & neighbor)
{ {
@@ -91,12 +91,12 @@ void ObjectGraphCalculator::addMinimalDistanceJunctions()
{ {
tbb::concurrent_unordered_set<int3, std::hash<int3>> junctions; tbb::concurrent_unordered_set<int3, std::hash<int3>> junctions;
pforeachTilePaths(aiNk->cbc->getMapSize(), aiNk, [this, &junctions](const int3 & pos, std::vector<AIPath> & paths) pforeachTilePaths(aiNk->cc->getMapSize(), aiNk, [this, &junctions](const int3 & pos, std::vector<AIPath> & paths)
{ {
if(target->hasNodeAt(pos)) if(target->hasNodeAt(pos))
return; return;
if(aiNk->cbc->getGuardingCreaturePosition(pos).isValid()) if(aiNk->cc->getGuardingCreaturePosition(pos).isValid())
return; return;
ConnectionCostInfo currentCost = getConnectionsCost(paths); ConnectionCostInfo currentCost = getConnectionsCost(paths);
@@ -134,7 +134,7 @@ void ObjectGraphCalculator::calculateConnections(const int3 & pos, std::vector<A
if(target->hasNodeAt(pos)) if(target->hasNodeAt(pos))
{ {
foreach_neighbour( foreach_neighbour(
aiNk->cbc.get(), aiNk->cc.get(),
pos, pos,
[this, &pos, &pathCache](const CPlayerSpecificInfoCallback * cb, const int3 & neighbor) [this, &pos, &pathCache](const CPlayerSpecificInfoCallback * cb, const int3 & neighbor)
{ {
@@ -152,7 +152,7 @@ void ObjectGraphCalculator::calculateConnections(const int3 & pos, std::vector<A
} }
}); });
auto obj = aiNk->cbc->getTopObj(pos); auto obj = aiNk->cc->getTopObj(pos);
if((obj && obj->ID == Obj::BOAT) || target->isVirtualBoat(pos)) if((obj && obj->ID == Obj::BOAT) || target->isVirtualBoat(pos))
{ {
@@ -185,7 +185,7 @@ void ObjectGraphCalculator::calculateConnections(const int3 & pos, std::vector<A
return; return;
} }
auto guardPos = aiNk->cbc->getGuardingCreaturePosition(pos); auto guardPos = aiNk->cc->getGuardingCreaturePosition(pos);
aiNk->pathfinder->calculatePathInfo(pathCache, pos); aiNk->pathfinder->calculatePathInfo(pathCache, pos);
@@ -205,12 +205,12 @@ void ObjectGraphCalculator::calculateConnections(const int3 & pos, std::vector<A
auto obj1 = actorObjectMap[path1.targetHero]; auto obj1 = actorObjectMap[path1.targetHero];
auto obj2 = actorObjectMap[path2.targetHero]; auto obj2 = actorObjectMap[path2.targetHero];
auto tile1 = cbcTl->getTile(pos1); auto tile1 = ccTl->getTile(pos1);
auto tile2 = cbcTl->getTile(pos2); auto tile2 = ccTl->getTile(pos2);
if(tile2->isWater() && !tile1->isWater()) if(tile2->isWater() && !tile1->isWater())
{ {
if(!cbcTl->getTile(pos)->isWater()) if(!ccTl->getTile(pos)->isWater())
continue; continue;
auto startingObjIsBoat = (obj1 && obj1->ID == Obj::BOAT) || target->isVirtualBoat(pos1); auto startingObjIsBoat = (obj1 && obj1->ID == Obj::BOAT) || target->isVirtualBoat(pos1);
@@ -295,7 +295,7 @@ void ObjectGraphCalculator::addObjectActor(const CGObjectInstance * obj)
objectActor->pos = objectActor->convertFromVisitablePos(visitablePos); objectActor->pos = objectActor->convertFromVisitablePos(visitablePos);
objectActor->initObj(randomizer); objectActor->initObj(randomizer);
if(cbcTl->getTile(visitablePos)->isWater()) if(ccTl->getTile(visitablePos)->isWater())
{ {
objectActor->setBoat(temporaryBoats.emplace_back(std::make_unique<CGBoat>(objectActor->cb)).get()); objectActor->setBoat(temporaryBoats.emplace_back(std::make_unique<CGBoat>(objectActor->cb)).get());
} }
@@ -332,7 +332,7 @@ void ObjectGraphCalculator::addJunctionActor(const int3 & visitablePos, bool isV
objectActor->pos = objectActor->convertFromVisitablePos(visitablePos); objectActor->pos = objectActor->convertFromVisitablePos(visitablePos);
objectActor->initObj(randomizer); objectActor->initObj(randomizer);
if(isVirtualBoat || aiNk->cbc->getTile(visitablePos)->isWater()) if(isVirtualBoat || aiNk->cc->getTile(visitablePos)->isWater())
{ {
objectActor->setBoat(temporaryBoats.emplace_back(std::make_unique<CGBoat>(objectActor->cb)).get()); objectActor->setBoat(temporaryBoats.emplace_back(std::make_unique<CGBoat>(objectActor->cb)).get());
} }

View File

@@ -49,7 +49,7 @@ namespace AIPathfinding
return; return;
// when actor represents moster graph node, we need to let him escape monster // when actor represents moster graph node, we need to let him escape monster
if(cbcTl->getGuardingCreaturePosition(source.coord) == actor->initialPosition) if(ccTl->getGuardingCreaturePosition(source.coord) == actor->initialPosition)
return; return;
} }