diff --git a/AI/BattleAI/BattleAI.cpp b/AI/BattleAI/BattleAI.cpp index f96d33084..b94a56513 100644 --- a/AI/BattleAI/BattleAI.cpp +++ b/AI/BattleAI/BattleAI.cpp @@ -52,7 +52,8 @@ void CBattleAI::initBattleInterface(std::shared_ptr ENV, std::share setCbc(CB); env = ENV; cb = CB; - playerID = *CB->getPlayerID(); //TODO should be sth in callback + assert(0);// FIXME: + // playerID = *CB->getPlayerID(); //TODO should be sth in callback wasWaitingForRealize = CB->waitTillRealize; wasUnlockingGs = CB->unlockGsWhenWaiting; CB->waitTillRealize = false; @@ -66,9 +67,9 @@ void CBattleAI::initBattleInterface(std::shared_ptr ENV, std::share autobattlePreferences = autocombatPreferences; } -BattleAction CBattleAI::useHealingTent(const CStack *stack) +BattleAction CBattleAI::useHealingTent(const BattleID & battleID, const CStack *stack) { - auto healingTargets = cb->battleGetStacks(CBattleInfoEssentials::ONLY_MINE); + auto healingTargets = cb->getBattle(battleID)->battleGetStacks(CBattleInfoEssentials::ONLY_MINE); std::map woundHpToStack; for(const auto * stack : healingTargets) { @@ -82,12 +83,12 @@ BattleAction CBattleAI::useHealingTent(const CStack *stack) return BattleAction::makeHeal(stack, woundHpToStack.rbegin()->second); //last element of the woundHpToStack is the most wounded stack } -void CBattleAI::yourTacticPhase(int distance) +void CBattleAI::yourTacticPhase(const BattleID & battleID, int distance) { - cb->battleMakeTacticAction(BattleAction::makeEndOFTacticPhase(cb->battleGetTacticsSide())); + cb->battleMakeTacticAction(battleID, BattleAction::makeEndOFTacticPhase(cb->getBattle(battleID)->battleGetTacticsSide())); } -float getStrengthRatio(std::shared_ptr cb, int side) +static float getStrengthRatio(std::shared_ptr cb, int side) { auto stacks = cb->battleGetAllStacks(); auto our = 0, enemy = 0; @@ -108,7 +109,7 @@ float getStrengthRatio(std::shared_ptr cb, int side) return enemy == 0 ? 1.0f : static_cast(our) / enemy; } -void CBattleAI::activeStack(const CStack * stack ) +void CBattleAI::activeStack(const BattleID & battleID, const CStack * stack ) { LOG_TRACE_PARAMS(logAi, "stack: %s", stack->nodeName()); @@ -128,12 +129,12 @@ void CBattleAI::activeStack(const CStack * stack ) { if(stack->creatureId() == CreatureID::CATAPULT) { - cb->battleMakeUnitAction(useCatapult(stack)); + cb->battleMakeUnitAction(battleID, useCatapult(battleID, stack)); return; } if(stack->hasBonusOfType(BonusType::SIEGE_WEAPON) && stack->hasBonusOfType(BonusType::HEALER)) { - cb->battleMakeUnitAction(useHealingTent(stack)); + cb->battleMakeUnitAction(battleID, useHealingTent(battleID, stack)); return; } @@ -141,7 +142,7 @@ void CBattleAI::activeStack(const CStack * stack ) logAi->trace("Build evaluator and targets"); #endif - BattleEvaluator evaluator(env, cb, stack, playerID, side, getStrengthRatio(cb, side)); + BattleEvaluator evaluator(env, cb, stack, playerID, battleID, side, getStrengthRatio(cb->getBattle(battleID), side)); result = evaluator.selectStackAction(stack); @@ -157,9 +158,9 @@ void CBattleAI::activeStack(const CStack * stack ) logAi->trace("Spellcast attempt completed in %lld", timeElapsed(start)); - if(auto action = considerFleeingOrSurrendering()) + if(auto action = considerFleeingOrSurrendering(battleID)) { - cb->battleMakeUnitAction(*action); + cb->battleMakeUnitAction(battleID, *action); return; } } @@ -183,17 +184,17 @@ void CBattleAI::activeStack(const CStack * stack ) logAi->trace("BattleAI decission made in %lld", timeElapsed(start)); - cb->battleMakeUnitAction(result); + cb->battleMakeUnitAction(battleID, result); } -BattleAction CBattleAI::useCatapult(const CStack * stack) +BattleAction CBattleAI::useCatapult(const BattleID & battleID, const CStack * stack) { BattleAction attack; BattleHex targetHex = BattleHex::INVALID; - if(cb->battleGetGateState() == EGateState::CLOSED) + if(cb->getBattle(battleID)->battleGetGateState() == EGateState::CLOSED) { - targetHex = cb->wallPartToBattleHex(EWallPart::GATE); + targetHex = cb->getBattle(battleID)->wallPartToBattleHex(EWallPart::GATE); } else { @@ -209,11 +210,11 @@ BattleAction CBattleAI::useCatapult(const CStack * stack) for(auto wallPart : wallParts) { - auto wallState = cb->battleGetWallState(wallPart); + auto wallState = cb->getBattle(battleID)->battleGetWallState(wallPart); if(wallState == EWallState::REINFORCED || wallState == EWallState::INTACT || wallState == EWallState::DAMAGED) { - targetHex = cb->wallPartToBattleHex(wallPart); + targetHex = cb->getBattle(battleID)->wallPartToBattleHex(wallPart); break; } } @@ -234,7 +235,7 @@ BattleAction CBattleAI::useCatapult(const CStack * stack) return attack; } -void CBattleAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool Side, bool replayAllowed) +void CBattleAI::battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool Side, bool replayAllowed) { LOG_TRACE(logAi); side = Side; @@ -247,17 +248,17 @@ void CBattleAI::print(const std::string &text) const logAi->trace("%s Battle AI[%p]: %s", playerID.toString(), this, text); } -std::optional CBattleAI::considerFleeingOrSurrendering() +std::optional CBattleAI::considerFleeingOrSurrendering(const BattleID & battleID) { BattleStateInfoForRetreat bs; - bs.canFlee = cb->battleCanFlee(); - bs.canSurrender = cb->battleCanSurrender(playerID); - bs.ourSide = cb->battleGetMySide(); - bs.ourHero = cb->battleGetMyHero(); + bs.canFlee = cb->getBattle(battleID)->battleCanFlee(); + bs.canSurrender = cb->getBattle(battleID)->battleCanSurrender(playerID); + bs.ourSide = cb->getBattle(battleID)->battleGetMySide(); + bs.ourHero = cb->getBattle(battleID)->battleGetMyHero(); bs.enemyHero = nullptr; - for(auto stack : cb->battleGetAllStacks(false)) + for(auto stack : cb->getBattle(battleID)->battleGetAllStacks(false)) { if(stack->alive()) { @@ -266,7 +267,7 @@ std::optional CBattleAI::considerFleeingOrSurrendering() else { bs.enemyStacks.push_back(stack); - bs.enemyHero = cb->battleGetOwnerHero(stack); + bs.enemyHero = cb->getBattle(battleID)->battleGetOwnerHero(stack); } } } @@ -278,7 +279,7 @@ std::optional CBattleAI::considerFleeingOrSurrendering() return std::nullopt; } - auto result = cb->makeSurrenderRetreatDecision(bs); + auto result = cb->makeSurrenderRetreatDecision(battleID, bs); if(!result && bs.canFlee && bs.turnsSkippedByDefense > 30) { diff --git a/AI/BattleAI/BattleAI.h b/AI/BattleAI/BattleAI.h index a059e501c..497a77f3f 100644 --- a/AI/BattleAI/BattleAI.h +++ b/AI/BattleAI/BattleAI.h @@ -71,16 +71,16 @@ public: void initBattleInterface(std::shared_ptr ENV, std::shared_ptr CB) override; void initBattleInterface(std::shared_ptr ENV, std::shared_ptr CB, AutocombatPreferences autocombatPreferences) override; - void activeStack(const CStack * stack) override; //called when it's turn of that stack - void yourTacticPhase(int distance) override; + void activeStack(const BattleID & battleID, const CStack * stack) override; //called when it's turn of that stack + void yourTacticPhase(const BattleID & battleID, int distance) override; - std::optional considerFleeingOrSurrendering(); + std::optional considerFleeingOrSurrendering(const BattleID & battleID); void print(const std::string &text) const; - BattleAction useCatapult(const CStack *stack); - BattleAction useHealingTent(const CStack *stack); + BattleAction useCatapult(const BattleID & battleID, const CStack *stack); + BattleAction useHealingTent(const BattleID & battleID, const CStack *stack); - void battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool Side, bool replayAllowed) override; + void battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool Side, bool replayAllowed) override; //void actionFinished(const BattleAction &action) override;//occurs AFTER every action taken by any stack or by the hero //void actionStarted(const BattleAction &action) override;//occurs BEFORE every action taken by any stack or by the hero //void battleAttack(const BattleAttack *ba) override; //called when stack is performing attack diff --git a/AI/BattleAI/BattleEvaluator.cpp b/AI/BattleAI/BattleEvaluator.cpp index ec65c194d..cae77e61f 100644 --- a/AI/BattleAI/BattleEvaluator.cpp +++ b/AI/BattleAI/BattleEvaluator.cpp @@ -53,12 +53,12 @@ std::vector BattleEvaluator::getBrokenWallMoatHexes() const for(EWallPart wallPart : { EWallPart::BOTTOM_WALL, EWallPart::BELOW_GATE, EWallPart::OVER_GATE, EWallPart::UPPER_WALL }) { - auto state = cb->battleGetWallState(wallPart); + auto state = cb->getBattle(battleID)->battleGetWallState(wallPart); if(state != EWallState::DESTROYED) continue; - auto wallHex = cb->wallPartToBattleHex((EWallPart)wallPart); + auto wallHex = cb->getBattle(battleID)->wallPartToBattleHex((EWallPart)wallPart); auto moatHex = wallHex.cloneInDirection(BattleHex::LEFT); result.push_back(moatHex); @@ -70,15 +70,15 @@ std::vector BattleEvaluator::getBrokenWallMoatHexes() const std::optional BattleEvaluator::findBestCreatureSpell(const CStack *stack) { //TODO: faerie dragon type spell should be selected by server - SpellID creatureSpellToCast = cb->battleGetRandomStackSpell(CRandomGenerator::getDefault(), stack, CBattleInfoCallback::RANDOM_AIMED); + SpellID creatureSpellToCast = cb->getBattle(battleID)->battleGetRandomStackSpell(CRandomGenerator::getDefault(), stack, CBattleInfoCallback::RANDOM_AIMED); if(stack->hasBonusOfType(BonusType::SPELLCASTER) && stack->canCast() && creatureSpellToCast != SpellID::NONE) { const CSpell * spell = creatureSpellToCast.toSpell(); - if(spell->canBeCast(getCbc().get(), spells::Mode::CREATURE_ACTIVE, stack)) + if(spell->canBeCast(cb->getBattle(battleID).get(), spells::Mode::CREATURE_ACTIVE, stack)) { std::vector possibleCasts; - spells::BattleCast temp(getCbc().get(), stack, spells::Mode::CREATURE_ACTIVE, spell); + spells::BattleCast temp(cb->getBattle(battleID).get(), stack, spells::Mode::CREATURE_ACTIVE, spell); for(auto & target : temp.findPotentialTargets()) { PossibleSpellcast ps; @@ -201,7 +201,7 @@ BattleAction BattleEvaluator::selectStackAction(const CStack * stack) if(score <= EvaluationResult::INEFFECTIVE_SCORE && !stack->hasBonusOfType(BonusType::FLYING) && stack->unitSide() == BattleSide::ATTACKER - && cb->battleGetSiegeLevel() >= CGTownInstance::CITADEL) + && cb->getBattle(battleID)->battleGetSiegeLevel() >= CGTownInstance::CITADEL) { auto brokenWallMoat = getBrokenWallMoatHexes(); @@ -228,8 +228,8 @@ uint64_t timeElapsed(std::chrono::time_point BattleAction BattleEvaluator::goTowardsNearest(const CStack * stack, std::vector hexes) { - auto reachability = cb->getReachability(stack); - auto avHexes = cb->battleGetAvailableHexes(reachability, stack, false); + auto reachability = cb->getBattle(battleID)->getReachability(stack); + auto avHexes = cb->getBattle(battleID)->battleGetAvailableHexes(reachability, stack, false); if(!avHexes.size() || !hexes.size()) //we are blocked or dest is blocked { @@ -325,16 +325,16 @@ BattleAction BattleEvaluator::goTowardsNearest(const CStack * stack, std::vector bool BattleEvaluator::canCastSpell() { - auto hero = cb->battleGetMyHero(); + auto hero = cb->getBattle(battleID)->battleGetMyHero(); if(!hero) return false; - return cb->battleCanCastSpell(hero, spells::Mode::HERO) == ESpellCastProblem::OK; + return cb->getBattle(battleID)->battleCanCastSpell(hero, spells::Mode::HERO) == ESpellCastProblem::OK; } bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack) { - auto hero = cb->battleGetMyHero(); + auto hero = cb->getBattle(battleID)->battleGetMyHero(); if(!hero) return false; @@ -343,7 +343,7 @@ bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack) std::vector possibleSpells; vstd::copy_if(VLC->spellh->objects, std::back_inserter(possibleSpells), [hero, this](const CSpell *s) -> bool { - return s->canBeCast(cb.get(), spells::Mode::HERO, hero); + return s->canBeCast(cb->getBattle(battleID).get(), spells::Mode::HERO, hero); }); LOGFL("I can cast %d spells.", possibleSpells.size()); @@ -358,7 +358,7 @@ bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack) std::vector possibleCasts; for(auto spell : possibleSpells) { - spells::BattleCast temp(cb.get(), hero, spells::Mode::HERO, spell); + spells::BattleCast temp(cb->getBattle(battleID).get(), hero, spells::Mode::HERO, spell); if(spell->getTargetType() == spells::AimType::LOCATION) continue; @@ -468,7 +468,7 @@ bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack) ValueMap valueOfStack; ValueMap healthOfStack; - TStacks all = cb->battleGetAllStacks(false); + TStacks all = cb->getBattle(battleID)->battleGetAllStacks(false); size_t ourRemainingTurns = 0; @@ -477,7 +477,7 @@ bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack) healthOfStack[unit->unitId()] = unit->getAvailableHealth(); valueOfStack[unit->unitId()] = 0; - if(cb->battleGetOwner(unit) == playerID && unit->canMove() && !unit->moved()) + if(cb->getBattle(battleID)->battleGetOwner(unit) == playerID && unit->canMove() && !unit->moved()) ourRemainingTurns++; } @@ -494,12 +494,12 @@ bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack) std::vector turnOrder; - cb->battleGetTurnOrder(turnOrder, amount, 2); //no more than 1 turn after current, each unit at least once + cb->getBattle(battleID)->battleGetTurnOrder(turnOrder, amount, 2); //no more than 1 turn after current, each unit at least once { bool enemyHadTurn = false; - auto state = std::make_shared(env.get(), cb); + auto state = std::make_shared(env.get(), cb->getBattle(battleID)); evaluateQueue(valueOfStack, turnOrder, state, 0, &enemyHadTurn); @@ -531,7 +531,7 @@ bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack) logAi->trace("Evaluating %s", ps.spell->getNameTranslated()); #endif - auto state = std::make_shared(env.get(), cb); + auto state = std::make_shared(env.get(), cb->getBattle(battleID)); spells::BattleCast cast(state.get(), hero, spells::Mode::HERO, ps.spell); cast.castEval(state->getServerCallback(), ps.dest); @@ -540,7 +540,7 @@ bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack) auto needFullEval = vstd::contains_if(allUnits, [&](const battle::Unit * u) -> bool { - auto original = cb->battleGetUnitByID(u->unitId()); + auto original = cb->getBattle(battleID)->battleGetUnitByID(u->unitId()); return !original || u->speed() != original->speed(); }); @@ -583,7 +583,7 @@ bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack) if(oldHealth != newHealth) { auto damage = std::abs(oldHealth - newHealth); - auto originalDefender = cb->battleGetUnitByID(unit->unitId()); + auto originalDefender = cb->getBattle(battleID)->battleGetUnitByID(unit->unitId()); auto dpsReduce = AttackPossibility::calculateDamageReduce( nullptr, @@ -639,7 +639,7 @@ bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack) spellcast.setTarget(castToPerform.dest); spellcast.side = side; spellcast.stackNumber = (!side) ? -1 : -2; - cb->battleMakeSpellAction(spellcast); + cb->battleMakeSpellAction(battleID, spellcast); activeActionMade = true; return true; @@ -656,8 +656,8 @@ void BattleEvaluator::evaluateCreatureSpellcast(const CStack * stack, PossibleSp using ValueMap = PossibleSpellcast::ValueMap; RNGStub rngStub; - HypotheticBattle state(env.get(), cb); - TStacks all = cb->battleGetAllStacks(false); + HypotheticBattle state(env.get(), cb->getBattle(battleID)); + TStacks all = cb->getBattle(battleID)->battleGetAllStacks(false); ValueMap healthOfStack; ValueMap newHealthOfStack; @@ -686,7 +686,7 @@ void BattleEvaluator::evaluateCreatureSpellcast(const CStack * stack, PossibleSp auto healthDiff = newHealthOfStack[unitId] - healthOfStack[unitId]; - if(localUnit->unitOwner() != getCbc()->getPlayerID()) + if(localUnit->unitOwner() != cb->getBattle(battleID)->getPlayerID()) healthDiff = -healthDiff; if(healthDiff < 0) diff --git a/AI/BattleAI/BattleEvaluator.h b/AI/BattleAI/BattleEvaluator.h index cb183f46b..6198d56a4 100644 --- a/AI/BattleAI/BattleEvaluator.h +++ b/AI/BattleAI/BattleEvaluator.h @@ -32,6 +32,7 @@ class BattleEvaluator bool activeActionMade = false; std::optional cachedAttack; PlayerColor playerID; + BattleID battleID; int side; float cachedScore; DamageCache damageCache; @@ -52,11 +53,12 @@ public: std::shared_ptr cb, const battle::Unit * activeStack, PlayerColor playerID, + BattleID battleID, int side, float strengthRatio) - :scoreEvaluator(cb, env, strengthRatio), cachedAttack(), playerID(playerID), side(side), env(env), cb(cb), strengthRatio(strengthRatio) + :scoreEvaluator(cb->getBattle(battleID), env, strengthRatio), cachedAttack(), playerID(playerID), side(side), env(env), cb(cb), strengthRatio(strengthRatio), battleID(battleID) { - hb = std::make_shared(env.get(), cb); + hb = std::make_shared(env.get(), cb->getBattle(battleID)); damageCache.buildDamageCache(hb, side); targets = std::make_unique(activeStack, damageCache, hb); @@ -70,9 +72,10 @@ public: DamageCache & damageCache, const battle::Unit * activeStack, PlayerColor playerID, + BattleID battleID, int side, float strengthRatio) - :scoreEvaluator(cb, env, strengthRatio), cachedAttack(), playerID(playerID), side(side), env(env), cb(cb), hb(hb), damageCache(damageCache), strengthRatio(strengthRatio) + :scoreEvaluator(cb->getBattle(battleID), env, strengthRatio), cachedAttack(), playerID(playerID), side(side), env(env), cb(cb), hb(hb), damageCache(damageCache), strengthRatio(strengthRatio), battleID(battleID) { targets = std::make_unique(activeStack, damageCache, hb); cachedScore = EvaluationResult::INEFFECTIVE_SCORE; diff --git a/AI/BattleAI/BattleExchangeVariant.h b/AI/BattleAI/BattleExchangeVariant.h index 19da2721a..36b8b2592 100644 --- a/AI/BattleAI/BattleExchangeVariant.h +++ b/AI/BattleAI/BattleExchangeVariant.h @@ -133,4 +133,4 @@ public: float getPositiveEffectMultiplier() { return 1; } float getNegativeEffectMultiplier() { return negativeEffectMultiplier; } -}; \ No newline at end of file +}; diff --git a/AI/EmptyAI/CEmptyAI.cpp b/AI/EmptyAI/CEmptyAI.cpp index 4c2829308..0e0a35489 100644 --- a/AI/EmptyAI/CEmptyAI.cpp +++ b/AI/EmptyAI/CEmptyAI.cpp @@ -36,14 +36,14 @@ void CEmptyAI::yourTurn(QueryID queryID) cb->endTurn(); } -void CEmptyAI::activeStack(const CStack * stack) +void CEmptyAI::activeStack(const BattleID & battleID, const CStack * stack) { - cb->battleMakeUnitAction(BattleAction::makeDefend(stack)); + cb->battleMakeUnitAction(battleID, BattleAction::makeDefend(stack)); } -void CEmptyAI::yourTacticPhase(int distance) +void CEmptyAI::yourTacticPhase(const BattleID & battleID, int distance) { - cb->battleMakeTacticAction(BattleAction::makeEndOFTacticPhase(cb->battleGetTacticsSide())); + cb->battleMakeTacticAction(battleID, BattleAction::makeEndOFTacticPhase(cb->getBattle(battleID)->battleGetTacticsSide())); } void CEmptyAI::heroGotLevel(const CGHeroInstance *hero, PrimarySkill pskill, std::vector &skills, QueryID queryID) @@ -76,7 +76,7 @@ void CEmptyAI::showMapObjectSelectDialog(QueryID askID, const Component & icon, cb->selectionMade(0, askID); } -std::optional CEmptyAI::makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) +std::optional CEmptyAI::makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState) { return std::nullopt; } diff --git a/AI/EmptyAI/CEmptyAI.h b/AI/EmptyAI/CEmptyAI.h index 297795839..1bc668e9e 100644 --- a/AI/EmptyAI/CEmptyAI.h +++ b/AI/EmptyAI/CEmptyAI.h @@ -24,15 +24,15 @@ public: void initGameInterface(std::shared_ptr ENV, std::shared_ptr CB) override; void yourTurn(QueryID queryID) override; - void yourTacticPhase(int distance) override; - void activeStack(const CStack * stack) override; + void yourTacticPhase(const BattleID & battleID, int distance) override; + void activeStack(const BattleID & battleID, const CStack * stack) override; void heroGotLevel(const CGHeroInstance *hero, PrimarySkill pskill, std::vector &skills, QueryID queryID) override; void commanderGotLevel (const CCommanderInstance * commander, std::vector skills, QueryID queryID) override; void showBlockingDialog(const std::string &text, const std::vector &components, QueryID askID, const int soundID, bool selection, bool cancel) override; void showTeleportDialog(TeleportChannelID channel, TTeleportExitsList exits, bool impassable, QueryID askID) override; void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, QueryID queryID) override; void showMapObjectSelectDialog(QueryID askID, const Component & icon, const MetaString & title, const MetaString & description, const std::vector & objects) override; - std::optional makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) override; + std::optional makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState) override; }; #define NAME "EmptyAI 0.1" diff --git a/AI/Nullkiller/AIGateway.cpp b/AI/Nullkiller/AIGateway.cpp index ad30802c3..83e0b1b28 100644 --- a/AI/Nullkiller/AIGateway.cpp +++ b/AI/Nullkiller/AIGateway.cpp @@ -21,6 +21,7 @@ #include "../../lib/serializer/BinarySerializer.h" #include "../../lib/serializer/BinaryDeserializer.h" #include "../../lib/battle/BattleStateInfoForRetreat.h" +#include "../../lib/battle/BattleInfo.h" #include "AIGateway.h" #include "Goals/Goals.h" @@ -510,7 +511,7 @@ void AIGateway::showWorldViewEx(const std::vector & objectPositio NET_EVENT_HANDLER; } -std::optional AIGateway::makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) +std::optional AIGateway::makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState) { LOG_TRACE(logAi); NET_EVENT_HANDLER; @@ -1080,22 +1081,22 @@ void AIGateway::recruitCreatures(const CGDwelling * d, const CArmedInstance * re } } -void AIGateway::battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed) +void AIGateway::battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed) { NET_EVENT_HANDLER; assert(!playerID.isValidPlayer() || status.getBattle() == UPCOMING_BATTLE); status.setBattle(ONGOING_BATTLE); const CGObjectInstance * presumedEnemy = vstd::backOrNull(cb->getVisitableObjs(tile)); //may be nullptr in some very are cases -> eg. visited monolith and fighting with an enemy at the FoW covered exit battlename = boost::str(boost::format("Starting battle of %s attacking %s at %s") % (hero1 ? hero1->getNameTranslated() : "a army") % (presumedEnemy ? presumedEnemy->getObjectName() : "unknown enemy") % tile.toString()); - CAdventureAI::battleStart(army1, army2, tile, hero1, hero2, side, replayAllowed); + CAdventureAI::battleStart(battleID, army1, army2, tile, hero1, hero2, side, replayAllowed); } -void AIGateway::battleEnd(const BattleResult * br, QueryID queryID) +void AIGateway::battleEnd(const BattleID & battleID, const BattleResult * br, QueryID queryID) { NET_EVENT_HANDLER; assert(status.getBattle() == ONGOING_BATTLE); status.setBattle(ENDING_BATTLE); - bool won = br->winner == myCb->battleGetMySide(); + bool won = br->winner == myCb->getBattle(battleID)->battleGetMySide(); logAi->debug("Player %d (%s): I %s the %s!", playerID, playerID.toString(), (won ? "won" : "lost"), battlename); battlename.clear(); @@ -1108,7 +1109,7 @@ void AIGateway::battleEnd(const BattleResult * br, QueryID queryID) answerQuery(queryID, confirmAction); }); } - CAdventureAI::battleEnd(br, queryID); + CAdventureAI::battleEnd(battleID, br, queryID); } void AIGateway::waitTillFree() diff --git a/AI/Nullkiller/AIGateway.h b/AI/Nullkiller/AIGateway.h index c4064f164..45021b419 100644 --- a/AI/Nullkiller/AIGateway.h +++ b/AI/Nullkiller/AIGateway.h @@ -167,10 +167,10 @@ public: void heroBonusChanged(const CGHeroInstance * hero, const Bonus & bonus, bool gain) override; void showMarketWindow(const IMarket * market, const CGHeroInstance * visitor) override; void showWorldViewEx(const std::vector & objectPositions, bool showTerrain) override; - std::optional makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) override; + std::optional makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState) override; - void battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed) override; - void battleEnd(const BattleResult * br, QueryID queryID) override; + void battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed) override; + void battleEnd(const BattleID & battleID, const BattleResult * br, QueryID queryID) override; void makeTurn(); diff --git a/AI/StupidAI/StupidAI.cpp b/AI/StupidAI/StupidAI.cpp index c8f495885..6cd6a15b2 100644 --- a/AI/StupidAI/StupidAI.cpp +++ b/AI/StupidAI/StupidAI.cpp @@ -14,6 +14,7 @@ #include "../../CCallback.h" #include "../../lib/CCreatureHandler.h" #include "../../lib/battle/BattleAction.h" +#include "../../lib/battle/BattleInfo.h" static std::shared_ptr cbc; @@ -53,12 +54,12 @@ void CStupidAI::initBattleInterface(std::shared_ptr ENV, std::share initBattleInterface(ENV, CB); } -void CStupidAI::actionFinished(const BattleAction &action) +void CStupidAI::actionFinished(const BattleID & battleID, const BattleAction &action) { print("actionFinished called"); } -void CStupidAI::actionStarted(const BattleAction &action) +void CStupidAI::actionStarted(const BattleID & battleID, const BattleAction &action) { print("actionStarted called"); } @@ -71,11 +72,11 @@ public: std::vector attackFrom; //for melee fight EnemyInfo(const CStack * _s) : s(_s), adi(0), adr(0) {} - void calcDmg(const CStack * ourStack) + void calcDmg(const BattleID & battleID, const CStack * ourStack) { // FIXME: provide distance info for Jousting bonus DamageEstimation retal; - DamageEstimation dmg = cbc->battleEstimateDamage(ourStack, s, 0, &retal); + DamageEstimation dmg = cbc->getBattle(battleID)->battleEstimateDamage(ourStack, s, 0, &retal); adi = static_cast((dmg.damage.min + dmg.damage.max) / 2); adr = static_cast((retal.damage.min + retal.damage.max) / 2); } @@ -91,14 +92,14 @@ bool isMoreProfitable(const EnemyInfo &ei1, const EnemyInfo& ei2) return (ei1.adi-ei1.adr) < (ei2.adi - ei2.adr); } -static bool willSecondHexBlockMoreEnemyShooters(const BattleHex &h1, const BattleHex &h2) +static bool willSecondHexBlockMoreEnemyShooters(const BattleID & battleID, const BattleHex &h1, const BattleHex &h2) { int shooters[2] = {0}; //count of shooters on hexes for(int i = 0; i < 2; i++) { for (auto & neighbour : (i ? h2 : h1).neighbouringTiles()) - if(const auto * s = cbc->battleGetUnitByPos(neighbour)) + if(const auto * s = cbc->getBattle(battleID)->battleGetUnitByPos(neighbour)) if(s->isShooter()) shooters[i]++; } @@ -106,16 +107,16 @@ static bool willSecondHexBlockMoreEnemyShooters(const BattleHex &h1, const Battl return shooters[0] < shooters[1]; } -void CStupidAI::yourTacticPhase(int distance) +void CStupidAI::yourTacticPhase(const BattleID & battleID, int distance) { - cb->battleMakeTacticAction(BattleAction::makeEndOFTacticPhase(cb->battleGetTacticsSide())); + cb->battleMakeTacticAction(battleID, BattleAction::makeEndOFTacticPhase(cb->getBattle(battleID)->battleGetTacticsSide())); } -void CStupidAI::activeStack( const CStack * stack ) +void CStupidAI::activeStack(const BattleID & battleID, const CStack * stack) { //boost::this_thread::sleep_for(boost::chrono::seconds(2)); print("activeStack called for " + stack->nodeName()); - ReachabilityInfo dists = cb->getReachability(stack); + ReachabilityInfo dists = cb->getBattle(battleID)->getReachability(stack); std::vector enemiesShootable, enemiesReachable, enemiesUnreachable; if(stack->creatureId() == CreatureID::CATAPULT) @@ -128,24 +129,24 @@ void CStupidAI::activeStack( const CStack * stack ) attack.side = side; attack.stackNumber = stack->unitId(); - cb->battleMakeUnitAction(attack); + cb->battleMakeUnitAction(battleID, attack); return; } else if(stack->hasBonusOfType(BonusType::SIEGE_WEAPON)) { - cb->battleMakeUnitAction(BattleAction::makeDefend(stack)); + cb->battleMakeUnitAction(battleID, BattleAction::makeDefend(stack)); return; } - for (const CStack *s : cb->battleGetStacks(CBattleCallback::ONLY_ENEMY)) + for (const CStack *s : cb->getBattle(battleID)->battleGetStacks(CBattleInfoEssentials::ONLY_ENEMY)) { - if(cb->battleCanShoot(stack, s->getPosition())) + if(cb->getBattle(battleID)->battleCanShoot(stack, s->getPosition())) { enemiesShootable.push_back(s); } else { - std::vector avHexes = cb->battleGetAvailableHexes(stack, false); + std::vector avHexes = cb->getBattle(battleID)->battleGetAvailableHexes(stack, false); for (BattleHex hex : avHexes) { @@ -168,21 +169,23 @@ void CStupidAI::activeStack( const CStack * stack ) } for ( auto & enemy : enemiesReachable ) - enemy.calcDmg( stack ); + enemy.calcDmg(battleID, stack); for ( auto & enemy : enemiesShootable ) - enemy.calcDmg( stack ); + enemy.calcDmg(battleID, stack); if(enemiesShootable.size()) { const EnemyInfo &ei= *std::max_element(enemiesShootable.begin(), enemiesShootable.end(), isMoreProfitable); - cb->battleMakeUnitAction(BattleAction::makeShotAttack(stack, ei.s)); + cb->battleMakeUnitAction(battleID, BattleAction::makeShotAttack(stack, ei.s)); return; } else if(enemiesReachable.size()) { const EnemyInfo &ei= *std::max_element(enemiesReachable.begin(), enemiesReachable.end(), &isMoreProfitable); - cb->battleMakeUnitAction(BattleAction::makeMeleeAttack(stack, ei.s->getPosition(), *std::max_element(ei.attackFrom.begin(), ei.attackFrom.end(), &willSecondHexBlockMoreEnemyShooters))); + BattleHex targetHex = *std::max_element(ei.attackFrom.begin(), ei.attackFrom.end(), [&](auto a, auto b) { return willSecondHexBlockMoreEnemyShooters(battleID, a, b);}); + + cb->battleMakeUnitAction(battleID, BattleAction::makeMeleeAttack(stack, ei.s->getPosition(), targetHex)); return; } else if(enemiesUnreachable.size()) //due to #955 - a buggy battle may occur when there are no enemies @@ -194,26 +197,26 @@ void CStupidAI::activeStack( const CStack * stack ) if(dists.distToNearestNeighbour(stack, closestEnemy->s) < GameConstants::BFIELD_SIZE) { - cb->battleMakeUnitAction(goTowards(stack, closestEnemy->s->getAttackableHexes(stack))); + cb->battleMakeUnitAction(battleID, goTowards(battleID, stack, closestEnemy->s->getAttackableHexes(stack))); return; } } - cb->battleMakeUnitAction(BattleAction::makeDefend(stack)); + cb->battleMakeUnitAction(battleID, BattleAction::makeDefend(stack)); return; } -void CStupidAI::battleAttack(const BattleAttack *ba) +void CStupidAI::battleAttack(const BattleID & battleID, const BattleAttack *ba) { print("battleAttack called"); } -void CStupidAI::battleStacksAttacked(const std::vector & bsa, bool ranged) +void CStupidAI::battleStacksAttacked(const BattleID & battleID, const std::vector & bsa, bool ranged) { print("battleStacksAttacked called"); } -void CStupidAI::battleEnd(const BattleResult *br, QueryID queryID) +void CStupidAI::battleEnd(const BattleID & battleID, const BattleResult *br, QueryID queryID) { print("battleEnd called"); } @@ -223,38 +226,38 @@ void CStupidAI::battleEnd(const BattleResult *br, QueryID queryID) // print("battleResultsApplied called"); // } -void CStupidAI::battleNewRoundFirst(int round) +void CStupidAI::battleNewRoundFirst(const BattleID & battleID, int round) { print("battleNewRoundFirst called"); } -void CStupidAI::battleNewRound(int round) +void CStupidAI::battleNewRound(const BattleID & battleID, int round) { print("battleNewRound called"); } -void CStupidAI::battleStackMoved(const CStack * stack, std::vector dest, int distance, bool teleport) +void CStupidAI::battleStackMoved(const BattleID & battleID, const CStack * stack, std::vector dest, int distance, bool teleport) { print("battleStackMoved called"); } -void CStupidAI::battleSpellCast(const BattleSpellCast *sc) +void CStupidAI::battleSpellCast(const BattleID & battleID, const BattleSpellCast *sc) { print("battleSpellCast called"); } -void CStupidAI::battleStacksEffectsSet(const SetStackEffect & sse) +void CStupidAI::battleStacksEffectsSet(const BattleID & battleID, const SetStackEffect & sse) { print("battleStacksEffectsSet called"); } -void CStupidAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool Side, bool replayAllowed) +void CStupidAI::battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool Side, bool replayAllowed) { print("battleStart called"); side = Side; } -void CStupidAI::battleCatapultAttacked(const CatapultAttack & ca) +void CStupidAI::battleCatapultAttacked(const BattleID & battleID, const CatapultAttack & ca) { print("battleCatapultAttacked called"); } @@ -264,10 +267,10 @@ void CStupidAI::print(const std::string &text) const logAi->trace("CStupidAI [%p]: %s", this, text); } -BattleAction CStupidAI::goTowards(const CStack * stack, std::vector hexes) const +BattleAction CStupidAI::goTowards(const BattleID & battleID, const CStack * stack, std::vector hexes) const { - auto reachability = cb->getReachability(stack); - auto avHexes = cb->battleGetAvailableHexes(reachability, stack, false); + auto reachability = cb->getBattle(battleID)->getReachability(stack); + auto avHexes = cb->getBattle(battleID)->battleGetAvailableHexes(reachability, stack, false); if(!avHexes.size() || !hexes.size()) //we are blocked or dest is blocked { diff --git a/AI/StupidAI/StupidAI.h b/AI/StupidAI/StupidAI.h index 6b0d230ad..20776bbc4 100644 --- a/AI/StupidAI/StupidAI.h +++ b/AI/StupidAI/StupidAI.h @@ -11,6 +11,7 @@ #include "../../lib/battle/BattleHex.h" #include "../../lib/battle/ReachabilityInfo.h" +#include "../../lib/CGameInterface.h" class EnemyInfo; @@ -30,25 +31,26 @@ public: void initBattleInterface(std::shared_ptr ENV, std::shared_ptr CB) override; void initBattleInterface(std::shared_ptr ENV, std::shared_ptr CB, AutocombatPreferences autocombatPreferences) override; - void actionFinished(const BattleAction &action) override;//occurs AFTER every action taken by any stack or by the hero - void actionStarted(const BattleAction &action) override;//occurs BEFORE every action taken by any stack or by the hero - void activeStack(const CStack * stack) override; //called when it's turn of that stack - void yourTacticPhase(int distance) override; - void battleAttack(const BattleAttack *ba) override; //called when stack is performing attack - void battleStacksAttacked(const std::vector & bsa, bool ranged) override; //called when stack receives damage (after battleAttack()) - void battleEnd(const BattleResult *br, QueryID queryID) override; + void actionFinished(const BattleID & battleID, const BattleAction &action) override;//occurs AFTER every action taken by any stack or by the hero + void actionStarted(const BattleID & battleID, const BattleAction &action) override;//occurs BEFORE every action taken by any stack or by the hero + void activeStack(const BattleID & battleID, const CStack * stack) override; //called when it's turn of that stack + void yourTacticPhase(const BattleID & battleID, int distance) override; + + void battleAttack(const BattleID & battleID, const BattleAttack *ba) override; //called when stack is performing attack + 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(int round) override; //called at the beginning of each turn before changes are applied; - 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 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 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 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 BattleTriggerEffect & bte) override; - 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 battleCatapultAttacked(const CatapultAttack & ca) override; //called when catapult makes an attack + 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 battleCatapultAttacked(const BattleID & battleID, const CatapultAttack & ca) override; //called when catapult makes an attack private: - BattleAction goTowards(const CStack * stack, std::vector hexes) const; + BattleAction goTowards(const BattleID & battleID, const CStack * stack, std::vector hexes) const; }; diff --git a/AI/VCAI/VCAI.cpp b/AI/VCAI/VCAI.cpp index a150e7c6a..5070ca2d7 100644 --- a/AI/VCAI/VCAI.cpp +++ b/AI/VCAI/VCAI.cpp @@ -1577,22 +1577,22 @@ void VCAI::completeGoal(Goals::TSubgoal goal) } -void VCAI::battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed) +void VCAI::battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed) { NET_EVENT_HANDLER; assert(!playerID.isValidPlayer() || status.getBattle() == UPCOMING_BATTLE); status.setBattle(ONGOING_BATTLE); const CGObjectInstance * presumedEnemy = vstd::backOrNull(cb->getVisitableObjs(tile)); //may be nullptr in some very are cases -> eg. visited monolith and fighting with an enemy at the FoW covered exit battlename = boost::str(boost::format("Starting battle of %s attacking %s at %s") % (hero1 ? hero1->getNameTranslated() : "a army") % (presumedEnemy ? presumedEnemy->getObjectName() : "unknown enemy") % tile.toString()); - CAdventureAI::battleStart(army1, army2, tile, hero1, hero2, side, replayAllowed); + CAdventureAI::battleStart(battleID, army1, army2, tile, hero1, hero2, side, replayAllowed); } -void VCAI::battleEnd(const BattleResult * br, QueryID queryID) +void VCAI::battleEnd(const BattleID & battleID, const BattleResult * br, QueryID queryID) { NET_EVENT_HANDLER; assert(status.getBattle() == ONGOING_BATTLE); status.setBattle(ENDING_BATTLE); - bool won = br->winner == myCb->battleGetMySide(); + bool won = br->winner == myCb->getBattle(battleID)->battleGetMySide(); logAi->debug("Player %d (%s): I %s the %s!", playerID, playerID.toString(), (won ? "won" : "lost"), battlename); battlename.clear(); @@ -1605,7 +1605,7 @@ void VCAI::battleEnd(const BattleResult * br, QueryID queryID) answerQuery(queryID, confirmAction); }); } - CAdventureAI::battleEnd(br, queryID); + CAdventureAI::battleEnd(battleID, br, queryID); } void VCAI::waitTillFree() @@ -2894,7 +2894,7 @@ bool shouldVisit(HeroPtr h, const CGObjectInstance * obj) return true; } -std::optional VCAI::makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) +std::optional VCAI::makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState) { return std::nullopt; } diff --git a/AI/VCAI/VCAI.h b/AI/VCAI/VCAI.h index ea341b4af..5b5df2ffa 100644 --- a/AI/VCAI/VCAI.h +++ b/AI/VCAI/VCAI.h @@ -201,9 +201,9 @@ public: void showMarketWindow(const IMarket * market, const CGHeroInstance * visitor) override; void showWorldViewEx(const std::vector & objectPositions, bool showTerrain) override; - void battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed) override; - void battleEnd(const BattleResult * br, QueryID queryID) override; - std::optional makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) override; + void battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed) override; + void battleEnd(const BattleID & battleID, const BattleResult * br, QueryID queryID) override; + std::optional makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState) override; void makeTurn(); void mainLoop(); diff --git a/CCallback.cpp b/CCallback.cpp index 1b1b034b9..43970c048 100644 --- a/CCallback.cpp +++ b/CCallback.cpp @@ -393,7 +393,7 @@ void CBattleCallback::battleMakeTacticAction( const BattleAction & action ) sendRequest(&ma); } -std::optional CBattleCallback::makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) +std::optional CBattleCallback::makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState) { - return cl->playerint[getPlayerID().value()]->makeSurrenderRetreatDecision(battleState); + return cl->playerint[getPlayerID().value()]->makeSurrenderRetreatDecision(battleID< battleState); } diff --git a/CCallback.h b/CCallback.h index 062ef8185..95b3f4493 100644 --- a/CCallback.h +++ b/CCallback.h @@ -53,10 +53,12 @@ public: bool waitTillRealize = false; //if true, request functions will return after they are realized by server bool unlockGsWhenWaiting = false;//if true after sending each request, gs mutex will be unlocked so the changes can be applied; NOTICE caller must have gs mx locked prior to any call to actiob callback! //battle - virtual void battleMakeSpellAction(const BattleAction & action) = 0; - virtual void battleMakeUnitAction(const BattleAction & action) = 0; - virtual void battleMakeTacticAction(const BattleAction & action) = 0; - virtual std::optional makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) = 0; + virtual void battleMakeSpellAction(const BattleID & battleID, const BattleAction & action) = 0; + virtual void battleMakeUnitAction(const BattleID & battleID, const BattleAction & action) = 0; + virtual void battleMakeTacticAction(const BattleID & battleID, const BattleAction & action) = 0; + virtual std::optional makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState) = 0; + + virtual std::shared_ptr getBattle(const BattleID & battleID) = 0; }; class IGameActionCallback @@ -108,18 +110,25 @@ public: virtual void bulkMoveArtifacts(ObjectInstanceID srcHero, ObjectInstanceID dstHero, bool swap) = 0; }; -class CBattleCallback : public IBattleCallback, public CPlayerBattleCallback +class CBattleCallback : public IBattleCallback { + std::map> activeBattles; + 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); - void battleMakeSpellAction(const BattleAction & action) override;//for casting spells by hero - DO NOT use it for moving active stack - void battleMakeUnitAction(const BattleAction & action) override; - void battleMakeTacticAction(const BattleAction & action) override; // performs tactic phase actions - std::optional makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) override; + 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; + + void onBattleStarted(const BattleID & battleID); + void onBattleEnded(const BattleID & battleID); #if SCRIPTING_ENABLED scripting::Pool * getContextPool() const override; @@ -129,9 +138,7 @@ public: friend class CClient; }; -class CCallback : public CPlayerSpecificInfoCallback, - public IGameActionCallback, - public CBattleCallback +class CCallback : public CPlayerSpecificInfoCallback, public CBattleCallback, public IGameActionCallback { public: CCallback(CGameState * GS, std::optional Player, CClient * C); diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index cddcfe2c9..0866394fb 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -1000,7 +1000,7 @@ void CPlayerInterface::battleGateStateChanged(const EGateState state) battleInt->gateStateChanged(state); } -void CPlayerInterface::yourTacticPhase(int distance) +void CPlayerInterface::yourTacticPhase(const BattleID & battleID, int distance) { EVENT_HANDLER_CALLED_BY_CLIENT; } @@ -2126,7 +2126,7 @@ void CPlayerInterface::showWorldViewEx(const std::vector& objectP adventureInt->openWorldView(objectPositions, showTerrain ); } -std::optional CPlayerInterface::makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) +std::optional CPlayerInterface::makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState) { return std::nullopt; } diff --git a/client/CPlayerInterface.h b/client/CPlayerInterface.h index c5048637f..4a74fd8d2 100644 --- a/client/CPlayerInterface.h +++ b/client/CPlayerInterface.h @@ -171,8 +171,8 @@ protected: // Call-ins from server, should not be called directly, but only via 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 yourTacticPhase(int distance) override; - std::optional makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) override; + void yourTacticPhase(const BattleID & battleID, int distance) override; + std::optional makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState) override; public: // public interface for use by client via LOCPLINT access diff --git a/client/Client.cpp b/client/Client.cpp index 931dd4e36..44652aeb7 100644 --- a/client/Client.cpp +++ b/client/Client.cpp @@ -634,7 +634,7 @@ void CClient::battleStarted(const BattleInfo * info) auto tacticianColor = info->sides[info->tacticsSide].color; if (vstd::contains(battleints, tacticianColor)) - battleints[tacticianColor]->yourTacticPhase(info->tacticDistance); + battleints[tacticianColor]->yourTacticPhase(info->battleID, info->tacticDistance); } } diff --git a/client/Client.h b/client/Client.h index 55dc5e708..48816798f 100644 --- a/client/Client.h +++ b/client/Client.h @@ -13,7 +13,6 @@ #include #include "../lib/IGameCallback.h" -#include "../lib/battle/CBattleInfoCallback.h" VCMI_LIB_NAMESPACE_BEGIN @@ -105,12 +104,12 @@ public: const Services * services() const override; vstd::CLoggerBase * logger() const override; events::EventBus * eventBus() const override; - const BattleCb * battle() const override; + const BattleCb * battle(const BattleID & battle) const override; const GameCb * game() const override; }; /// Class which handles client - server logic -class CClient : public IGameCallback, public CBattleInfoCallback, public Environment +class CClient : public IGameCallback, public Environment { public: std::map> playerint; @@ -124,7 +123,7 @@ public: ~CClient(); const Services * services() const override; - const BattleCb * battle() const override; + const BattleCb * battle(const BattleID & battle) const override; const GameCb * game() const override; vstd::CLoggerBase * logger() const override; events::EventBus * eventBus() const override; diff --git a/lib/CGameInterface.cpp b/lib/CGameInterface.cpp index 5b052d3c8..3148aa65d 100644 --- a/lib/CGameInterface.cpp +++ b/lib/CGameInterface.cpp @@ -157,90 +157,90 @@ CGlobalAI::CGlobalAI() human = false; } -void CAdventureAI::battleNewRound(int round) +void CAdventureAI::battleNewRound(const BattleID & battleID, int round) { - battleAI->battleNewRound(round); + battleAI->battleNewRound(battleID, round); } -void CAdventureAI::battleCatapultAttacked(const CatapultAttack & ca) +void CAdventureAI::battleCatapultAttacked(const BattleID & battleID, const CatapultAttack & ca) { - battleAI->battleCatapultAttacked(ca); + battleAI->battleCatapultAttacked(battleID, ca); } -void CAdventureAI::battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, +void CAdventureAI::battleStart(const BattleID & battleID, const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side, bool replayAllowed) { assert(!battleAI); assert(cbc); battleAI = CDynLibHandler::getNewBattleAI(getBattleAIName()); battleAI->initBattleInterface(env, cbc); - battleAI->battleStart(army1, army2, tile, hero1, hero2, side, replayAllowed); + battleAI->battleStart(battleID, army1, army2, tile, hero1, hero2, side, replayAllowed); } -void CAdventureAI::battleStacksAttacked(const std::vector & bsa, bool ranged) +void CAdventureAI::battleStacksAttacked(const BattleID & battleID, const std::vector & bsa, bool ranged) { - battleAI->battleStacksAttacked(bsa, ranged); + battleAI->battleStacksAttacked(battleID, bsa, ranged); } -void CAdventureAI::actionStarted(const BattleAction & action) +void CAdventureAI::actionStarted(const BattleID & battleID, const BattleAction & action) { - battleAI->actionStarted(action); + battleAI->actionStarted(battleID, action); } -void CAdventureAI::battleNewRoundFirst(int round) +void CAdventureAI::battleNewRoundFirst(const BattleID & battleID, int round) { - battleAI->battleNewRoundFirst(round); + battleAI->battleNewRoundFirst(battleID, round); } -void CAdventureAI::actionFinished(const BattleAction & action) +void CAdventureAI::actionFinished(const BattleID & battleID, const BattleAction & action) { - battleAI->actionFinished(action); + battleAI->actionFinished(battleID, action); } -void CAdventureAI::battleStacksEffectsSet(const SetStackEffect & sse) +void CAdventureAI::battleStacksEffectsSet(const BattleID & battleID, const SetStackEffect & sse) { - battleAI->battleStacksEffectsSet(sse); + battleAI->battleStacksEffectsSet(battleID, sse); } -void CAdventureAI::battleObstaclesChanged(const std::vector & obstacles) +void CAdventureAI::battleObstaclesChanged(const BattleID & battleID, const std::vector & obstacles) { - battleAI->battleObstaclesChanged(obstacles); + battleAI->battleObstaclesChanged(battleID, obstacles); } -void CAdventureAI::battleStackMoved(const CStack * stack, std::vector dest, int distance, bool teleport) +void CAdventureAI::battleStackMoved(const BattleID & battleID, const CStack * stack, std::vector dest, int distance, bool teleport) { - battleAI->battleStackMoved(stack, dest, distance, teleport); + battleAI->battleStackMoved(battleID, stack, dest, distance, teleport); } -void CAdventureAI::battleAttack(const BattleAttack * ba) +void CAdventureAI::battleAttack(const BattleID & battleID, const BattleAttack * ba) { - battleAI->battleAttack(ba); + battleAI->battleAttack(battleID, ba); } -void CAdventureAI::battleSpellCast(const BattleSpellCast * sc) +void CAdventureAI::battleSpellCast(const BattleID & battleID, const BattleSpellCast * sc) { - battleAI->battleSpellCast(sc); + battleAI->battleSpellCast(battleID, sc); } -void CAdventureAI::battleEnd(const BattleResult * br, QueryID queryID) +void CAdventureAI::battleEnd(const BattleID & battleID, const BattleResult * br, QueryID queryID) { - battleAI->battleEnd(br, queryID); + battleAI->battleEnd(battleID, br, queryID); battleAI.reset(); } -void CAdventureAI::battleUnitsChanged(const std::vector & units) +void CAdventureAI::battleUnitsChanged(const BattleID & battleID, const std::vector & units) { - battleAI->battleUnitsChanged(units); + battleAI->battleUnitsChanged(battleID, units); } -void CAdventureAI::activeStack(const CStack * stack) +void CAdventureAI::activeStack(const BattleID & battleID, const CStack * stack) { - battleAI->activeStack(stack); + battleAI->activeStack(battleID, stack); } -void CAdventureAI::yourTacticPhase(int distance) +void CAdventureAI::yourTacticPhase(const BattleID & battleID, int distance) { - battleAI->yourTacticPhase(distance); + battleAI->yourTacticPhase(battleID, distance); } void CAdventureAI::saveGame(BinarySerializer & h, const int version) /*saving */ diff --git a/lib/CGameInterface.h b/lib/CGameInterface.h index 24eb0a11f..2f9fe192f 100644 --- a/lib/CGameInterface.h +++ b/lib/CGameInterface.h @@ -80,8 +80,8 @@ public: virtual void initBattleInterface(std::shared_ptr ENV, std::shared_ptr CB, AutocombatPreferences autocombatPreferences){}; //battle call-ins - virtual void activeStack(const CStack * stack)=0; //called when it's turn of that stack - virtual void yourTacticPhase(int distance)=0; //called when interface has opportunity to use Tactics skill -> use cb->battleMakeTacticAction from this function + virtual void activeStack(const BattleID & battleID, const CStack * stack)=0; //called when it's turn of that stack + virtual void yourTacticPhase(const BattleID & battleID, int distance)=0; //called when interface has opportunity to use Tactics skill -> use cb->battleMakeTacticAction from this function }; /// Central class for managing human player / AI interface logic @@ -109,7 +109,7 @@ public: virtual void showWorldViewEx(const std::vector & objectPositions, bool showTerrain){}; - virtual std::optional makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) = 0; + virtual std::optional makeSurrenderRetreatDecision(const BattleID & battleID, const BattleStateInfoForRetreat & battleState) = 0; virtual void saveGame(BinarySerializer & h, const int version) = 0; virtual void loadGame(BinaryDeserializer & h, const int version) = 0; @@ -144,22 +144,23 @@ public: virtual std::string getBattleAIName() const = 0; //has to return name of the battle AI to be used //battle interface - virtual void activeStack(const CStack * stack) override; - virtual void yourTacticPhase(int distance) override; - virtual void battleNewRound(int round) override; - virtual void battleCatapultAttacked(const CatapultAttack & ca) override; - virtual void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side, bool replayAllowed) override; - virtual void battleStacksAttacked(const std::vector & bsa, bool ranged) override; - virtual void actionStarted(const BattleAction &action) override; - virtual void battleNewRoundFirst(int round) override; - virtual void actionFinished(const BattleAction &action) override; - virtual void battleStacksEffectsSet(const SetStackEffect & sse) override; - virtual void battleObstaclesChanged(const std::vector & obstacles) override; - virtual void battleStackMoved(const CStack * stack, std::vector dest, int distance, bool teleport) override; - virtual void battleAttack(const BattleAttack *ba) override; - virtual void battleSpellCast(const BattleSpellCast *sc) override; - virtual void battleEnd(const BattleResult *br, QueryID queryID) override; - virtual void battleUnitsChanged(const std::vector & units) override; + 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 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 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; + virtual void battleStackMoved(const BattleID & battleID, const CStack * stack, std::vector dest, int distance, bool teleport) override; + virtual void battleAttack(const BattleID & battleID, const BattleAttack *ba) override; + virtual void battleSpellCast(const BattleID & battleID, const BattleSpellCast *sc) override; + virtual void battleEnd(const BattleID & battleID, const BattleResult *br, QueryID queryID) override; + virtual void battleUnitsChanged(const BattleID & battleID, const std::vector & units) override; virtual void saveGame(BinarySerializer & h, const int version) override; virtual void loadGame(BinaryDeserializer & h, const int version) override; diff --git a/lib/IGameEventsReceiver.h b/lib/IGameEventsReceiver.h index a19c9f11e..8139ee674 100644 --- a/lib/IGameEventsReceiver.h +++ b/lib/IGameEventsReceiver.h @@ -56,24 +56,24 @@ class UnitChanges; class DLL_LINKAGE IBattleEventsReceiver { public: - virtual void actionFinished(const BattleAction &action){};//occurs AFTER every action taken by any stack or by the hero - virtual void actionStarted(const BattleAction &action){};//occurs BEFORE every action taken by any stack or by the hero - virtual void battleAttack(const BattleAttack *ba){}; //called when stack is performing attack - virtual void battleStacksAttacked(const std::vector & bsa, bool ranged){}; //called when stack receives damage (after battleAttack()) - virtual void battleEnd(const BattleResult *br, QueryID queryID){}; - virtual void battleNewRoundFirst(int round){}; //called at the beginning of each turn before changes are applied; - virtual void battleNewRound(int round){}; //called at the beginning of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn - virtual void battleLogMessage(const std::vector & lines){}; - virtual void battleStackMoved(const CStack * stack, std::vector dest, int distance, bool teleport){}; - virtual void battleSpellCast(const BattleSpellCast *sc){}; - virtual void battleStacksEffectsSet(const SetStackEffect & sse){};//called when a specific effect is set to stacks - virtual void battleTriggerEffect(const BattleTriggerEffect & bte){}; //called for various one-shot effects - virtual void battleStartBefore(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2) {}; //called just before battle start - virtual void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side, bool replayAllowed){}; //called by engine when battle starts; side=0 - left, side=1 - right - virtual void battleUnitsChanged(const std::vector & units){}; - virtual void battleObstaclesChanged(const std::vector & obstacles){}; - virtual void battleCatapultAttacked(const CatapultAttack & ca){}; //called when catapult makes an attack - virtual void battleGateStateChanged(const EGateState state){}; + virtual void actionFinished(const BattleID & battleID, const BattleAction &action){};//occurs AFTER every action taken by any stack or by the hero + virtual void actionStarted(const BattleID & battleID, const BattleAction &action){};//occurs BEFORE every action taken by any stack or by the hero + 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 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){}; + virtual void battleStacksEffectsSet(const BattleID & battleID, const SetStackEffect & sse){};//called when a specific effect is set to stacks + virtual void battleTriggerEffect(const BattleID & battleID, const BattleTriggerEffect & bte){}; //called for various one-shot effects + virtual void battleStartBefore(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2) {}; //called just before battle start + virtual void battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side, bool replayAllowed){}; //called by engine when battle starts; side=0 - left, side=1 - right + virtual void battleUnitsChanged(const BattleID & battleID, const std::vector & units){}; + virtual void battleObstaclesChanged(const BattleID & battleID, const std::vector & obstacles){}; + virtual void battleCatapultAttacked(const BattleID & battleID, const CatapultAttack & ca){}; //called when catapult makes an attack + virtual void battleGateStateChanged(const BattleID & battleID, const EGateState state){}; }; class DLL_LINKAGE IGameEventsReceiver