diff --git a/AI/EmptyAI/CEmptyAI.cpp b/AI/EmptyAI/CEmptyAI.cpp index 0e0a35489..2ae81c102 100644 --- a/AI/EmptyAI/CEmptyAI.cpp +++ b/AI/EmptyAI/CEmptyAI.cpp @@ -27,7 +27,7 @@ void CEmptyAI::initGameInterface(std::shared_ptr ENV, std::shared_p cb = CB; env = ENV; human=false; - playerID = *cb->getMyColor(); + playerID = *cb->getPlayerID(); } void CEmptyAI::yourTurn(QueryID queryID) diff --git a/AI/Nullkiller/AIGateway.cpp b/AI/Nullkiller/AIGateway.cpp index 83e0b1b28..6ed2fdc90 100644 --- a/AI/Nullkiller/AIGateway.cpp +++ b/AI/Nullkiller/AIGateway.cpp @@ -536,7 +536,7 @@ void AIGateway::initGameInterface(std::shared_ptr env, std::shared_ cbc = CB; NET_EVENT_HANDLER; - playerID = *myCb->getMyColor(); + playerID = *myCb->getPlayerID(); myCb->waitTillRealize = true; myCb->unlockGsWhenWaiting = true; diff --git a/AI/StupidAI/StupidAI.cpp b/AI/StupidAI/StupidAI.cpp index 6cd6a15b2..5836b2b7a 100644 --- a/AI/StupidAI/StupidAI.cpp +++ b/AI/StupidAI/StupidAI.cpp @@ -226,12 +226,12 @@ void CStupidAI::battleEnd(const BattleID & battleID, const BattleResult *br, Que // print("battleResultsApplied called"); // } -void CStupidAI::battleNewRoundFirst(const BattleID & battleID, int round) +void CStupidAI::battleNewRoundFirst(const BattleID & battleID) { print("battleNewRoundFirst called"); } -void CStupidAI::battleNewRound(const BattleID & battleID, int round) +void CStupidAI::battleNewRound(const BattleID & battleID) { print("battleNewRound called"); } diff --git a/AI/StupidAI/StupidAI.h b/AI/StupidAI/StupidAI.h index 20776bbc4..744214643 100644 --- a/AI/StupidAI/StupidAI.h +++ b/AI/StupidAI/StupidAI.h @@ -41,8 +41,8 @@ public: void battleStacksAttacked(const BattleID & battleID, const std::vector & bsa, bool ranged) override; //called when stack receives damage (after battleAttack()) void battleEnd(const BattleID & battleID, const BattleResult *br, QueryID queryID) override; //void battleResultsApplied() override; //called when all effects of last battle are applied - void battleNewRoundFirst(const BattleID & battleID, int round) override; //called at the beginning of each turn before changes are applied; - void battleNewRound(const BattleID & battleID, int round) override; //called at the beginning of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn + void battleNewRoundFirst(const BattleID & battleID) override; //called at the beginning of each turn before changes are applied; + void battleNewRound(const BattleID & battleID) override; //called at the beginning of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn void battleStackMoved(const BattleID & battleID, const CStack * stack, std::vector dest, int distance, bool teleport) override; void battleSpellCast(const BattleID & battleID, const BattleSpellCast *sc) override; void battleStacksEffectsSet(const BattleID & battleID, const SetStackEffect & sse) override;//called when a specific effect is set to stacks diff --git a/AI/VCAI/VCAI.cpp b/AI/VCAI/VCAI.cpp index 5070ca2d7..ddc952fbc 100644 --- a/AI/VCAI/VCAI.cpp +++ b/AI/VCAI/VCAI.cpp @@ -600,7 +600,7 @@ void VCAI::initGameInterface(std::shared_ptr ENV, std::shared_ptrinit(CB.get()); NET_EVENT_HANDLER; //sets ah->rm->cb - playerID = *myCb->getMyColor(); + playerID = *myCb->getPlayerID(); myCb->waitTillRealize = true; myCb->unlockGsWhenWaiting = true; diff --git a/CCallback.cpp b/CCallback.cpp index 43970c048..542b781a1 100644 --- a/CCallback.cpp +++ b/CCallback.cpp @@ -203,7 +203,7 @@ bool CCallback::buildBuilding(const CGTownInstance *town, BuildingID buildingID) return true; } -void CBattleCallback::battleMakeSpellAction(const BattleAction & action) +void CBattleCallback::battleMakeSpellAction(const BattleID & battleID, const BattleAction & action) { assert(action.actionType == EActionType::HERO_SPELL); MakeAction mca(action); @@ -212,7 +212,7 @@ void CBattleCallback::battleMakeSpellAction(const BattleAction & action) int CBattleCallback::sendRequest(const CPackForServer * request) { - int requestID = cl->sendRequest(request, *player); + int requestID = cl->sendRequest(request, *getPlayerID()); if(waitTillRealize) { logGlobal->trace("We'll wait till request %d is answered.\n", requestID); @@ -226,8 +226,7 @@ int CBattleCallback::sendRequest(const CPackForServer * request) void CCallback::swapGarrisonHero( const CGTownInstance *town ) { - if(town->tempOwner == *player - || (town->garrisonHero && town->garrisonHero->tempOwner == *player )) + if(town->tempOwner == *player || (town->garrisonHero && town->garrisonHero->tempOwner == *player )) { GarrisonHeroSwap pack(town->id); sendRequest(&pack); @@ -236,7 +235,7 @@ void CCallback::swapGarrisonHero( const CGTownInstance *town ) void CCallback::buyArtifact(const CGHeroInstance *hero, ArtifactID aid) { - if(hero->tempOwner != player) return; + if(hero->tempOwner != *player) return; BuyArtifact pack(hero->id,aid); sendRequest(&pack); @@ -297,8 +296,8 @@ void CCallback::buildBoat( const IShipyard *obj ) sendRequest(&bb); } -CCallback::CCallback(CGameState * GS, std::optional Player, CClient * C): - CBattleCallback(Player, C) +CCallback::CCallback(CGameState * GS, std::optional Player, CClient * C) + : CBattleCallback(Player, C) { gs = GS; @@ -306,10 +305,7 @@ CCallback::CCallback(CGameState * GS, std::optional Player, CClient unlockGsWhenWaiting = false; } -CCallback::~CCallback() -{ -//trivial, but required. Don`t remove. -} +CCallback::~CCallback() = default; bool CCallback::canMoveBetween(const int3 &a, const int3 &b) { @@ -322,6 +318,11 @@ std::shared_ptr CCallback::getPathsInfo(const CGHeroInstance * return cl->getPathsInfo(h); } +std::optional CCallback::getPlayerID() const +{ + return CBattleCallback::getPlayerID(); +} + int3 CCallback::getGuardingCreaturePosition(int3 tile) { if (!gs->map->isInTheMap(tile)) @@ -371,23 +372,23 @@ scripting::Pool * CBattleCallback::getContextPool() const } #endif -CBattleCallback::CBattleCallback(std::optional Player, CClient * C) +CBattleCallback::CBattleCallback(std::optional player, CClient * C): + cl(C), + player(player) { - player = Player; - cl = C; } -void CBattleCallback::battleMakeUnitAction(const BattleAction & action) +void CBattleCallback::battleMakeUnitAction(const BattleID & battleID, const BattleAction & action) { - assert(!cl->gs->curB->tacticDistance); + assert(!cl->gs->getBattle(battleID)->tacticDistance); MakeAction ma; ma.ba = action; sendRequest(&ma); } -void CBattleCallback::battleMakeTacticAction( const BattleAction & action ) +void CBattleCallback::battleMakeTacticAction(const BattleID & battleID, const BattleAction & action ) { - assert(cl->gs->curB->tacticDistance); + assert(cl->gs->getBattle(battleID)->tacticDistance); MakeAction ma; ma.ba = action; sendRequest(&ma); @@ -395,5 +396,25 @@ void CBattleCallback::battleMakeTacticAction( const BattleAction & action ) std::optional CBattleCallback::makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState) { - return cl->playerint[getPlayerID().value()]->makeSurrenderRetreatDecision(battleID< battleState); + return cl->playerint[getPlayerID().value()]->makeSurrenderRetreatDecision(battleID, battleState); +} + +std::shared_ptr CBattleCallback::getBattle(const BattleID & battleID) +{ + return activeBattles.at(battleID); +} + +std::optional CBattleCallback::getPlayerID() const +{ + return player; +} + +void CBattleCallback::onBattleStarted(const IBattleInfo * info) +{ + activeBattles[info->getBattleID()] = std::make_shared(info, *getPlayerID()); +} + +void CBattleCallback::onBattleEnded(const BattleID & battleID) +{ + activeBattles.erase(battleID); } diff --git a/CCallback.h b/CCallback.h index 95b3f4493..33d0c8b99 100644 --- a/CCallback.h +++ b/CCallback.h @@ -59,6 +59,7 @@ public: virtual std::optional makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState) = 0; virtual std::shared_ptr getBattle(const BattleID & battleID) = 0; + virtual std::optional getPlayerID() const = 0; }; class IGameActionCallback @@ -114,20 +115,23 @@ class CBattleCallback : public IBattleCallback { std::map> activeBattles; + std::optional player; + protected: int sendRequest(const CPackForServer * request); //returns requestID (that'll be matched to requestID in PackageApplied) CClient *cl; public: - CBattleCallback(std::optional Player, CClient * C); + CBattleCallback(std::optional player, CClient * C); void battleMakeSpellAction(const BattleID & battleID, const BattleAction & action) override;//for casting spells by hero - DO NOT use it for moving active stack void battleMakeUnitAction(const BattleID & battleID, const BattleAction & action) override; void battleMakeTacticAction(const BattleID & battleID, const BattleAction & action) override; // performs tactic phase actions std::optional makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState) override; std::shared_ptr getBattle(const BattleID & battleID) override; + std::optional getPlayerID() const override; - void onBattleStarted(const BattleID & battleID); + void onBattleStarted(const IBattleInfo * info); void onBattleEnded(const BattleID & battleID); #if SCRIPTING_ENABLED @@ -145,9 +149,11 @@ public: virtual ~CCallback(); //client-specific functionalities (pathfinding) - virtual bool canMoveBetween(const int3 &a, const int3 &b); - virtual int3 getGuardingCreaturePosition(int3 tile); - virtual std::shared_ptr getPathsInfo(const CGHeroInstance * h); + bool canMoveBetween(const int3 &a, const int3 &b); + int3 getGuardingCreaturePosition(int3 tile); + std::shared_ptr getPathsInfo(const CGHeroInstance * h); + + std::optional getPlayerID() const override; //Set of metrhods that allows adding more interfaces for this player that'll receive game event call-ins. void registerBattleInterface(std::shared_ptr battleEvents); diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index 0866394fb..7e422d12d 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -658,7 +658,7 @@ void CPlayerInterface::buildChanged(const CGTownInstance *town, BuildingID build } } -void CPlayerInterface::battleStartBefore(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2) +void CPlayerInterface::battleStartBefore(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2) { // when battle starts, game will send battleStart pack *before* movement confirmation // and since network thread wait for battle intro to play, movement confirmation will only happen after intro @@ -670,7 +670,7 @@ void CPlayerInterface::battleStartBefore(const CCreatureSet *army1, const CCreat waitForAllDialogs(); } -void CPlayerInterface::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side, bool replayAllowed) +void CPlayerInterface::battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side, bool replayAllowed) { EVENT_HANDLER_CALLED_BY_CLIENT; @@ -685,7 +685,7 @@ void CPlayerInterface::battleStart(const CCreatureSet *army1, const CCreatureSet autocombatPreferences.enableSpellsUsage = settings["battle"]["enableAutocombatSpells"].Bool(); autofightingAI->initBattleInterface(env, cb, autocombatPreferences); - autofightingAI->battleStart(army1, army2, tile, hero1, hero2, side, false); + autofightingAI->battleStart(battleID, army1, army2, tile, hero1, hero2, side, false); isAutoFightOn = true; cb->registerBattleInterface(autofightingAI); } @@ -697,7 +697,7 @@ void CPlayerInterface::battleStart(const CCreatureSet *army1, const CCreatureSet BATTLE_EVENT_POSSIBLE_RETURN; } -void CPlayerInterface::battleUnitsChanged(const std::vector & units) +void CPlayerInterface::battleUnitsChanged(const BattleID & battleID, const std::vector & units) { EVENT_HANDLER_CALLED_BY_CLIENT; BATTLE_EVENT_POSSIBLE_RETURN; @@ -708,7 +708,7 @@ void CPlayerInterface::battleUnitsChanged(const std::vector & units { case UnitChanges::EOperation::RESET_STATE: { - const CStack * stack = cb->battleGetStackByID(info.id ); + const CStack * stack = cb->getBattle(battleID)->battleGetStackByID(info.id ); if(!stack) { @@ -723,7 +723,7 @@ void CPlayerInterface::battleUnitsChanged(const std::vector & units break; case UnitChanges::EOperation::ADD: { - const CStack * unit = cb->battleGetStackByID(info.id); + const CStack * unit = cb->getBattle(battleID)->battleGetStackByID(info.id); if(!unit) { logGlobal->error("Invalid unit ID %d", info.id); @@ -739,7 +739,7 @@ void CPlayerInterface::battleUnitsChanged(const std::vector & units } } -void CPlayerInterface::battleObstaclesChanged(const std::vector & obstacles) +void CPlayerInterface::battleObstaclesChanged(const BattleID & battleID, const std::vector & obstacles) { EVENT_HANDLER_CALLED_BY_CLIENT; BATTLE_EVENT_POSSIBLE_RETURN; @@ -751,7 +751,7 @@ void CPlayerInterface::battleObstaclesChanged(const std::vector { if(change.operation == BattleChanges::EOperation::ADD) { - auto instance = cb->battleGetObstacleByID(change.id); + auto instance = cb->getBattle(battleID)->battleGetObstacleByID(change.id); if(instance) newObstacles.push_back(instance); else @@ -770,7 +770,7 @@ void CPlayerInterface::battleObstaclesChanged(const std::vector battleInt->fieldController->redrawBackgroundWithHexes(); } -void CPlayerInterface::battleCatapultAttacked(const CatapultAttack & ca) +void CPlayerInterface::battleCatapultAttacked(const BattleID & battleID, const CatapultAttack & ca) { EVENT_HANDLER_CALLED_BY_CLIENT; BATTLE_EVENT_POSSIBLE_RETURN; @@ -778,15 +778,15 @@ void CPlayerInterface::battleCatapultAttacked(const CatapultAttack & ca) battleInt->stackIsCatapulting(ca); } -void CPlayerInterface::battleNewRound(int round) //called at the beginning of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn +void CPlayerInterface::battleNewRound(const BattleID & battleID) //called at the beginning of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn { EVENT_HANDLER_CALLED_BY_CLIENT; BATTLE_EVENT_POSSIBLE_RETURN; - battleInt->newRound(round); + battleInt->newRound(); } -void CPlayerInterface::actionStarted(const BattleAction &action) +void CPlayerInterface::actionStarted(const BattleID & battleID, const BattleAction &action) { EVENT_HANDLER_CALLED_BY_CLIENT; BATTLE_EVENT_POSSIBLE_RETURN; @@ -794,7 +794,7 @@ void CPlayerInterface::actionStarted(const BattleAction &action) battleInt->startAction(action); } -void CPlayerInterface::actionFinished(const BattleAction &action) +void CPlayerInterface::actionFinished(const BattleID & battleID, const BattleAction &action) { EVENT_HANDLER_CALLED_BY_CLIENT; BATTLE_EVENT_POSSIBLE_RETURN; @@ -802,17 +802,17 @@ void CPlayerInterface::actionFinished(const BattleAction &action) battleInt->endAction(action); } -void CPlayerInterface::activeStack(const CStack * stack) //called when it's turn of that stack +void CPlayerInterface::activeStack(const BattleID & battleID, const CStack * stack) //called when it's turn of that stack { EVENT_HANDLER_CALLED_BY_CLIENT; logGlobal->trace("Awaiting command for %s", stack->nodeName()); - assert(!cb->battleIsFinished()); - if (cb->battleIsFinished()) + assert(!cb->getBattle(battleID)->battleIsFinished()); + if (cb->getBattle(battleID)->battleIsFinished()) { logGlobal->error("Received CPlayerInterface::activeStack after battle is finished!"); - cb->battleMakeUnitAction(BattleAction::makeDefend(stack)); + cb->battleMakeUnitAction(battleID, BattleAction::makeDefend(stack)); return ; } @@ -823,7 +823,7 @@ void CPlayerInterface::activeStack(const CStack * stack) //called when it's turn //FIXME: we want client rendering to proceed while AI is making actions // so unlock mutex while AI is busy since this might take quite a while, especially if hero has many spells auto unlockPim = vstd::makeUnlockGuard(*pim); - autofightingAI->activeStack(stack); + autofightingAI->activeStack(battleID, stack); return; } @@ -835,7 +835,7 @@ void CPlayerInterface::activeStack(const CStack * stack) //called when it's turn if(!battleInt) { // probably battle is finished already - cb->battleMakeUnitAction(BattleAction::makeDefend(stack)); + cb->battleMakeUnitAction(battleID, BattleAction::makeDefend(stack)); } { @@ -845,7 +845,7 @@ void CPlayerInterface::activeStack(const CStack * stack) //called when it's turn } } -void CPlayerInterface::battleEnd(const BattleResult *br, QueryID queryID) +void CPlayerInterface::battleEnd(const BattleID & battleID, const BattleResult *br, QueryID queryID) { EVENT_HANDLER_CALLED_BY_CLIENT; if(isAutoFightOn || autofightingAI) @@ -880,7 +880,7 @@ void CPlayerInterface::battleEnd(const BattleResult *br, QueryID queryID) battleInt->battleFinished(*br, queryID); } -void CPlayerInterface::battleLogMessage(const std::vector & lines) +void CPlayerInterface::battleLogMessage(const BattleID & battleID, const std::vector & lines) { EVENT_HANDLER_CALLED_BY_CLIENT; BATTLE_EVENT_POSSIBLE_RETURN; @@ -888,28 +888,28 @@ void CPlayerInterface::battleLogMessage(const std::vector & lines) battleInt->displayBattleLog(lines); } -void CPlayerInterface::battleStackMoved(const CStack * stack, std::vector dest, int distance, bool teleport) +void CPlayerInterface::battleStackMoved(const BattleID & battleID, const CStack * stack, std::vector dest, int distance, bool teleport) { EVENT_HANDLER_CALLED_BY_CLIENT; BATTLE_EVENT_POSSIBLE_RETURN; battleInt->stackMoved(stack, dest, distance, teleport); } -void CPlayerInterface::battleSpellCast( const BattleSpellCast *sc ) +void CPlayerInterface::battleSpellCast(const BattleID & battleID, const BattleSpellCast * sc) { EVENT_HANDLER_CALLED_BY_CLIENT; BATTLE_EVENT_POSSIBLE_RETURN; battleInt->spellCast(sc); } -void CPlayerInterface::battleStacksEffectsSet( const SetStackEffect & sse ) +void CPlayerInterface::battleStacksEffectsSet(const BattleID & battleID, const SetStackEffect & sse) { EVENT_HANDLER_CALLED_BY_CLIENT; BATTLE_EVENT_POSSIBLE_RETURN; battleInt->battleStacksEffectsSet(sse); } -void CPlayerInterface::battleTriggerEffect (const BattleTriggerEffect & bte) +void CPlayerInterface::battleTriggerEffect(const BattleID & battleID, const BattleTriggerEffect & bte) { EVENT_HANDLER_CALLED_BY_CLIENT; BATTLE_EVENT_POSSIBLE_RETURN; @@ -923,7 +923,7 @@ void CPlayerInterface::battleTriggerEffect (const BattleTriggerEffect & bte) battleInt->windowObject->heroManaPointsChanged(manaDrainedHero); } } -void CPlayerInterface::battleStacksAttacked(const std::vector & bsa, bool ranged) +void CPlayerInterface::battleStacksAttacked(const BattleID & battleID, const std::vector & bsa, bool ranged) { EVENT_HANDLER_CALLED_BY_CLIENT; BATTLE_EVENT_POSSIBLE_RETURN; @@ -931,8 +931,8 @@ void CPlayerInterface::battleStacksAttacked(const std::vector arg; for(auto & elem : bsa) { - const CStack * defender = cb->battleGetStackByID(elem.stackAttacked, false); - const CStack * attacker = cb->battleGetStackByID(elem.attackerID, false); + const CStack * defender = cb->getBattle(battleID)->battleGetStackByID(elem.stackAttacked, false); + const CStack * attacker = cb->getBattle(battleID)->battleGetStackByID(elem.attackerID, false); assert(defender); @@ -955,13 +955,13 @@ void CPlayerInterface::battleStacksAttacked(const std::vectorstacksAreAttacked(arg); } -void CPlayerInterface::battleAttack(const BattleAttack * ba) +void CPlayerInterface::battleAttack(const BattleID & battleID, const BattleAttack * ba) { EVENT_HANDLER_CALLED_BY_CLIENT; BATTLE_EVENT_POSSIBLE_RETURN; StackAttackInfo info; - info.attacker = cb->battleGetStackByID(ba->stackAttacking); + info.attacker = cb->getBattle(battleID)->battleGetStackByID(ba->stackAttacking); info.defender = nullptr; info.indirectAttack = ba->shot(); info.lucky = ba->lucky(); @@ -979,11 +979,11 @@ void CPlayerInterface::battleAttack(const BattleAttack * ba) if(!elem.isSecondary()) { assert(info.defender == nullptr); - info.defender = cb->battleGetStackByID(elem.stackAttacked); + info.defender = cb->getBattle(battleID)->battleGetStackByID(elem.stackAttacked); } else { - info.secondaryDefender.push_back(cb->battleGetStackByID(elem.stackAttacked)); + info.secondaryDefender.push_back(cb->getBattle(battleID)->battleGetStackByID(elem.stackAttacked)); } } assert(info.defender != nullptr); @@ -992,7 +992,7 @@ void CPlayerInterface::battleAttack(const BattleAttack * ba) battleInt->stackAttacking(info); } -void CPlayerInterface::battleGateStateChanged(const EGateState state) +void CPlayerInterface::battleGateStateChanged(const BattleID & battleID, const EGateState state) { EVENT_HANDLER_CALLED_BY_CLIENT; BATTLE_EVENT_POSSIBLE_RETURN; @@ -1705,12 +1705,12 @@ void CPlayerInterface::tryDigging(const CGHeroInstance * h) showInfoDialog(CGI->generaltexth->allTexts[msgToShow]); } -void CPlayerInterface::battleNewRoundFirst( int round ) +void CPlayerInterface::battleNewRoundFirst(const BattleID & battleID) { EVENT_HANDLER_CALLED_BY_CLIENT; BATTLE_EVENT_POSSIBLE_RETURN; - battleInt->newRoundFirst(round); + battleInt->newRoundFirst(); } void CPlayerInterface::stopMovement() diff --git a/client/CPlayerInterface.h b/client/CPlayerInterface.h index 4a74fd8d2..5319d5c63 100644 --- a/client/CPlayerInterface.h +++ b/client/CPlayerInterface.h @@ -152,25 +152,25 @@ protected: // Call-ins from server, should not be called directly, but only via void showWorldViewEx(const std::vector & objectPositions, bool showTerrain) override; //for battles - void actionFinished(const BattleAction& action) override;//occurs AFTER action taken by active stack or by the hero - void actionStarted(const BattleAction& action) override;//occurs BEFORE action taken by active stack or by the hero - void activeStack(const CStack * stack) override; //called when it's turn of that stack - void battleAttack(const BattleAttack *ba) override; //stack performs attack - void battleEnd(const BattleResult *br, QueryID queryID) override; //end of battle - void battleNewRoundFirst(int round) override; //called at the beginning of each turn before changes are applied; used for HP regen handling - void battleNewRound(int round) override; //called at the beginning of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn - void battleLogMessage(const std::vector & lines) override; - void battleStackMoved(const CStack * stack, std::vector dest, int distance, bool teleport) override; - void battleSpellCast(const BattleSpellCast *sc) override; - void battleStacksEffectsSet(const SetStackEffect & sse) override; //called when a specific effect is set to stacks - void battleTriggerEffect(const BattleTriggerEffect & bte) override; //various one-shot effect - void battleStacksAttacked(const std::vector & bsa, bool ranged) override; - void battleStartBefore(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2) override; //called by engine just before battle starts; side=0 - left, side=1 - right - void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side, bool replayAllowed) override; //called by engine when battle starts; side=0 - left, side=1 - right - void battleUnitsChanged(const std::vector & units) override; - void battleObstaclesChanged(const std::vector & obstacles) override; - void battleCatapultAttacked(const CatapultAttack & ca) override; //called when catapult makes an attack - void battleGateStateChanged(const EGateState state) override; + void actionFinished(const BattleID & battleID, const BattleAction& action) override;//occurs AFTER action taken by active stack or by the hero + void actionStarted(const BattleID & battleID, const BattleAction& action) override;//occurs BEFORE action taken by active stack or by the hero + void activeStack(const BattleID & battleID, const CStack * stack) override; //called when it's turn of that stack + void battleAttack(const BattleID & battleID, const BattleAttack *ba) override; //stack performs attack + void battleEnd(const BattleID & battleID, const BattleResult *br, QueryID queryID) override; //end of battle + void battleNewRoundFirst(const BattleID & battleID) override; //called at the beginning of each turn before changes are applied; used for HP regen handling + void battleNewRound(const BattleID & battleID) override; //called at the beginning of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn + void battleLogMessage(const BattleID & battleID, const std::vector & lines) override; + void battleStackMoved(const BattleID & battleID, const CStack * stack, std::vector dest, int distance, bool teleport) override; + void battleSpellCast(const BattleID & battleID, const BattleSpellCast *sc) override; + void battleStacksEffectsSet(const BattleID & battleID, const SetStackEffect & sse) override; //called when a specific effect is set to stacks + void battleTriggerEffect(const BattleID & battleID, const BattleTriggerEffect & bte) override; //various one-shot effect + void battleStacksAttacked(const BattleID & battleID, const std::vector & bsa, bool ranged) override; + void battleStartBefore(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2) override; //called by engine just before battle starts; side=0 - left, side=1 - right + void battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side, bool replayAllowed) override; //called by engine when battle starts; side=0 - left, side=1 - right + void battleUnitsChanged(const BattleID & battleID, const std::vector & units) override; + void battleObstaclesChanged(const BattleID & battleID, const std::vector & obstacles) override; + void battleCatapultAttacked(const BattleID & battleID, const CatapultAttack & ca) override; //called when catapult makes an attack + void battleGateStateChanged(const BattleID & battleID, const EGateState state) override; void yourTacticPhase(const BattleID & battleID, int distance) override; std::optional makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState) override; diff --git a/client/Client.cpp b/client/Client.cpp index 44652aeb7..96a8a8173 100644 --- a/client/Client.cpp +++ b/client/Client.cpp @@ -122,9 +122,9 @@ events::EventBus * CPlayerEnvironment::eventBus() const return cl->eventBus();//always get actual value } -const CPlayerEnvironment::BattleCb * CPlayerEnvironment::battle() const +const CPlayerEnvironment::BattleCb * CPlayerEnvironment::battle(const BattleID & battleID) const { - return mainCallback.get(); + return mainCallback->getBattle(battleID).get(); } const CPlayerEnvironment::GameCb * CPlayerEnvironment::game() const @@ -153,9 +153,9 @@ const Services * CClient::services() const return VLC; //todo: this should be CGI } -const CClient::BattleCb * CClient::battle() const +const CClient::BattleCb * CClient::battle(const BattleID & battleID) const { - return this; + return nullptr; //todo? } const CClient::GameCb * CClient::game() const @@ -345,7 +345,7 @@ void CClient::serialize(BinaryDeserializer & h, const int version) void CClient::save(const std::string & fname) { - if(gs->curB) + if(!gs->currentBattles.empty()) { logNetwork->error("Game cannot be saved during battle!"); return; @@ -565,14 +565,12 @@ int CClient::sendRequest(const CPackForServer * request, PlayerColor player) void CClient::battleStarted(const BattleInfo * info) { - setBattle(info); - for(auto & battleCb : battleCallbacks) { if(vstd::contains_if(info->sides, [&](const SideInBattle& side) {return side.color == battleCb.first; }) || !battleCb.first.isValidPlayer()) { - battleCb.second->setBattle(info); + battleCb.second->onBattleStarted(info); } } @@ -583,7 +581,7 @@ void CClient::battleStarted(const BattleInfo * info) auto callBattleStart = [&](PlayerColor color, ui8 side) { if(vstd::contains(battleints, color)) - battleints[color]->battleStart(leftSide.armyObject, rightSide.armyObject, info->tile, leftSide.hero, rightSide.hero, side, info->replayAllowed); + battleints[color]->battleStart(info->battleID, leftSide.armyObject, rightSide.armyObject, info->tile, leftSide.hero, rightSide.hero, side, info->replayAllowed); }; callBattleStart(leftSide.color, 0); @@ -601,11 +599,11 @@ void CClient::battleStarted(const BattleInfo * info) //Remove player interfaces for auto battle (quickCombat option) if(att && att->isAutoFightOn) { - if (att->cb->battleGetTacticDist()) + if (att->cb->getBattle(info->battleID)->battleGetTacticDist()) { - auto side = att->cb->playerToSide(att->playerID); + auto side = att->cb->getBattle(info->battleID)->playerToSide(att->playerID); auto action = BattleAction::makeEndOFTacticPhase(*side); - att->cb->battleMakeTacticAction(action); + att->cb->battleMakeTacticAction(info->battleID, action); } att.reset(); @@ -623,7 +621,7 @@ void CClient::battleStarted(const BattleInfo * info) { //TODO: This certainly need improvement auto spectratorInt = std::dynamic_pointer_cast(playerint[PlayerColor::SPECTATOR]); - spectratorInt->cb->setBattle(info); + spectratorInt->cb->onBattleStarted(info); boost::unique_lock un(*CPlayerInterface::pim); CPlayerInterface::battleInt = std::make_shared(leftSide.armyObject, rightSide.armyObject, leftSide.hero, rightSide.hero, att, def, spectratorInt); } @@ -638,20 +636,17 @@ void CClient::battleStarted(const BattleInfo * info) } } -void CClient::battleFinished() +void CClient::battleFinished(const BattleID & battleID) { - for(auto & side : gs->curB->sides) + for(auto & side : gs->getBattle(battleID)->sides) if(battleCallbacks.count(side.color)) - battleCallbacks[side.color]->setBattle(nullptr); + battleCallbacks[side.color]->onBattleEnded(battleID); if(settings["session"]["spectate"].Bool() && !settings["session"]["spectate-skip-battle"].Bool()) - battleCallbacks[PlayerColor::SPECTATOR]->setBattle(nullptr); - - setBattle(nullptr); - gs->curB.dellNull(); + battleCallbacks[PlayerColor::SPECTATOR]->onBattleEnded(battleID); } -void CClient::startPlayerBattleAction(PlayerColor color) +void CClient::startPlayerBattleAction(const BattleID & battleID, PlayerColor color) { assert(vstd::contains(battleints, color)); @@ -661,7 +656,7 @@ void CClient::startPlayerBattleAction(PlayerColor color) auto unlock = vstd::makeUnlockGuardIf(*CPlayerInterface::pim, !battleints[color]->human); assert(vstd::contains(battleints, color)); - battleints[color]->activeStack(gs->curB->battleGetStackByID(gs->curB->activeStack, false)); + battleints[color]->activeStack(battleID, gs->getBattle(battleID)->battleGetStackByID(gs->getBattle(battleID)->activeStack, false)); } } diff --git a/client/Client.h b/client/Client.h index 48816798f..6155b9486 100644 --- a/client/Client.h +++ b/client/Client.h @@ -24,6 +24,7 @@ class CGameInterface; class BinaryDeserializer; class BinarySerializer; class BattleAction; +class BattleInfo; template class CApplier; @@ -150,8 +151,8 @@ public: int sendRequest(const CPackForServer * request, PlayerColor player); //returns ID given to that request void battleStarted(const BattleInfo * info); - void battleFinished(); - void startPlayerBattleAction(PlayerColor color); + void battleFinished(const BattleID & battleID); + void startPlayerBattleAction(const BattleID & battleID, PlayerColor color); void invalidatePaths(); std::shared_ptr getPathsInfo(const CGHeroInstance * h); diff --git a/client/NetPacksClient.cpp b/client/NetPacksClient.cpp index 3a89d8e1b..6df37a4f0 100644 --- a/client/NetPacksClient.cpp +++ b/client/NetPacksClient.cpp @@ -95,18 +95,18 @@ void callAllInterfaces(CClient & cl, void (T::*ptr)(Args...), Args2 && ...args) //calls all normal interfaces and privileged ones, playerints may be updated when iterating over it, so we need a copy template -void callBattleInterfaceIfPresentForBothSides(CClient & cl, void (T::*ptr)(Args...), Args2 && ...args) +void callBattleInterfaceIfPresentForBothSides(CClient & cl, const BattleID & battleID, void (T::*ptr)(Args...), Args2 && ...args) { - assert(cl.gameState()->curB); + assert(cl.gameState()->getBattle(battleID)); - if (!cl.gameState()->curB) + if (!cl.gameState()->getBattle(battleID)) { logGlobal->error("Attempt to call battle interface without ongoing battle!"); return; } - callOnlyThatBattleInterface(cl, cl.gameState()->curB->sides[0].color, ptr, std::forward(args)...); - callOnlyThatBattleInterface(cl, cl.gameState()->curB->sides[1].color, ptr, std::forward(args)...); + callOnlyThatBattleInterface(cl, cl.gameState()->getBattle(battleID)->sides[0].color, ptr, std::forward(args)...); + callOnlyThatBattleInterface(cl, cl.gameState()->getBattle(battleID)->sides[1].color, ptr, std::forward(args)...); if(settings["session"]["spectate"].Bool() && !settings["session"]["spectate-skip-battle"].Bool() && LOCPLINT->battleInt) { callOnlyThatBattleInterface(cl, PlayerColor::SPECTATOR, ptr, std::forward(args)...); @@ -714,11 +714,11 @@ void ApplyClientNetPackVisitor::visitMapObjectSelectDialog(MapObjectSelectDialog void ApplyFirstClientNetPackVisitor::visitBattleStart(BattleStart & pack) { // Cannot use the usual code because curB is not set yet - callOnlyThatBattleInterface(cl, pack.info->sides[0].color, &IBattleEventsReceiver::battleStartBefore, pack.info->sides[0].armyObject, pack.info->sides[1].armyObject, + callOnlyThatBattleInterface(cl, pack.info->sides[0].color, &IBattleEventsReceiver::battleStartBefore, pack.battleID, pack.info->sides[0].armyObject, pack.info->sides[1].armyObject, pack.info->tile, pack.info->sides[0].hero, pack.info->sides[1].hero); - callOnlyThatBattleInterface(cl, pack.info->sides[1].color, &IBattleEventsReceiver::battleStartBefore, pack.info->sides[0].armyObject, pack.info->sides[1].armyObject, + callOnlyThatBattleInterface(cl, pack.info->sides[1].color, &IBattleEventsReceiver::battleStartBefore, pack.battleID, pack.info->sides[0].armyObject, pack.info->sides[1].armyObject, pack.info->tile, pack.info->sides[0].hero, pack.info->sides[1].hero); - callOnlyThatBattleInterface(cl, PlayerColor::SPECTATOR, &IBattleEventsReceiver::battleStartBefore, pack.info->sides[0].armyObject, pack.info->sides[1].armyObject, + callOnlyThatBattleInterface(cl, PlayerColor::SPECTATOR, &IBattleEventsReceiver::battleStartBefore, pack.battleID, pack.info->sides[0].armyObject, pack.info->sides[1].armyObject, pack.info->tile, pack.info->sides[0].hero, pack.info->sides[1].hero); } @@ -729,12 +729,12 @@ void ApplyClientNetPackVisitor::visitBattleStart(BattleStart & pack) void ApplyFirstClientNetPackVisitor::visitBattleNextRound(BattleNextRound & pack) { - callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleNewRoundFirst, pack.round); + callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::battleNewRoundFirst, pack.battleID); } void ApplyClientNetPackVisitor::visitBattleNextRound(BattleNextRound & pack) { - callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleNewRound, pack.round); + callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::battleNewRound, pack.battleID); } void ApplyClientNetPackVisitor::visitBattleSetActiveStack(BattleSetActiveStack & pack) @@ -742,56 +742,56 @@ void ApplyClientNetPackVisitor::visitBattleSetActiveStack(BattleSetActiveStack & if(!pack.askPlayerInterface) return; - const CStack *activated = gs.curB->battleGetStackByID(pack.stack); + const CStack *activated = gs.getBattle(pack.battleID)->battleGetStackByID(pack.stack); PlayerColor playerToCall; //pack.player that will move activated stack if (activated->hasBonusOfType(BonusType::HYPNOTIZED)) { - playerToCall = (gs.curB->sides[0].color == activated->unitOwner() - ? gs.curB->sides[1].color - : gs.curB->sides[0].color); + playerToCall = (gs.getBattle(pack.battleID)->sides[0].color == activated->unitOwner() + ? gs.getBattle(pack.battleID)->sides[1].color + : gs.getBattle(pack.battleID)->sides[0].color); } else { playerToCall = activated->unitOwner(); } - cl.startPlayerBattleAction(playerToCall); + cl.startPlayerBattleAction(pack.battleID, playerToCall); } void ApplyClientNetPackVisitor::visitBattleLogMessage(BattleLogMessage & pack) { - callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleLogMessage, pack.lines); + callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::battleLogMessage, pack.battleID, pack.lines); } void ApplyClientNetPackVisitor::visitBattleTriggerEffect(BattleTriggerEffect & pack) { - callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleTriggerEffect, pack); + callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::battleTriggerEffect, pack.battleID, pack); } void ApplyFirstClientNetPackVisitor::visitBattleUpdateGateState(BattleUpdateGateState & pack) { - callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleGateStateChanged, pack.state); + callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::battleGateStateChanged, pack.battleID, pack.state); } void ApplyFirstClientNetPackVisitor::visitBattleResult(BattleResult & pack) { - callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleEnd, &pack, pack.queryID); - cl.battleFinished(); + callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::battleEnd, pack.battleID, &pack, pack.queryID); + cl.battleFinished(pack.battleID); } void ApplyFirstClientNetPackVisitor::visitBattleStackMoved(BattleStackMoved & pack) { - const CStack * movedStack = gs.curB->battleGetStackByID(pack.stack); - callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleStackMoved, movedStack, pack.tilesToMove, pack.distance, pack.teleporting); + const CStack * movedStack = gs.getBattle(pack.battleID)->battleGetStackByID(pack.stack); + callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::battleStackMoved, pack.battleID, movedStack, pack.tilesToMove, pack.distance, pack.teleporting); } void ApplyFirstClientNetPackVisitor::visitBattleAttack(BattleAttack & pack) { - callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleAttack, &pack); + callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::battleAttack, pack.battleID, &pack); // battleStacksAttacked should be excuted before BattleAttack.applyGs() to play animation before damaging unit // so this has to be here instead of ApplyClientNetPackVisitor::visitBattleAttack() - callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleStacksAttacked, pack.bsa, pack.shot()); + callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::battleStacksAttacked, pack.battleID, pack.bsa, pack.shot()); } void ApplyClientNetPackVisitor::visitBattleAttack(BattleAttack & pack) @@ -801,23 +801,23 @@ void ApplyClientNetPackVisitor::visitBattleAttack(BattleAttack & pack) void ApplyFirstClientNetPackVisitor::visitStartAction(StartAction & pack) { cl.currentBattleAction = std::make_unique(pack.ba); - callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::actionStarted, pack.ba); + callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::actionStarted, pack.battleID, pack.ba); } void ApplyClientNetPackVisitor::visitBattleSpellCast(BattleSpellCast & pack) { - callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleSpellCast, &pack); + callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::battleSpellCast, pack.battleID, &pack); } void ApplyClientNetPackVisitor::visitSetStackEffect(SetStackEffect & pack) { //informing about effects - callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleStacksEffectsSet, pack); + callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::battleStacksEffectsSet, pack.battleID, pack); } void ApplyClientNetPackVisitor::visitStacksInjured(StacksInjured & pack) { - callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleStacksAttacked, pack.stacks, false); + callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::battleStacksAttacked, pack.battleID, pack.stacks, false); } void ApplyClientNetPackVisitor::visitBattleResultsApplied(BattleResultsApplied & pack) @@ -829,24 +829,24 @@ void ApplyClientNetPackVisitor::visitBattleResultsApplied(BattleResultsApplied & void ApplyClientNetPackVisitor::visitBattleUnitsChanged(BattleUnitsChanged & pack) { - callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleUnitsChanged, pack.changedStacks); + callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::battleUnitsChanged, pack.battleID, pack.changedStacks); } void ApplyClientNetPackVisitor::visitBattleObstaclesChanged(BattleObstaclesChanged & pack) { //inform interfaces about removed obstacles - callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleObstaclesChanged, pack.changes); + callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::battleObstaclesChanged, pack.battleID, pack.changes); } void ApplyClientNetPackVisitor::visitCatapultAttack(CatapultAttack & pack) { //inform interfaces about catapult attack - callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::battleCatapultAttacked, pack); + callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::battleCatapultAttacked, pack.battleID, pack); } void ApplyClientNetPackVisitor::visitEndAction(EndAction & pack) { - callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::actionFinished, *cl.currentBattleAction); + callBattleInterfaceIfPresentForBothSides(cl, pack.battleID, &IBattleEventsReceiver::actionFinished, pack.battleID, *cl.currentBattleAction); cl.currentBattleAction.reset(); } diff --git a/client/battle/BattleActionsController.cpp b/client/battle/BattleActionsController.cpp index 55b01d2af..43eb0729b 100644 --- a/client/battle/BattleActionsController.cpp +++ b/client/battle/BattleActionsController.cpp @@ -171,7 +171,7 @@ void BattleActionsController::enterCreatureCastingMode() spells::Target target; target.emplace_back(); - spells::BattleCast cast(owner.curInt->cb.get(), caster, spells::Mode::CREATURE_ACTIVE, spell); + spells::BattleCast cast(owner.getBattle().get(), caster, spells::Mode::CREATURE_ACTIVE, spell); auto m = spell->battleMechanics(&cast); spells::detail::ProblemImpl ignored; @@ -207,7 +207,7 @@ std::vector BattleActionsController::getPossibleActi data.creatureSpellsToCast.push_back(spell->id); data.tacticsMode = owner.tacticsMode; - auto allActions = owner.curInt->cb->getClientActionsForStack(stack, data); + auto allActions = owner.getBattle()->getClientActionsForStack(stack, data); allActions.push_back(PossiblePlayerBattleAction::HERO_INFO); allActions.push_back(PossiblePlayerBattleAction::CREATURE_INFO); @@ -231,7 +231,7 @@ void BattleActionsController::reorderPossibleActionsPriority(const CStack * stac case PossiblePlayerBattleAction::OBSTACLE: if(!stack->hasBonusOfType(BonusType::NO_SPELLCAST_BY_DEFAULT) && targetStack != nullptr) { - PlayerColor stackOwner = owner.curInt->cb->battleGetOwner(targetStack); + PlayerColor stackOwner = owner.getBattle()->battleGetOwner(targetStack); bool enemyTargetingPositiveSpellcast = item.spell().toSpell()->isPositive() && stackOwner != LOCPLINT->playerID; bool friendTargetingNegativeSpellcast = item.spell().toSpell()->isNegative() && stackOwner == LOCPLINT->playerID; @@ -300,12 +300,12 @@ void BattleActionsController::castThisSpell(SpellID spellID) //choosing possible targets const CGHeroInstance *castingHero = (owner.attackingHeroInstance->tempOwner == owner.curInt->playerID) ? owner.attackingHeroInstance : owner.defendingHeroInstance; assert(castingHero); // code below assumes non-null hero - PossiblePlayerBattleAction spellSelMode = owner.curInt->cb->getCasterAction(spellID.toSpell(), castingHero, spells::Mode::HERO); + PossiblePlayerBattleAction spellSelMode = owner.getBattle()->getCasterAction(spellID.toSpell(), castingHero, spells::Mode::HERO); if (spellSelMode.get() == PossiblePlayerBattleAction::NO_LOCATION) //user does not have to select location { heroSpellToCast->aimToHex(BattleHex::INVALID); - owner.curInt->cb->battleMakeSpellAction(*heroSpellToCast); + owner.curInt->cb->battleMakeSpellAction(owner.getBattleID(), *heroSpellToCast); endCastingSpell(); } else @@ -353,10 +353,10 @@ const CSpell * BattleActionsController::getCurrentSpell(BattleHex hoveredHex) const CStack * BattleActionsController::getStackForHex(BattleHex hoveredHex) { - const CStack * shere = owner.curInt->cb->battleGetStackByPos(hoveredHex, true); + const CStack * shere = owner.getBattle()->battleGetStackByPos(hoveredHex, true); if(shere) return shere; - return owner.curInt->cb->battleGetStackByPos(hoveredHex, false); + return owner.getBattle()->battleGetStackByPos(hoveredHex, false); } void BattleActionsController::actionSetCursor(PossiblePlayerBattleAction action, BattleHex targetHex) @@ -400,7 +400,7 @@ void BattleActionsController::actionSetCursor(PossiblePlayerBattleAction action, } case PossiblePlayerBattleAction::SHOOT: - if (owner.curInt->cb->battleHasShootingPenalty(owner.stacksController->getActiveStack(), targetHex)) + if (owner.getBattle()->battleHasShootingPenalty(owner.stacksController->getActiveStack(), targetHex)) CCS->curh->set(Cursor::Combat::SHOOT_PENALTY); else CCS->curh->set(Cursor::Combat::SHOOT); @@ -482,7 +482,7 @@ std::string BattleActionsController::actionGetStatusMessage(PossiblePlayerBattle case PossiblePlayerBattleAction::ATTACK_AND_RETURN: //TODO: allow to disable return { BattleHex attackFromHex = owner.fieldController->fromWhichHexAttack(targetHex); - DamageEstimation estimation = owner.curInt->cb->battleEstimateDamage(owner.stacksController->getActiveStack(), targetStack, attackFromHex); + DamageEstimation estimation = owner.getBattle()->battleEstimateDamage(owner.stacksController->getActiveStack(), targetStack, attackFromHex); estimation.kills.max = std::min(estimation.kills.max, targetStack->getCount()); estimation.kills.min = std::min(estimation.kills.min, targetStack->getCount()); @@ -493,7 +493,7 @@ std::string BattleActionsController::actionGetStatusMessage(PossiblePlayerBattle { const auto * shooter = owner.stacksController->getActiveStack(); - DamageEstimation estimation = owner.curInt->cb->battleEstimateDamage(shooter, targetStack, shooter->getPosition()); + DamageEstimation estimation = owner.getBattle()->battleEstimateDamage(shooter, targetStack, shooter->getPosition()); estimation.kills.max = std::min(estimation.kills.max, targetStack->getCount()); estimation.kills.min = std::min(estimation.kills.min, targetStack->getCount()); @@ -593,7 +593,7 @@ bool BattleActionsController::actionIsLegal(PossiblePlayerBattleAction action, B case PossiblePlayerBattleAction::ATTACK: case PossiblePlayerBattleAction::WALK_AND_ATTACK: case PossiblePlayerBattleAction::ATTACK_AND_RETURN: - if(owner.curInt->cb->battleCanAttack(owner.stacksController->getActiveStack(), targetStack, targetHex)) + if(owner.getBattle()->battleCanAttack(owner.stacksController->getActiveStack(), targetStack, targetHex)) { if (owner.fieldController->isTileAttackable(targetHex)) // move isTileAttackable to be part of battleCanAttack? return true; @@ -601,7 +601,7 @@ bool BattleActionsController::actionIsLegal(PossiblePlayerBattleAction action, B return false; case PossiblePlayerBattleAction::SHOOT: - return owner.curInt->cb->battleCanShoot(owner.stacksController->getActiveStack(), targetHex); + return owner.getBattle()->battleCanShoot(owner.stacksController->getActiveStack(), targetHex); case PossiblePlayerBattleAction::NO_LOCATION: return false; @@ -615,7 +615,7 @@ bool BattleActionsController::actionIsLegal(PossiblePlayerBattleAction action, B case PossiblePlayerBattleAction::RANDOM_GENIE_SPELL: if(targetStack && targetStackOwned && targetStack != owner.stacksController->getActiveStack() && targetStack->alive()) //only positive spells for other allied creatures { - int spellID = owner.curInt->cb->battleGetRandomStackSpell(CRandomGenerator::getDefault(), targetStack, CBattleInfoCallback::RANDOM_GENIE); + int spellID = owner.getBattle()->battleGetRandomStackSpell(CRandomGenerator::getDefault(), targetStack, CBattleInfoCallback::RANDOM_GENIE); return spellID > -1; } return false; @@ -658,7 +658,7 @@ void BattleActionsController::actionRealize(PossiblePlayerBattleAction action, B { if(owner.stacksController->getActiveStack()->doubleWide()) { - std::vector acc = owner.curInt->cb->battleGetAvailableHexes(owner.stacksController->getActiveStack(), false); + std::vector acc = owner.getBattle()->battleGetAvailableHexes(owner.stacksController->getActiveStack(), false); BattleHex shiftedDest = targetHex.cloneInDirection(owner.stacksController->getActiveStack()->destShiftDir(), false); if(vstd::contains(acc, targetHex)) owner.giveCommand(EActionType::WALK, targetHex); @@ -770,7 +770,7 @@ void BattleActionsController::actionRealize(PossiblePlayerBattleAction action, B heroSpellToCast->aimToHex(targetHex); break; } - owner.curInt->cb->battleMakeSpellAction(*heroSpellToCast); + owner.curInt->cb->battleMakeSpellAction(owner.getBattleID(), *heroSpellToCast); endCastingSpell(); } selectedStack = nullptr; @@ -886,7 +886,7 @@ void BattleActionsController::tryActivateStackSpellcasting(const CStack *casterS { // faerie dragon can cast only one, randomly selected spell until their next move //TODO: faerie dragon type spell should be selected by server - const auto * spellToCast = owner.curInt->cb->battleGetRandomStackSpell(CRandomGenerator::getDefault(), casterStack, CBattleInfoCallback::RANDOM_AIMED).toSpell(); + const auto * spellToCast = owner.getBattle()->battleGetRandomStackSpell(CRandomGenerator::getDefault(), casterStack, CBattleInfoCallback::RANDOM_AIMED).toSpell(); if (spellToCast) creatureSpells.push_back(spellToCast); @@ -933,7 +933,7 @@ bool BattleActionsController::isCastingPossibleHere(const CSpell * currentSpell, target.emplace_back(targetStack); target.emplace_back(targetHex); - spells::BattleCast cast(owner.curInt->cb.get(), caster, mode, currentSpell); + spells::BattleCast cast(owner.getBattle().get(), caster, mode, currentSpell); auto m = currentSpell->battleMechanics(&cast); spells::detail::ProblemImpl problem; //todo: display problem in status bar @@ -943,7 +943,7 @@ bool BattleActionsController::isCastingPossibleHere(const CSpell * currentSpell, bool BattleActionsController::canStackMoveHere(const CStack * stackToMove, BattleHex myNumber) const { - std::vector acc = owner.curInt->cb->battleGetAvailableHexes(stackToMove, false); + std::vector acc = owner.getBattle()->battleGetAvailableHexes(stackToMove, false); BattleHex shiftedDest = myNumber.cloneInDirection(stackToMove->destShiftDir(), false); if (vstd::contains(acc, myNumber)) @@ -1006,7 +1006,7 @@ void BattleActionsController::onHexRightClicked(BattleHex clickedHex) return; } - auto selectedStack = owner.curInt->cb->battleGetStackByPos(clickedHex, true); + auto selectedStack = owner.getBattle()->battleGetStackByPos(clickedHex, true); if (selectedStack != nullptr) GH.windows().createAndPushWindow(selectedStack, true); diff --git a/client/battle/BattleAnimationClasses.cpp b/client/battle/BattleAnimationClasses.cpp index 3a89b0661..fa24a13a4 100644 --- a/client/battle/BattleAnimationClasses.cpp +++ b/client/battle/BattleAnimationClasses.cpp @@ -970,7 +970,7 @@ bool EffectAnimation::init() } else { - const auto * destStack = owner.getCurrentPlayerInterface()->cb->battleGetUnitByPos(battlehexes[i], false); + const auto * destStack = owner.getBattle()->battleGetUnitByPos(battlehexes[i], false); Rect tilePos = owner.fieldController->hexPositionLocal(battlehexes[i]); be.pos.x = tilePos.x + tilePos.w/2 - first->width()/2; diff --git a/client/battle/BattleEffectsController.cpp b/client/battle/BattleEffectsController.cpp index bdaba92af..66ed2e52b 100644 --- a/client/battle/BattleEffectsController.cpp +++ b/client/battle/BattleEffectsController.cpp @@ -59,7 +59,7 @@ void BattleEffectsController::battleTriggerEffect(const BattleTriggerEffect & bt { owner.checkForAnimations(); - const CStack * stack = owner.curInt->cb->battleGetStackByID(bte.stackID); + const CStack * stack = owner.getBattle()->battleGetStackByID(bte.stackID); if(!stack) { logGlobal->error("Invalid stack ID %d", bte.stackID); @@ -98,7 +98,7 @@ void BattleEffectsController::startAction(const BattleAction & action) { owner.checkForAnimations(); - const CStack *stack = owner.curInt->cb->battleGetStackByID(action.stackNumber); + const CStack *stack = owner.getBattle()->battleGetStackByID(action.stackNumber); switch(action.actionType) { diff --git a/client/battle/BattleFieldController.cpp b/client/battle/BattleFieldController.cpp index 8eda33038..e85a18ad9 100644 --- a/client/battle/BattleFieldController.cpp +++ b/client/battle/BattleFieldController.cpp @@ -141,7 +141,7 @@ BattleFieldController::BattleFieldController(BattleInterface & owner): if(!owner.siegeController) { - auto bfieldType = owner.curInt->cb->battleGetBattlefieldType(); + auto bfieldType = owner.getBattle()->battleGetBattlefieldType(); if(bfieldType == BattleField::NONE) logGlobal->error("Invalid battlefield returned for current battle"); @@ -284,7 +284,7 @@ void BattleFieldController::redrawBackgroundWithHexes() const CStack *activeStack = owner.stacksController->getActiveStack(); std::vector attackableHexes; if(activeStack) - occupiableHexes = owner.curInt->cb->battleGetAvailableHexes(activeStack, false, true, &attackableHexes); + occupiableHexes = owner.getBattle()->battleGetAvailableHexes(activeStack, false, true, &attackableHexes); // prepare background graphic with hexes and shaded hexes backgroundWithHexes->draw(background, Point(0,0)); @@ -339,7 +339,7 @@ std::set BattleFieldController::getHighlightedHexesForActiveStack() auto hoveredHex = getHoveredHex(); - std::set set = owner.curInt->cb->battleGetAttackedHexes(owner.stacksController->getActiveStack(), hoveredHex); + std::set set = owner.getBattle()->battleGetAttackedHexes(owner.stacksController->getActiveStack(), hoveredHex); for(BattleHex hex : set) result.insert(hex); @@ -359,10 +359,10 @@ std::set BattleFieldController::getMovementRangeForHoveredStack() auto hoveredHex = getHoveredHex(); // add possible movement hexes for stack under mouse - const CStack * const hoveredStack = owner.curInt->cb->battleGetStackByPos(hoveredHex, true); + const CStack * const hoveredStack = owner.getBattle()->battleGetStackByPos(hoveredHex, true); if(hoveredStack) { - std::vector v = owner.curInt->cb->battleGetAvailableHexes(hoveredStack, true, true, nullptr); + std::vector v = owner.getBattle()->battleGetAvailableHexes(hoveredStack, true, true, nullptr); for(BattleHex hex : v) result.insert(hex); } @@ -387,7 +387,7 @@ std::set BattleFieldController::getHighlightedHexesForSpellRange() if(caster && spell) //when casting spell { // printing shaded hex(es) - spells::BattleCast event(owner.curInt->cb.get(), caster, mode, spell); + spells::BattleCast event(owner.getBattle().get(), caster, mode, spell); auto shadedHexes = spell->battleMechanics(&event)->rangeInHexes(hoveredHex); for(BattleHex shadedHex : shadedHexes) @@ -407,10 +407,10 @@ std::set BattleFieldController::getHighlightedHexesForMovementTarget( if(!stack) return {}; - std::vector availableHexes = owner.curInt->cb->battleGetAvailableHexes(stack, false, false, nullptr); + std::vector availableHexes = owner.getBattle()->battleGetAvailableHexes(stack, false, false, nullptr); - auto hoveredStack = owner.curInt->cb->battleGetStackByPos(hoveredHex, true); - if(owner.curInt->cb->battleCanAttack(stack, hoveredStack, hoveredHex)) + auto hoveredStack = owner.getBattle()->battleGetStackByPos(hoveredHex, true); + if(owner.getBattle()->battleCanAttack(stack, hoveredStack, hoveredHex)) { if(isTileAttackable(hoveredHex)) { @@ -670,7 +670,7 @@ BattleHex BattleFieldController::getHoveredHex() const CStack* BattleFieldController::getHoveredStack() { auto hoveredHex = getHoveredHex(); - const CStack* hoveredStack = owner.curInt->cb->battleGetStackByPos(hoveredHex, true); + const CStack* hoveredStack = owner.getBattle()->battleGetStackByPos(hoveredHex, true); return hoveredStack; } @@ -856,7 +856,7 @@ bool BattleFieldController::isTileAttackable(const BattleHex & number) const void BattleFieldController::updateAccessibleHexes() { - auto accessibility = owner.curInt->cb->getAccesibility(); + auto accessibility = owner.getBattle()->getAccesibility(); for(int i = 0; i < accessibility.size(); i++) stackCountOutsideHexes[i] = (accessibility[i] == EAccessibility::ACCESSIBLE || (accessibility[i] == EAccessibility::SIDE_COLUMN)); diff --git a/client/battle/BattleInterface.cpp b/client/battle/BattleInterface.cpp index 2cd96c9d9..b857e565e 100644 --- a/client/battle/BattleInterface.cpp +++ b/client/battle/BattleInterface.cpp @@ -68,9 +68,9 @@ BattleInterface::BattleInterface(const CCreatureSet *army1, const CCreatureSet * } //hot-seat -> check tactics for both players (defender may be local human) - if(attackerInt && attackerInt->cb->battleGetTacticDist()) + if(attackerInt && attackerInt->cb->getBattle(getBattleID())->battleGetTacticDist()) tacticianInterface = attackerInt; - else if(defenderInt && defenderInt->cb->battleGetTacticDist()) + else if(defenderInt && defenderInt->cb->getBattle(getBattleID())->battleGetTacticDist()) tacticianInterface = defenderInt; //if we found interface of player with tactics, then enter tactics mode @@ -80,7 +80,7 @@ BattleInterface::BattleInterface(const CCreatureSet *army1, const CCreatureSet * this->army1 = army1; this->army2 = army2; - const CGTownInstance *town = curInt->cb->battleGetDefendedTown(); + const CGTownInstance *town = getBattle()->battleGetDefendedTown(); if(town && town->hasFort()) siegeController.reset(new BattleSiegeController(*this, town)); @@ -223,12 +223,12 @@ void BattleInterface::stackAttacking( const StackAttackInfo & attackInfo ) stacksController->stackAttacking(attackInfo); } -void BattleInterface::newRoundFirst( int round ) +void BattleInterface::newRoundFirst() { waitForAnimations(); } -void BattleInterface::newRound(int number) +void BattleInterface::newRound() { console->addText(CGI->generaltexth->allTexts[412]); } @@ -241,7 +241,7 @@ void BattleInterface::giveCommand(EActionType action, BattleHex tile, SpellID sp actor = stacksController->getActiveStack(); } - auto side = curInt->cb->playerToSide(curInt->playerID); + auto side = getBattle()->playerToSide(curInt->playerID); if(!side) { logGlobal->error("Player %s is not in battle", curInt->playerID.toString()); @@ -265,11 +265,11 @@ void BattleInterface::sendCommand(BattleAction command, const CStack * actor) { logGlobal->trace("Setting command for %s", (actor ? actor->nodeName() : "hero")); stacksController->setActiveStack(nullptr); - curInt->cb->battleMakeUnitAction(command); + curInt->cb->battleMakeUnitAction(battleID, command); } else { - curInt->cb->battleMakeTacticAction(command); + curInt->cb->battleMakeTacticAction(battleID, command); stacksController->setActiveStack(nullptr); //next stack will be activated when action ends } @@ -368,13 +368,13 @@ void BattleInterface::spellCast(const BattleSpellCast * sc) if ( sc->activeCast ) { - const CStack * casterStack = curInt->cb->battleGetStackByID(sc->casterStack); + const CStack * casterStack = getBattle()->battleGetStackByID(sc->casterStack); if(casterStack != nullptr ) { addToAnimationStage(EAnimationEvents::BEFORE_HIT, [=]() { - stacksController->addNewAnim(new CastAnimation(*this, casterStack, targetedTile, curInt->cb->battleGetStackByPos(targetedTile), spell)); + stacksController->addNewAnim(new CastAnimation(*this, casterStack, targetedTile, getBattle()->battleGetStackByPos(targetedTile), spell)); displaySpellCast(spell, casterStack->getPosition()); }); } @@ -385,7 +385,7 @@ void BattleInterface::spellCast(const BattleSpellCast * sc) addToAnimationStage(EAnimationEvents::BEFORE_HIT, [=]() { - stacksController->addNewAnim(new HeroCastAnimation(*this, hero, targetedTile, curInt->cb->battleGetStackByPos(targetedTile), spell)); + stacksController->addNewAnim(new HeroCastAnimation(*this, hero, targetedTile, getBattle()->battleGetStackByPos(targetedTile), spell)); }); } } @@ -397,7 +397,7 @@ void BattleInterface::spellCast(const BattleSpellCast * sc) //queuing affect animation for(auto & elem : sc->affectedCres) { - auto stack = curInt->cb->battleGetStackByID(elem, false); + auto stack = getBattle()->battleGetStackByID(elem, false); assert(stack); if(stack) { @@ -409,7 +409,7 @@ void BattleInterface::spellCast(const BattleSpellCast * sc) for(auto & elem : sc->reflectedCres) { - auto stack = curInt->cb->battleGetStackByID(elem, false); + auto stack = getBattle()->battleGetStackByID(elem, false); assert(stack); addToAnimationStage(EAnimationEvents::HIT, [=](){ effectsController->displayEffect(EBattleEffect::MAGIC_MIRROR, stack->getPosition()); @@ -425,7 +425,7 @@ void BattleInterface::spellCast(const BattleSpellCast * sc) for(auto & elem : sc->resistedCres) { - auto stack = curInt->cb->battleGetStackByID(elem, false); + auto stack = getBattle()->battleGetStackByID(elem, false); assert(stack); addToAnimationStage(EAnimationEvents::HIT, [=](){ effectsController->displayEffect(EBattleEffect::RESISTANCE, stack->getPosition()); @@ -487,7 +487,7 @@ void BattleInterface::displaySpellAnimationQueue(const CSpell * spell, const CSp if (!animation.effectName.empty()) { - const CStack * destStack = getCurrentPlayerInterface()->cb->battleGetStackByPos(destinationTile, false); + const CStack * destStack = getBattle()->battleGetStackByPos(destinationTile, false); if (destStack) stacksController->addNewAnim(new ColorTransformAnimation(*this, destStack, animation.effectName, spell )); @@ -566,12 +566,22 @@ bool BattleInterface::makingTurn() const return stacksController->getActiveStack() != nullptr; } +BattleID BattleInterface::getBattleID() const +{ + return battleID; +} + +std::shared_ptr BattleInterface::getBattle() const +{ + return curInt->cb->getBattle(battleID); +} + void BattleInterface::endAction(const BattleAction &action) { // it is possible that tactics mode ended while opening music is still playing waitForAnimations(); - const CStack *stack = curInt->cb->battleGetStackByID(action.stackNumber); + const CStack *stack = getBattle()->battleGetStackByID(action.stackNumber); // Activate stack from stackToActivate because this might have been temporary disabled, e.g., during spell cast activateStack(); @@ -606,7 +616,7 @@ void BattleInterface::startAction(const BattleAction & action) if (!action.isUnitAction()) return; - assert(curInt->cb->battleGetStackByID(action.stackNumber)); + assert(getBattle()->battleGetStackByID(action.stackNumber)); windowObject->updateQueue(); effectsController->startAction(action); } @@ -616,10 +626,10 @@ void BattleInterface::tacticPhaseEnd() stacksController->setActiveStack(nullptr); tacticsMode = false; - auto side = tacticianInterface->cb->playerToSide(tacticianInterface->playerID); + auto side = tacticianInterface->cb->getBattle(battleID)->playerToSide(tacticianInterface->playerID); auto action = BattleAction::makeEndOFTacticPhase(*side); - tacticianInterface->cb->battleMakeTacticAction(action); + tacticianInterface->cb->battleMakeTacticAction(battleID, action); } static bool immobile(const CStack *s) @@ -635,7 +645,7 @@ void BattleInterface::tacticNextStack(const CStack * current) //no switching stacks when the current one is moving checkForAnimations(); - TStacks stacksOfMine = tacticianInterface->cb->battleGetStacks(CBattleCallback::ONLY_MINE); + TStacks stacksOfMine = tacticianInterface->cb->getBattle(battleID)->battleGetStacks(CPlayerBattleCallback::ONLY_MINE); vstd::erase_if (stacksOfMine, &immobile); if (stacksOfMine.empty()) { @@ -687,7 +697,7 @@ void BattleInterface::requestAutofightingAIToTakeAction() { assert(curInt->isAutoFightOn); - if(curInt->cb->battleIsFinished()) + if(getBattle()->battleIsFinished()) { return; // battle finished with spellcast } @@ -716,7 +726,7 @@ void BattleInterface::requestAutofightingAIToTakeAction() boost::thread aiThread([this, activeStack]() { setThreadName("autofightingAI"); - curInt->autofightingAI->activeStack(activeStack); + curInt->autofightingAI->activeStack(battleID, activeStack); }); aiThread.detach(); } diff --git a/client/battle/BattleInterface.h b/client/battle/BattleInterface.h index 4124c5f47..8ca2e8015 100644 --- a/client/battle/BattleInterface.h +++ b/client/battle/BattleInterface.h @@ -30,6 +30,7 @@ struct BattleTriggerEffect; struct BattleHex; struct InfoAboutHero; class ObstacleChanges; +class CPlayerBattleCallback; VCMI_LIB_NAMESPACE_END @@ -115,6 +116,9 @@ class BattleInterface /// if set to true, battle is still starting and waiting for intro sound to end / key press from player bool battleOpeningDelayActive; + /// ID of ongoing battle + BattleID battleID; + void playIntroSoundAndUnlockInterface(); void onIntroSoundPlayed(); public: @@ -149,6 +153,9 @@ public: bool makingTurn() const; + BattleID getBattleID() const; + std::shared_ptr getBattle() const; + BattleInterface(const CCreatureSet *army1, const CCreatureSet *army2, const CGHeroInstance *hero1, const CGHeroInstance *hero2, std::shared_ptr att, std::shared_ptr defen, std::shared_ptr spectatorInt = nullptr); ~BattleInterface(); @@ -196,8 +203,8 @@ public: void stackMoved(const CStack *stack, std::vector destHex, int distance, bool teleport); //stack with id number moved to destHex void stacksAreAttacked(std::vector attackedInfos); //called when a certain amount of stacks has been attacked void stackAttacking(const StackAttackInfo & attackInfo); //called when stack with id ID is attacking something on hex dest - void newRoundFirst( int round ); - void newRound(int number); //caled when round is ended; number is the number of round + void newRoundFirst(); + void newRound(); //caled when round is ended; void stackIsCatapulting(const CatapultAttack & ca); //called when a stack is attacking walls void battleFinished(const BattleResult& br, QueryID queryID); //called when battle is finished - battleresult window should be printed void spellCast(const BattleSpellCast *sc); //called when a hero casts a spell diff --git a/client/battle/BattleInterfaceClasses.cpp b/client/battle/BattleInterfaceClasses.cpp index 94ea31b38..81c22b91d 100644 --- a/client/battle/BattleInterfaceClasses.cpp +++ b/client/battle/BattleInterfaceClasses.cpp @@ -289,7 +289,7 @@ void BattleHero::heroLeftClicked() if(!hero || !owner.makingTurn()) return; - if(owner.getCurrentPlayerInterface()->cb->battleCanCastSpell(hero, spells::Mode::HERO) == ESpellCastProblem::OK) //check conditions + if(owner.getBattle()->battleCanCastSpell(hero, spells::Mode::HERO) == ESpellCastProblem::OK) //check conditions { CCS->curh->set(Cursor::Map::POINTER); GH.windows().createAndPushWindow(hero, owner.getCurrentPlayerInterface()); @@ -502,7 +502,7 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface for(int i = 0; i < 2; i++) { - auto heroInfo = owner.cb->battleGetHeroInfo(i); + auto heroInfo = owner.cb->getBattle(br.battleID)->battleGetHeroInfo(i); const int xs[] = {21, 392}; if(heroInfo.portrait >= 0) //attacking hero @@ -512,7 +512,7 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface } else { - auto stacks = owner.cb->battleGetAllStacks(); + auto stacks = owner.cb->getBattle(br.battleID)->battleGetAllStacks(); vstd::erase_if(stacks, [i](const CStack * stack) //erase stack of other side and not coming from garrison { return stack->unitSide() != i || !stack->base; @@ -561,7 +561,7 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface } } //printing result description - bool weAreAttacker = !(owner.cb->battleGetMySide()); + bool weAreAttacker = !(owner.cb->getBattle(br.battleID)->battleGetMySide()); if((br.winner == 0 && weAreAttacker) || (br.winner == 1 && !weAreAttacker)) //we've won { int text = 304; @@ -584,7 +584,7 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface CCS->videoh->open("WIN3.BIK"); std::string str = CGI->generaltexth->allTexts[text]; - const CGHeroInstance * ourHero = owner.cb->battleGetMyHero(); + const CGHeroInstance * ourHero = owner.cb->getBattle(br.battleID)->battleGetMyHero(); if (ourHero) { str += CGI->generaltexth->allTexts[305]; @@ -714,7 +714,7 @@ void StackQueue::update() { std::vector queueData; - owner.getCurrentPlayerInterface()->cb->battleGetTurnOrder(queueData, stackBoxes.size(), 0); + owner.getBattle()->battleGetTurnOrder(queueData, stackBoxes.size(), 0); size_t boxIndex = 0; diff --git a/client/battle/BattleObstacleController.cpp b/client/battle/BattleObstacleController.cpp index d41b09a66..2c2cca455 100644 --- a/client/battle/BattleObstacleController.cpp +++ b/client/battle/BattleObstacleController.cpp @@ -31,7 +31,7 @@ BattleObstacleController::BattleObstacleController(BattleInterface & owner): owner(owner), timePassed(0.f) { - auto obst = owner.curInt->cb->battleGetAllObstacles(); + auto obst = owner.getBattle()->battleGetAllObstacles(); for(auto & elem : obst) { if ( elem->obstacleType == CObstacleInstance::MOAT ) @@ -99,9 +99,9 @@ void BattleObstacleController::obstaclePlaced(const std::vectorcb->playerToSide(owner.curInt->playerID); + auto side = owner.getBattle()->playerToSide(owner.curInt->playerID); - if(!oi->visibleForSide(side.value(), owner.curInt->cb->battleHasNativeStack(side.value()))) + if(!oi->visibleForSide(side.value(), owner.getBattle()->battleHasNativeStack(side.value()))) continue; auto animation = std::make_shared(oi->getAppearAnimation()); @@ -127,7 +127,7 @@ void BattleObstacleController::obstaclePlaced(const std::vectorcb->battleGetAllObstacles()) + for(auto & obstacle : owner.getBattle()->battleGetAllObstacles()) { if(obstacle->obstacleType == CObstacleInstance::ABSOLUTE_OBSTACLE) { @@ -153,7 +153,7 @@ void BattleObstacleController::showAbsoluteObstacles(Canvas & canvas) void BattleObstacleController::collectRenderableObjects(BattleRenderer & renderer) { - for (auto obstacle : owner.curInt->cb->battleGetAllObstacles()) + for (auto obstacle : owner.getBattle()->battleGetAllObstacles()) { if (obstacle->obstacleType == CObstacleInstance::ABSOLUTE_OBSTACLE) continue; diff --git a/client/battle/BattleSiegeController.cpp b/client/battle/BattleSiegeController.cpp index 63c8cab10..9be33e30a 100644 --- a/client/battle/BattleSiegeController.cpp +++ b/client/battle/BattleSiegeController.cpp @@ -133,9 +133,9 @@ bool BattleSiegeController::getWallPieceExistance(EWallVisual::EWallVisual what) { case EWallVisual::MOAT: return town->hasBuilt(BuildingID::CITADEL) && town->town->clientInfo.siegePositions.at(EWallVisual::MOAT).isValid(); case EWallVisual::MOAT_BANK: return town->hasBuilt(BuildingID::CITADEL) && town->town->clientInfo.siegePositions.at(EWallVisual::MOAT_BANK).isValid(); - case EWallVisual::KEEP_BATTLEMENT: return town->hasBuilt(BuildingID::CITADEL) && owner.curInt->cb->battleGetWallState(EWallPart::KEEP) != EWallState::DESTROYED; - case EWallVisual::UPPER_BATTLEMENT: return town->hasBuilt(BuildingID::CASTLE) && owner.curInt->cb->battleGetWallState(EWallPart::UPPER_TOWER) != EWallState::DESTROYED; - case EWallVisual::BOTTOM_BATTLEMENT: return town->hasBuilt(BuildingID::CASTLE) && owner.curInt->cb->battleGetWallState(EWallPart::BOTTOM_TOWER) != EWallState::DESTROYED; + case EWallVisual::KEEP_BATTLEMENT: return town->hasBuilt(BuildingID::CITADEL) && owner.getBattle()->battleGetWallState(EWallPart::KEEP) != EWallState::DESTROYED; + case EWallVisual::UPPER_BATTLEMENT: return town->hasBuilt(BuildingID::CASTLE) && owner.getBattle()->battleGetWallState(EWallPart::UPPER_TOWER) != EWallState::DESTROYED; + case EWallVisual::BOTTOM_BATTLEMENT: return town->hasBuilt(BuildingID::CASTLE) && owner.getBattle()->battleGetWallState(EWallPart::BOTTOM_TOWER) != EWallState::DESTROYED; default: return true; } } @@ -220,7 +220,7 @@ Point BattleSiegeController::getTurretCreaturePosition( BattleHex position ) con void BattleSiegeController::gateStateChanged(const EGateState state) { - auto oldState = owner.curInt->cb->battleGetGateState(); + auto oldState = owner.getBattle()->battleGetGateState(); bool playSound = false; auto stateId = EWallState::NONE; switch(state) @@ -275,7 +275,7 @@ BattleHex BattleSiegeController::getTurretBattleHex(EWallVisual::EWallVisual wal const CStack * BattleSiegeController::getTurretStack(EWallVisual::EWallVisual wallPiece) const { - for (auto & stack : owner.curInt->cb->battleGetAllStacks(true)) + for (auto & stack : owner.getBattle()->battleGetAllStacks(true)) { if ( stack->initialPosition == getTurretBattleHex(wallPiece)) return stack; @@ -318,15 +318,15 @@ bool BattleSiegeController::isAttackableByCatapult(BattleHex hex) const if (owner.tacticsMode) return false; - auto wallPart = owner.curInt->cb->battleHexToWallPart(hex); - return owner.curInt->cb->isWallPartAttackable(wallPart); + auto wallPart = owner.getBattle()->battleHexToWallPart(hex); + return owner.getBattle()->isWallPartAttackable(wallPart); } void BattleSiegeController::stackIsCatapulting(const CatapultAttack & ca) { if (ca.attacker != -1) { - const CStack *stack = owner.curInt->cb->battleGetStackByID(ca.attacker); + const CStack *stack = owner.getBattle()->battleGetStackByID(ca.attacker); for (auto attackInfo : ca.attackedParts) { owner.stacksController->addNewAnim(new CatapultAnimation(owner, stack, attackInfo.destinationTile, nullptr, attackInfo.damageDealt)); @@ -353,7 +353,7 @@ void BattleSiegeController::stackIsCatapulting(const CatapultAttack & ca) if (wallId == EWallVisual::GATE) continue; - auto wallState = EWallState(owner.curInt->cb->battleGetWallState(attackInfo.attackedPart)); + auto wallState = EWallState(owner.getBattle()->battleGetWallState(attackInfo.attackedPart)); wallPieceImages[wallId] = IImage::createFromFile(getWallPieceImageName(EWallVisual::EWallVisual(wallId), wallState)); } diff --git a/client/battle/BattleStacksController.cpp b/client/battle/BattleStacksController.cpp index f83e97782..d9a060031 100644 --- a/client/battle/BattleStacksController.cpp +++ b/client/battle/BattleStacksController.cpp @@ -94,7 +94,7 @@ BattleStacksController::BattleStacksController(BattleInterface & owner): amountNegative->adjustPalette(shifterNegative, ignoredMask); amountEffNeutral->adjustPalette(shifterNeutral, ignoredMask); - std::vector stacks = owner.curInt->cb->battleGetAllStacks(true); + std::vector stacks = owner.getBattle()->battleGetAllStacks(true); for(const CStack * s : stacks) { stackAdded(s, true); @@ -126,7 +126,7 @@ BattleHex BattleStacksController::getStackCurrentPosition(const CStack * stack) void BattleStacksController::collectRenderableObjects(BattleRenderer & renderer) { - auto stacks = owner.curInt->cb->battleGetAllStacks(false); + auto stacks = owner.getBattle()->battleGetAllStacks(false); for (auto stack : stacks) { @@ -359,7 +359,7 @@ void BattleStacksController::initializeBattleAnimations() void BattleStacksController::tickFrameBattleAnimations(uint32_t msPassed) { - for (auto stack : owner.curInt->cb->battleGetAllStacks(true)) + for (auto stack : owner.getBattle()->battleGetAllStacks(true)) { if (stackAnimation.find(stack->unitId()) == stackAnimation.end()) //e.g. for summoned but not yet handled stacks continue; @@ -552,9 +552,7 @@ void BattleStacksController::stackMoved(const CStack *stack, std::vectorcb->isToReverse( - attacker, - defender); + bool mustReverse = owner.getBattle()->isToReverse(attacker, defender); if (attacker->unitSide() == BattleSide::ATTACKER) return !mustReverse; @@ -670,7 +668,7 @@ void BattleStacksController::endAction(const BattleAction & action) owner.checkForAnimations(); //check if we should reverse stacks - TStacks stacks = owner.curInt->cb->battleGetStacks(CBattleCallback::MINE_AND_ENEMY); + TStacks stacks = owner.getBattle()->battleGetStacks(CPlayerBattleCallback::MINE_AND_ENEMY); for (const CStack *s : stacks) { @@ -847,7 +845,7 @@ std::vector BattleStacksController::selectHoveredStacks() auto hoveredQueueUnitId = owner.windowObject->getQueueHoveredUnitId(); if(hoveredQueueUnitId.has_value()) { - return { owner.curInt->cb->battleGetStackByID(hoveredQueueUnitId.value(), true) }; + return { owner.getBattle()->battleGetStackByID(hoveredQueueUnitId.value(), true) }; } auto hoveredHex = owner.fieldController->getHoveredHex(); @@ -867,14 +865,14 @@ std::vector BattleStacksController::selectHoveredStacks() spells::Target target; target.emplace_back(hoveredHex); - spells::BattleCast event(owner.curInt->cb.get(), caster, mode, spell); + spells::BattleCast event(owner.getBattle().get(), caster, mode, spell); auto mechanics = spell->battleMechanics(&event); return mechanics->getAffectedStacks(target); } if(hoveredHex.isValid()) { - const CStack * const stack = owner.curInt->cb->battleGetStackByPos(hoveredHex, true); + const CStack * const stack = owner.getBattle()->battleGetStackByPos(hoveredHex, true); if (stack) return {stack}; diff --git a/client/battle/BattleWindow.cpp b/client/battle/BattleWindow.cpp index 79f558932..0c71ac31b 100644 --- a/client/battle/BattleWindow.cpp +++ b/client/battle/BattleWindow.cpp @@ -367,10 +367,10 @@ void BattleWindow::bSurrenderf() if (owner.actionsController->spellcastingModeActive()) return; - int cost = owner.curInt->cb->battleGetSurrenderCost(); + int cost = owner.getBattle()->battleGetSurrenderCost(); if(cost >= 0) { - std::string enemyHeroName = owner.curInt->cb->battleGetEnemyHero().name; + std::string enemyHeroName = owner.getBattle()->battleGetEnemyHero().name; if(enemyHeroName.empty()) { logGlobal->warn("Surrender performed without enemy hero, should not happen!"); @@ -387,7 +387,7 @@ void BattleWindow::bFleef() if (owner.actionsController->spellcastingModeActive()) return; - if ( owner.curInt->cb->battleCanFlee() ) + if ( owner.getBattle()->battleCanFlee() ) { CFunctionList ony = std::bind(&BattleWindow::reallyFlee,this); owner.curInt->showYesNoDialog(CGI->generaltexth->allTexts[28], ony, nullptr); //Are you sure you want to retreat? @@ -398,10 +398,10 @@ void BattleWindow::bFleef() std::string heroName; //calculating fleeing hero's name if (owner.attackingHeroInstance) - if (owner.attackingHeroInstance->tempOwner == owner.curInt->cb->getMyColor()) + if (owner.attackingHeroInstance->tempOwner == owner.curInt->cb->getPlayerID()) heroName = owner.attackingHeroInstance->getNameTranslated(); if (owner.defendingHeroInstance) - if (owner.defendingHeroInstance->tempOwner == owner.curInt->cb->getMyColor()) + if (owner.defendingHeroInstance->tempOwner == owner.curInt->cb->getPlayerID()) heroName = owner.defendingHeroInstance->getNameTranslated(); //calculating text auto txt = boost::format(CGI->generaltexth->allTexts[340]) % heroName; //The Shackles of War are present. %s can not retreat! @@ -419,7 +419,7 @@ void BattleWindow::reallyFlee() void BattleWindow::reallySurrender() { - if (owner.curInt->cb->getResourceAmount(EGameResID::GOLD) < owner.curInt->cb->battleGetSurrenderCost()) + if (owner.curInt->cb->getResourceAmount(EGameResID::GOLD) < owner.getBattle()->battleGetSurrenderCost()) { owner.curInt->showInfoDialog(CGI->generaltexth->allTexts[29]); //You don't have enough gold! } @@ -509,7 +509,7 @@ void BattleWindow::bAutofightf() autocombatPreferences.enableSpellsUsage = settings["battle"]["enableAutocombatSpells"].Bool(); ai->initBattleInterface(owner.curInt->env, owner.curInt->cb, autocombatPreferences); - ai->battleStart(owner.army1, owner.army2, int3(0,0,0), owner.attackingHeroInstance, owner.defendingHeroInstance, owner.curInt->cb->battleGetMySide(), false); + ai->battleStart(owner.getBattleID(), owner.army1, owner.army2, int3(0,0,0), owner.attackingHeroInstance, owner.defendingHeroInstance, owner.getBattle()->battleGetMySide(), false); owner.curInt->autofightingAI = ai; owner.curInt->cb->registerBattleInterface(ai); @@ -531,7 +531,7 @@ void BattleWindow::bSpellf() CCS->curh->set(Cursor::Map::POINTER); - ESpellCastProblem spellCastProblem = owner.curInt->cb->battleCanCastSpell(myHero, spells::Mode::HERO); + ESpellCastProblem spellCastProblem = owner.getBattle()->battleCanCastSpell(myHero, spells::Mode::HERO); if(spellCastProblem == ESpellCastProblem::OK) { @@ -633,11 +633,11 @@ void BattleWindow::bTacticPhaseEnd() void BattleWindow::blockUI(bool on) { bool canCastSpells = false; - auto hero = owner.curInt->cb->battleGetMyHero(); + auto hero = owner.getBattle()->battleGetMyHero(); if(hero) { - ESpellCastProblem spellcastingProblem = owner.curInt->cb->battleCanCastSpell(hero, spells::Mode::HERO); + ESpellCastProblem spellcastingProblem = owner.getBattle()->battleCanCastSpell(hero, spells::Mode::HERO); //if magic is blocked, we leave button active, so the message can be displayed after button click canCastSpells = spellcastingProblem == ESpellCastProblem::OK || spellcastingProblem == ESpellCastProblem::MAGIC_IS_BLOCKED; @@ -646,8 +646,8 @@ void BattleWindow::blockUI(bool on) bool canWait = owner.stacksController->getActiveStack() ? !owner.stacksController->getActiveStack()->waitedThisTurn : false; setShortcutBlocked(EShortcut::GLOBAL_OPTIONS, on); - setShortcutBlocked(EShortcut::BATTLE_RETREAT, on || !owner.curInt->cb->battleCanFlee()); - setShortcutBlocked(EShortcut::BATTLE_SURRENDER, on || owner.curInt->cb->battleGetSurrenderCost() < 0); + setShortcutBlocked(EShortcut::BATTLE_RETREAT, on || !owner.getBattle()->battleCanFlee()); + setShortcutBlocked(EShortcut::BATTLE_SURRENDER, on || owner.getBattle()->battleGetSurrenderCost() < 0); setShortcutBlocked(EShortcut::BATTLE_CAST_SPELL, on || owner.tacticsMode || !canCastSpells); setShortcutBlocked(EShortcut::BATTLE_WAIT, on || owner.tacticsMode || !canWait); setShortcutBlocked(EShortcut::BATTLE_DEFEND, on || owner.tacticsMode); diff --git a/client/windows/CSpellWindow.cpp b/client/windows/CSpellWindow.cpp index 288a696cb..61f708068 100644 --- a/client/windows/CSpellWindow.cpp +++ b/client/windows/CSpellWindow.cpp @@ -503,7 +503,7 @@ void CSpellWindow::SpellArea::clickPressed(const Point & cursorPosition) else if(combatSpell) { spells::detail::ProblemImpl problem; - if(mySpell->canBeCast(problem, owner->myInt->cb.get(), spells::Mode::HERO, owner->myHero)) + if(mySpell->canBeCast(problem, owner->myInt->battleInt->getBattle().get(), spells::Mode::HERO, owner->myHero)) { owner->myInt->battleInt->castThisSpell(mySpell->id); owner->fexitb(); diff --git a/client/windows/GUIClasses.cpp b/client/windows/GUIClasses.cpp index 74ceb4317..abbb0539b 100644 --- a/client/windows/GUIClasses.cpp +++ b/client/windows/GUIClasses.cpp @@ -677,8 +677,8 @@ std::function CExchangeController::onSwapArmy() { return [&]() { - if(left->tempOwner != cb->getMyColor() - || right->tempOwner != cb->getMyColor()) + if(left->tempOwner != cb->getPlayerID() + || right->tempOwner != cb->getPlayerID()) { return; } @@ -720,7 +720,7 @@ std::function CExchangeController::onMoveStackToLeft(SlotID slotID) { return [=]() { - if(right->tempOwner != cb->getMyColor()) + if(right->tempOwner != cb->getPlayerID()) { return; } @@ -733,7 +733,7 @@ std::function CExchangeController::onMoveStackToRight(SlotID slotID) { return [=]() { - if(left->tempOwner != cb->getMyColor()) + if(left->tempOwner != cb->getPlayerID()) { return; } @@ -778,7 +778,7 @@ void CExchangeController::moveArmy(bool leftToRight) const CGarrisonSlot * selection = this->view->getSelectedSlotID(); SlotID slot; - if(source->tempOwner != cb->getMyColor()) + if(source->tempOwner != cb->getPlayerID()) { return; } @@ -807,7 +807,7 @@ void CExchangeController::moveArtifacts(bool leftToRight) const CGHeroInstance * source = leftToRight ? left : right; const CGHeroInstance * target = leftToRight ? right : left; - if(source->tempOwner != cb->getMyColor()) + if(source->tempOwner != cb->getPlayerID()) { return; } diff --git a/cmake_modules/VCMI_lib.cmake b/cmake_modules/VCMI_lib.cmake index ab2fbea2c..8cdec99e6 100644 --- a/cmake_modules/VCMI_lib.cmake +++ b/cmake_modules/VCMI_lib.cmake @@ -15,7 +15,6 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE) ${MAIN_LIB_DIR}/battle/BattleStateInfoForRetreat.cpp ${MAIN_LIB_DIR}/battle/CBattleInfoCallback.cpp ${MAIN_LIB_DIR}/battle/CBattleInfoEssentials.cpp - ${MAIN_LIB_DIR}/battle/CCallbackBase.cpp ${MAIN_LIB_DIR}/battle/CObstacleInstance.cpp ${MAIN_LIB_DIR}/battle/CPlayerBattleCallback.cpp ${MAIN_LIB_DIR}/battle/CUnitState.cpp @@ -339,7 +338,6 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE) ${MAIN_LIB_DIR}/battle/BattleProxy.h ${MAIN_LIB_DIR}/battle/CBattleInfoCallback.h ${MAIN_LIB_DIR}/battle/CBattleInfoEssentials.h - ${MAIN_LIB_DIR}/battle/CCallbackBase.h ${MAIN_LIB_DIR}/battle/CObstacleInstance.h ${MAIN_LIB_DIR}/battle/CPlayerBattleCallback.h ${MAIN_LIB_DIR}/battle/CUnitState.h diff --git a/lib/CGameInfoCallback.cpp b/lib/CGameInfoCallback.cpp index 3eac1f6be..b50d59e9b 100644 --- a/lib/CGameInfoCallback.cpp +++ b/lib/CGameInfoCallback.cpp @@ -66,6 +66,11 @@ bool CGameInfoCallback::isAllowed(int32_t type, int32_t id) const } } +std::optional CGameInfoCallback::getPlayerID() const +{ + return std::nullopt; +} + const Player * CGameInfoCallback::getPlayer(PlayerColor color) const { return getPlayerState(color, false); @@ -151,7 +156,7 @@ const CGObjectInstance* CGameInfoCallback::getObj(ObjectInstanceID objid, bool v return nullptr; } - if(!isVisible(ret, player) && ret->tempOwner != player) + if(!isVisible(ret, getPlayerID()) && ret->tempOwner != getPlayerID()) { if(verbose) logGlobal->error("Cannot get object with id %d. Object is not visible.", oid); @@ -232,7 +237,7 @@ void CGameInfoCallback::getThievesGuildInfo(SThievesGuildInfo & thi, const CGObj if(obj->ID == Obj::TOWN || obj->ID == Obj::TAVERN) { int taverns = 0; - for(auto town : gs->players[*player].towns) + for(auto town : gs->players[*getPlayerID()].towns) { if(town->hasBuilt(BuildingID::TAVERN)) taverns++; @@ -254,7 +259,7 @@ int CGameInfoCallback::howManyTowns(PlayerColor Player) const bool CGameInfoCallback::getTownInfo(const CGObjectInstance * town, InfoAboutTown & dest, const CGObjectInstance * selectedObject) const { - ERROR_RET_VAL_IF(!isVisible(town, player), "Town is not visible!", false); //it's not a town or it's not visible for layer + ERROR_RET_VAL_IF(!isVisible(town, getPlayerID()), "Town is not visible!", false); //it's not a town or it's not visible for layer bool detailed = hasAccess(town->tempOwner); if(town->ID == Obj::TOWN) @@ -305,9 +310,9 @@ bool CGameInfoCallback::getHeroInfo(const CGObjectInstance * hero, InfoAboutHero if (infoLevel == InfoAboutHero::EInfoLevel::BASIC) { - auto ourBattle = gs->getBattle(*player); + auto ourBattle = gs->getBattle(*getPlayerID()); - if(ourBattle && ourBattle->playerHasAccessToHeroInfo(*player, h)) //if it's battle we can get enemy hero full data + if(ourBattle && ourBattle->playerHasAccessToHeroInfo(*getPlayerID(), h)) //if it's battle we can get enemy hero full data infoLevel = InfoAboutHero::EInfoLevel::INBATTLE; else ERROR_RET_VAL_IF(!isVisible(h->visitablePos()), "That hero is not visible!", false); @@ -324,7 +329,7 @@ bool CGameInfoCallback::getHeroInfo(const CGObjectInstance * hero, InfoAboutHero dest.initFromHero(h, infoLevel); //DISGUISED bonus implementation - if(getPlayerRelations(*player, hero->tempOwner) == PlayerRelations::ENEMIES) + if(getPlayerRelations(*getPlayerID(), hero->tempOwner) == PlayerRelations::ENEMIES) { //todo: bonus cashing int disguiseLevel = h->valOfBonuses(Selector::typeSubtype(BonusType::DISGUISED, 0)); @@ -422,7 +427,7 @@ bool CGameInfoCallback::isVisible(int3 pos, const std::optional & P bool CGameInfoCallback::isVisible(int3 pos) const { - return isVisible(pos, player); + return isVisible(pos, getPlayerID()); } bool CGameInfoCallback::isVisible(const CGObjectInstance * obj, const std::optional & Player) const @@ -432,7 +437,7 @@ bool CGameInfoCallback::isVisible(const CGObjectInstance * obj, const std::optio bool CGameInfoCallback::isVisible(const CGObjectInstance *obj) const { - return isVisible(obj, player); + return isVisible(obj, getPlayerID()); } // const CCreatureSet* CInfoCallback::getGarrison(const CGObjectInstance *obj) const // { @@ -464,7 +469,7 @@ std::vector CGameInfoCallback::getVisitableObjs(int3 for(const CGObjectInstance * obj : t->visitableObjects) { - if(player || obj->ID != Obj::EVENT) //hide events from players + if(getPlayerID() || obj->ID != Obj::EVENT) //hide events from players ret.push_back(obj); } @@ -500,7 +505,7 @@ std::vector CGameInfoCallback::getAvailableHeroes(const const CGTownInstance * town = getTown(townOrTavern->id); if(townOrTavern->ID == Obj::TAVERN || (town && town->hasBuilt(BuildingID::TAVERN))) - return gs->heroesPool->getHeroesFor(*player); + return gs->heroesPool->getHeroesFor(*getPlayerID()); return ret; } @@ -531,8 +536,8 @@ EDiggingStatus CGameInfoCallback::getTileDigStatus(int3 tile, bool verbose) cons //TODO: typedef? std::shared_ptr> CGameInfoCallback::getAllVisibleTiles() const { - assert(player.has_value()); - const auto * team = getPlayerTeam(player.value()); + assert(getPlayerID().has_value()); + const auto * team = getPlayerTeam(getPlayerID().value()); size_t width = gs->map->width; size_t height = gs->map->height; @@ -631,7 +636,7 @@ const CMapHeader * CGameInfoCallback::getMapHeader() const bool CGameInfoCallback::hasAccess(std::optional playerId) const { - return !player || player->isSpectator() || gs->getPlayerRelations(*playerId, *player) != PlayerRelations::ENEMIES; + return !getPlayerID() || getPlayerID()->isSpectator() || gs->getPlayerRelations(*playerId, *getPlayerID()) != PlayerRelations::ENEMIES; } EPlayerStatus CGameInfoCallback::getPlayerStatus(PlayerColor player, bool verbose) const @@ -713,23 +718,22 @@ bool CGameInfoCallback::isPlayerMakingTurn(PlayerColor player) const return gs->actingPlayers.count(player); } -CGameInfoCallback::CGameInfoCallback(CGameState * GS, std::optional Player): +CGameInfoCallback::CGameInfoCallback(CGameState * GS): gs(GS) { - player = std::move(Player); } std::shared_ptr> CPlayerSpecificInfoCallback::getVisibilityMap() const { //boost::shared_lock lock(*gs->mx); - return gs->getPlayerTeam(*player)->fogOfWarMap; + return gs->getPlayerTeam(*getPlayerID())->fogOfWarMap; } int CPlayerSpecificInfoCallback::howManyTowns() const { //boost::shared_lock lock(*gs->mx); - ERROR_RET_VAL_IF(!player, "Applicable only for player callbacks", -1); - return CGameInfoCallback::howManyTowns(*player); + ERROR_RET_VAL_IF(!getPlayerID(), "Applicable only for player callbacks", -1); + return CGameInfoCallback::howManyTowns(*getPlayerID()); } std::vector < const CGTownInstance *> CPlayerSpecificInfoCallback::getTownsInfo(bool onlyOur) const @@ -740,7 +744,7 @@ std::vector < const CGTownInstance *> CPlayerSpecificInfoCallback::getTownsInfo( { for(const auto & town : i.second.towns) { - if(i.first == player || (!onlyOur && isVisible(town, player))) + if(i.first == getPlayerID() || (!onlyOur && isVisible(town, getPlayerID()))) { ret.push_back(town); } @@ -755,8 +759,8 @@ std::vector < const CGHeroInstance *> CPlayerSpecificInfoCallback::getHeroesInfo for(auto hero : gs->map->heroesOnMap) { // !player || // - why would we even get access to hero not owned by any player? - if((hero->tempOwner == *player) || - (isVisible(hero->visitablePos(), player) && !onlyOur) ) + if((hero->tempOwner == *getPlayerID()) || + (isVisible(hero->visitablePos(), getPlayerID()) && !onlyOur) ) { ret.push_back(hero); } @@ -764,18 +768,13 @@ std::vector < const CGHeroInstance *> CPlayerSpecificInfoCallback::getHeroesInfo return ret; } -std::optional CPlayerSpecificInfoCallback::getMyColor() const -{ - return player; -} - int CPlayerSpecificInfoCallback::getHeroSerial(const CGHeroInstance * hero, bool includeGarrisoned) const { if (hero->inTownGarrison && !includeGarrisoned) return -1; size_t index = 0; - auto & heroes = gs->players[*player].heroes; + auto & heroes = gs->players[*getPlayerID()].heroes; for (auto & heroe : heroes) { @@ -790,13 +789,13 @@ int CPlayerSpecificInfoCallback::getHeroSerial(const CGHeroInstance * hero, bool int3 CPlayerSpecificInfoCallback::getGrailPos( double *outKnownRatio ) { - if (!player || CGObelisk::obeliskCount == 0) + if (!getPlayerID() || CGObelisk::obeliskCount == 0) { *outKnownRatio = 0.0; } else { - TeamID t = gs->getPlayerTeam(*player)->id; + TeamID t = gs->getPlayerTeam(*getPlayerID())->id; double visited = 0.0; if(CGObelisk::visited.count(t)) visited = static_cast(CGObelisk::visited[t]); @@ -811,7 +810,7 @@ std::vector < const CGObjectInstance * > CPlayerSpecificInfoCallback::getMyObjec std::vector < const CGObjectInstance * > ret; for(const CGObjectInstance * obj : gs->map->objects) { - if(obj && obj->tempOwner == player) + if(obj && obj->tempOwner == getPlayerID()) ret.push_back(obj); } return ret; @@ -821,7 +820,7 @@ std::vector < const CGDwelling * > CPlayerSpecificInfoCallback::getMyDwellings() { ASSERT_IF_CALLED_WITH_PLAYER std::vector < const CGDwelling * > ret; - for(CGDwelling * dw : gs->getPlayerState(*player)->dwellings) + for(CGDwelling * dw : gs->getPlayerState(*getPlayerID())->dwellings) { ret.push_back(dw); } @@ -831,7 +830,7 @@ std::vector < const CGDwelling * > CPlayerSpecificInfoCallback::getMyDwellings() std::vector CPlayerSpecificInfoCallback::getMyQuests() const { std::vector ret; - for(const auto & quest : gs->getPlayerState(*player)->quests) + for(const auto & quest : gs->getPlayerState(*getPlayerID())->quests) { ret.push_back (quest); } @@ -841,14 +840,14 @@ std::vector CPlayerSpecificInfoCallback::getMyQuests() const int CPlayerSpecificInfoCallback::howManyHeroes(bool includeGarrisoned) const { //boost::shared_lock lock(*gs->mx); - ERROR_RET_VAL_IF(!player, "Applicable only for player callbacks", -1); - return getHeroCount(*player,includeGarrisoned); + ERROR_RET_VAL_IF(!getPlayerID(), "Applicable only for player callbacks", -1); + return getHeroCount(*getPlayerID(), includeGarrisoned); } const CGHeroInstance* CPlayerSpecificInfoCallback::getHeroBySerial(int serialId, bool includeGarrisoned) const { ASSERT_IF_CALLED_WITH_PLAYER - const PlayerState *p = getPlayerState(*player); + const PlayerState *p = getPlayerState(*getPlayerID()); ERROR_RET_VAL_IF(!p, "No player info", nullptr); if (!includeGarrisoned) @@ -864,7 +863,7 @@ const CGHeroInstance* CPlayerSpecificInfoCallback::getHeroBySerial(int serialId, const CGTownInstance* CPlayerSpecificInfoCallback::getTownBySerial(int serialId) const { ASSERT_IF_CALLED_WITH_PLAYER - const PlayerState *p = getPlayerState(*player); + const PlayerState *p = getPlayerState(*getPlayerID()); ERROR_RET_VAL_IF(!p, "No player info", nullptr); ERROR_RET_VAL_IF(serialId < 0 || serialId >= p->towns.size(), "No player info", nullptr); return p->towns[serialId]; @@ -873,15 +872,15 @@ const CGTownInstance* CPlayerSpecificInfoCallback::getTownBySerial(int serialId) int CPlayerSpecificInfoCallback::getResourceAmount(GameResID type) const { //boost::shared_lock lock(*gs->mx); - ERROR_RET_VAL_IF(!player, "Applicable only for player callbacks", -1); - return getResource(*player, type); + ERROR_RET_VAL_IF(!getPlayerID(), "Applicable only for player callbacks", -1); + return getResource(*getPlayerID(), type); } TResources CPlayerSpecificInfoCallback::getResourceAmount() const { //boost::shared_lock lock(*gs->mx); - ERROR_RET_VAL_IF(!player, "Applicable only for player callbacks", TResources()); - return gs->players[*player].resources; + ERROR_RET_VAL_IF(!getPlayerID(), "Applicable only for player callbacks", TResources()); + return gs->players[*getPlayerID()].resources; } const TeamState * CGameInfoCallback::getTeam( TeamID teamID ) const @@ -892,11 +891,11 @@ const TeamState * CGameInfoCallback::getTeam( TeamID teamID ) const if (team != gs->teams.end()) { const TeamState *ret = &team->second; - if(!player.has_value()) //neutral (or invalid) player + if(!getPlayerID().has_value()) //neutral (or invalid) player return ret; else { - if (vstd::contains(ret->players, *player)) //specific player + if (vstd::contains(ret->players, *getPlayerID())) //specific player return ret; else { @@ -942,7 +941,7 @@ bool CGameInfoCallback::isInTheMap(const int3 &pos) const void CGameInfoCallback::getVisibleTilesInRange(std::unordered_set &tiles, int3 pos, int radious, int3::EDistanceFormula distanceFormula) const { - gs->getTilesInRange(tiles, pos, radious, *player, -1, distanceFormula); + gs->getTilesInRange(tiles, pos, radious, *getPlayerID(), -1, distanceFormula); } void CGameInfoCallback::calculatePaths(const std::shared_ptr & config) diff --git a/lib/CGameInfoCallback.h b/lib/CGameInfoCallback.h index e912b53e2..e1a19d5c3 100644 --- a/lib/CGameInfoCallback.h +++ b/lib/CGameInfoCallback.h @@ -11,7 +11,8 @@ #include "int3.h" #include "ResourceSet.h" // for Res -#include "battle/CCallbackBase.h" + +#define ASSERT_IF_CALLED_WITH_PLAYER if(!getPlayerID()) {logGlobal->error(BOOST_CURRENT_FUNCTION); assert(0);} VCMI_LIB_NAMESPACE_BEGIN @@ -57,6 +58,7 @@ public: virtual bool isAllowed(int32_t type, int32_t id) const = 0; //type: 0 - spell; 1- artifact; 2 - secondary skill //player + virtual std::optional getPlayerID() const = 0; virtual const Player * getPlayer(PlayerColor color) const = 0; // virtual int getResource(PlayerColor Player, EGameResID which) const = 0; // bool isVisible(int3 pos) const; @@ -123,13 +125,13 @@ public: // bool isTeleportEntrancePassable(const CGTeleport * obj, PlayerColor player) const; }; -class DLL_LINKAGE CGameInfoCallback : public virtual CCallbackBase, public IGameInfoCallback +class DLL_LINKAGE CGameInfoCallback : public IGameInfoCallback { protected: CGameState * gs;//todo: replace with protected const getter, only actual Server and Client objects should hold game state CGameInfoCallback() = default; - CGameInfoCallback(CGameState * GS, std::optional Player); + CGameInfoCallback(CGameState * GS); bool hasAccess(std::optional playerId) const; bool canGetFullInfo(const CGObjectInstance *obj) const; //true we player owns obj or ally owns obj or privileged mode @@ -142,6 +144,7 @@ public: bool isAllowed(int32_t type, int32_t id) const override; //type: 0 - spell; 1- artifact; 2 - secondary skill //player + std::optional getPlayerID() const override; const Player * getPlayer(PlayerColor color) const override; virtual const PlayerState * getPlayerState(PlayerColor color, bool verbose = true) const; virtual int getResource(PlayerColor Player, GameResID which) const; @@ -229,7 +232,6 @@ public: virtual int howManyTowns() const; virtual int howManyHeroes(bool includeGarrisoned = true) const; virtual int3 getGrailPos(double *outKnownRatio); - virtual std::optional getMyColor() const; virtual std::vector getTownsInfo(bool onlyOur = true) const; //true -> only owned; false -> all visible virtual int getHeroSerial(const CGHeroInstance * hero, bool includeGarrisoned=true) const; diff --git a/lib/CGameInterface.cpp b/lib/CGameInterface.cpp index 3148aa65d..c2e49742d 100644 --- a/lib/CGameInterface.cpp +++ b/lib/CGameInterface.cpp @@ -157,9 +157,9 @@ CGlobalAI::CGlobalAI() human = false; } -void CAdventureAI::battleNewRound(const BattleID & battleID, int round) +void CAdventureAI::battleNewRound(const BattleID & battleID) { - battleAI->battleNewRound(battleID, round); + battleAI->battleNewRound(battleID); } void CAdventureAI::battleCatapultAttacked(const BattleID & battleID, const CatapultAttack & ca) @@ -187,9 +187,9 @@ void CAdventureAI::actionStarted(const BattleID & battleID, const BattleAction & battleAI->actionStarted(battleID, action); } -void CAdventureAI::battleNewRoundFirst(const BattleID & battleID, int round) +void CAdventureAI::battleNewRoundFirst(const BattleID & battleID) { - battleAI->battleNewRoundFirst(battleID, round); + battleAI->battleNewRoundFirst(battleID); } void CAdventureAI::actionFinished(const BattleID & battleID, const BattleAction & action) diff --git a/lib/CGameInterface.h b/lib/CGameInterface.h index 2f9fe192f..b0b9e6ce4 100644 --- a/lib/CGameInterface.h +++ b/lib/CGameInterface.h @@ -147,12 +147,12 @@ public: virtual void activeStack(const BattleID & battleID, const CStack * stack) override; virtual void yourTacticPhase(const BattleID & battleID, int distance) override; - virtual void battleNewRound(const BattleID & battleID, int round) override; + virtual void battleNewRound(const BattleID & battleID) override; virtual void battleCatapultAttacked(const BattleID & battleID, const CatapultAttack & ca) override; virtual void battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side, bool replayAllowed) override; virtual void battleStacksAttacked(const BattleID & battleID, const std::vector & bsa, bool ranged) override; virtual void actionStarted(const BattleID & battleID, const BattleAction &action) override; - virtual void battleNewRoundFirst(const BattleID & battleID, int round) override; + virtual void battleNewRoundFirst(const BattleID & battleID) override; virtual void actionFinished(const BattleID & battleID, const BattleAction &action) override; virtual void battleStacksEffectsSet(const BattleID & battleID, const SetStackEffect & sse) override; virtual void battleObstaclesChanged(const BattleID & battleID, const std::vector & obstacles) override; diff --git a/lib/IGameEventsReceiver.h b/lib/IGameEventsReceiver.h index 8139ee674..e3d81ec76 100644 --- a/lib/IGameEventsReceiver.h +++ b/lib/IGameEventsReceiver.h @@ -61,8 +61,8 @@ public: virtual void battleAttack(const BattleID & battleID, const BattleAttack *ba){}; //called when stack is performing attack virtual void battleStacksAttacked(const BattleID & battleID, const std::vector & bsa, bool ranged){}; //called when stack receives damage (after battleAttack()) virtual void battleEnd(const BattleID & battleID, const BattleResult *br, QueryID queryID){}; - virtual void battleNewRoundFirst(const BattleID & battleID, int round){}; //called at the beginning of each turn before changes are applied; - virtual void battleNewRound(const BattleID & battleID, int round){}; //called at the beginning of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn + virtual void battleNewRoundFirst(const BattleID & battleID){}; //called at the beginning of each turn before changes are applied; + virtual void battleNewRound(const BattleID & battleID){}; //called at the beginning of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn virtual void battleLogMessage(const BattleID & battleID, const std::vector & lines){}; virtual void battleStackMoved(const BattleID & battleID, const CStack * stack, std::vector dest, int distance, bool teleport){}; virtual void battleSpellCast(const BattleID & battleID, const BattleSpellCast *sc){}; diff --git a/lib/battle/CBattleInfoCallback.h b/lib/battle/CBattleInfoCallback.h index a2b197f2e..b0d30a0c3 100644 --- a/lib/battle/CBattleInfoCallback.h +++ b/lib/battle/CBattleInfoCallback.h @@ -11,7 +11,6 @@ #include -#include "CCallbackBase.h" #include "ReachabilityInfo.h" #include "BattleAttackInfo.h" diff --git a/lib/battle/CBattleInfoEssentials.h b/lib/battle/CBattleInfoEssentials.h index 18456c345..d1921e965 100644 --- a/lib/battle/CBattleInfoEssentials.h +++ b/lib/battle/CBattleInfoEssentials.h @@ -8,7 +8,6 @@ * */ #pragma once -#include "CCallbackBase.h" #include "IBattleInfoCallback.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/battle/CCallbackBase.cpp b/lib/battle/CCallbackBase.cpp deleted file mode 100644 index 0693548b4..000000000 --- a/lib/battle/CCallbackBase.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* - * CCallbackBase.cpp, part of VCMI engine - * - * Authors: listed in file AUTHORS in main folder - * - * License: GNU General Public License v2.0 or later - * Full text of license available in license.txt file, in main folder - * - */ -#include "StdInc.h" -#include "CCallbackBase.h" -#include "IBattleState.h" - -VCMI_LIB_NAMESPACE_BEGIN - -CCallbackBase::CCallbackBase(std::optional Player): - player(std::move(Player)) -{ -} - -std::optional CCallbackBase::getPlayerID() const -{ - return player; -} - - -VCMI_LIB_NAMESPACE_END diff --git a/lib/battle/CCallbackBase.h b/lib/battle/CCallbackBase.h deleted file mode 100644 index 16e408974..000000000 --- a/lib/battle/CCallbackBase.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * CCallbackBase.h, part of VCMI engine - * - * Authors: listed in file AUTHORS in main folder - * - * License: GNU General Public License v2.0 or later - * Full text of license available in license.txt file, in main folder - * - */ -#pragma once -#include "../GameConstants.h" - -#define RETURN_IF_NOT_BATTLE(...) if(!duringBattle()) {logGlobal->error("%s called when no battle!", __FUNCTION__); return __VA_ARGS__; } -#define ASSERT_IF_CALLED_WITH_PLAYER if(!getPlayerID()) {logGlobal->error(BOOST_CURRENT_FUNCTION); assert(0);} - -VCMI_LIB_NAMESPACE_BEGIN - -class IBattleInfo; -class BattleInfo; -class CBattleInfoEssentials; - -//Basic class for various callbacks (interfaces called by players to get info about game and so forth) -class DLL_LINKAGE CCallbackBase -{ -protected: - std::optional player; // not set gives access to all information, otherwise callback provides only information "visible" for player - - CCallbackBase(std::optional Player); - CCallbackBase() = default; - -public: - std::optional getPlayerID() const; -}; - - -VCMI_LIB_NAMESPACE_END diff --git a/lib/battle/CPlayerBattleCallback.cpp b/lib/battle/CPlayerBattleCallback.cpp index 08e9112c0..4412c9d28 100644 --- a/lib/battle/CPlayerBattleCallback.cpp +++ b/lib/battle/CPlayerBattleCallback.cpp @@ -11,9 +11,27 @@ #include "CPlayerBattleCallback.h" #include "../CStack.h" #include "../gameState/InfoAboutArmy.h" +#include "../CGameInfoCallback.h" VCMI_LIB_NAMESPACE_BEGIN +CPlayerBattleCallback::CPlayerBattleCallback(const IBattleInfo * battle, PlayerColor player): + battle(battle), + player(player) +{ + +} + +const IBattleInfo * CPlayerBattleCallback::getBattle() const +{ + return battle; +} + +std::optional CPlayerBattleCallback::getPlayerID() const +{ + return player; +} + bool CPlayerBattleCallback::battleCanFlee() const { RETURN_IF_NOT_BATTLE(false); diff --git a/lib/battle/CPlayerBattleCallback.h b/lib/battle/CPlayerBattleCallback.h index f903a37af..60fbbd3d5 100644 --- a/lib/battle/CPlayerBattleCallback.h +++ b/lib/battle/CPlayerBattleCallback.h @@ -16,7 +16,15 @@ class CGHeroInstance; class DLL_LINKAGE CPlayerBattleCallback : public CBattleInfoCallback { + const IBattleInfo * battle; + PlayerColor player; + public: + CPlayerBattleCallback(const IBattleInfo * battle, PlayerColor player); + + const IBattleInfo * getBattle() const override; + std::optional getPlayerID() const override; + bool battleCanFlee() const; //returns true if caller can flee from the battle TStacks battleGetStacks(EStackOwnership whose = MINE_AND_ENEMY, bool onlyAlive = true) const; //returns stacks on battlefield diff --git a/lib/battle/IBattleInfoCallback.h b/lib/battle/IBattleInfoCallback.h index cc03c4ab5..d216bf454 100644 --- a/lib/battle/IBattleInfoCallback.h +++ b/lib/battle/IBattleInfoCallback.h @@ -15,6 +15,8 @@ #include +#define RETURN_IF_NOT_BATTLE(...) if(!duringBattle()) {logGlobal->error("%s called when no battle!", __FUNCTION__); return __VA_ARGS__; } + VCMI_LIB_NAMESPACE_BEGIN struct CObstacleInstance; diff --git a/lib/pathfinder/CPathfinder.cpp b/lib/pathfinder/CPathfinder.cpp index 78a9b307a..cf4910ea3 100644 --- a/lib/pathfinder/CPathfinder.cpp +++ b/lib/pathfinder/CPathfinder.cpp @@ -456,7 +456,7 @@ bool CPathfinderHelper::passOneTurnLimitCheck(const PathNodeInfo & source) const } CPathfinderHelper::CPathfinderHelper(CGameState * gs, const CGHeroInstance * Hero, const PathfinderOptions & Options): - CGameInfoCallback(gs, std::optional()), + CGameInfoCallback(gs), turn(-1), hero(Hero), options(Options),