diff --git a/AI/StupidAI/StupidAI.cpp b/AI/StupidAI/StupidAI.cpp index e0733d2b4..b6825dbee 100644 --- a/AI/StupidAI/StupidAI.cpp +++ b/AI/StupidAI/StupidAI.cpp @@ -55,7 +55,7 @@ struct EnemyInfo } }; -bool isMoreProfitable(const EnemyInfo &ei1, const EnemyInfo& ei2) +bool isMoreProfitable(const EnemyInfo &ei1, const EnemyInfo& ei2) { return (ei1.adi-ei1.adr) < (ei2.adi - ei2.adr); } @@ -175,68 +175,68 @@ void CStupidAI::battleStacksAttacked(const std::vector & bs print("battleStacksAttacked called"); } -void CStupidAI::battleEnd(const BattleResult *br) +void CStupidAI::battleEnd(const BattleResult *br) { print("battleEnd called"); } -// void CStupidAI::battleResultsApplied() +// void CStupidAI::battleResultsApplied() // { // print("battleResultsApplied called"); // } -void CStupidAI::battleNewRoundFirst(int round) +void CStupidAI::battleNewRoundFirst(int round) { print("battleNewRoundFirst called"); } -void CStupidAI::battleNewRound(int round) +void CStupidAI::battleNewRound(int round) { print("battleNewRound called"); } -void CStupidAI::battleStackMoved(const CStack * stack, std::vector dest, int distance) +void CStupidAI::battleStackMoved(const CStack * stack, std::vector dest, int distance) { print("battleStackMoved called");; } -void CStupidAI::battleSpellCast(const BattleSpellCast *sc) +void CStupidAI::battleSpellCast(const BattleSpellCast *sc) { print("battleSpellCast called"); } -void CStupidAI::battleStacksEffectsSet(const SetStackEffect & sse) +void CStupidAI::battleStacksEffectsSet(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) +void CStupidAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool Side) { print("battleStart called"); side = Side; } -void CStupidAI::battleStacksHealedRes(const std::vector > & healedStacks, bool lifeDrain, bool tentHeal, si32 lifeDrainFrom) +void CStupidAI::battleStacksHealedRes(const std::vector > & healedStacks, bool lifeDrain, bool tentHeal, si32 lifeDrainFrom) { print("battleStacksHealedRes called"); } -void CStupidAI::battleNewStackAppeared(const CStack * stack) +void CStupidAI::battleNewStackAppeared(const CStack * stack) { print("battleNewStackAppeared called"); } -void CStupidAI::battleObstaclesRemoved(const std::set & removedObstacles) +void CStupidAI::battleObstaclesRemoved(const std::set & removedObstacles) { print("battleObstaclesRemoved called"); } -void CStupidAI::battleCatapultAttacked(const CatapultAttack & ca) +void CStupidAI::battleCatapultAttacked(const CatapultAttack & ca) { print("battleCatapultAttacked called"); } -void CStupidAI::battleStacksRemoved(const BattleStacksRemoved & bsr) +void CStupidAI::battleStacksRemoved(const BattleStacksRemoved & bsr) { print("battleStacksRemoved called"); } @@ -254,7 +254,7 @@ BattleAction CStupidAI::goTowards(const CStack * stack, BattleHex destination) if(vstd::contains(avHexes, destination)) return BattleAction::makeMove(stack, destination); - + auto destNeighbours = destination.neighbouringTiles(); if(vstd::contains_if(destNeighbours, [&](BattleHex n) { return stack->coversPos(destination); })) { @@ -278,8 +278,8 @@ BattleAction CStupidAI::goTowards(const CStack * stack, BattleHex destination) auto distToDestNeighbour = [&](BattleHex hex) -> int { auto nearestNeighbourToHex = vstd::minElementByFun(destNeighbours, [&](BattleHex a) - { - return BattleHex::getDistance(a, hex); + { + return BattleHex::getDistance(a, hex); }); return BattleHex::getDistance(*nearestNeighbourToHex, hex); diff --git a/Global.h b/Global.h index 48cf2cb81..dbc69c880 100644 --- a/Global.h +++ b/Global.h @@ -349,7 +349,7 @@ namespace vstd std::advance(itr, index); return *itr; } - + template void erase_if(Range &vec, Predicate pred) { @@ -373,7 +373,7 @@ namespace vstd auto minElementByFun(const ForwardRange& rng, ValueFunction vf) -> decltype(boost::begin(rng)) { typedef decltype(*boost::begin(rng)) ElemType; - return boost::min_element(rng, [&] (const ElemType &lhs, const ElemType &rhs) -> bool + return boost::min_element(rng, [&] (ElemType lhs, ElemType rhs) -> bool { return vf(lhs) < vf(rhs); }); diff --git a/lib/BattleState.cpp b/lib/BattleState.cpp index 8fa0ec581..0753bcf5b 100644 --- a/lib/BattleState.cpp +++ b/lib/BattleState.cpp @@ -45,19 +45,19 @@ const CStack * BattleInfo::getNextStack() const // void BattleInfo::getAccessibilityMap(bool *accessibility, bool twoHex, bool attackerOwned, bool addOccupiable, std::set & occupyable, bool flying, const CStack * stackToOmmit) const // { // memset(accessibility, 1, GameConstants::BFIELD_SIZE); //initialize array with trues -// +// // //removing accessibility for side columns of hexes // for(int v = 0; v < GameConstants::BFIELD_SIZE; ++v) // { // if( v % GameConstants::BFIELD_WIDTH == 0 || v % GameConstants::BFIELD_WIDTH == (GameConstants::BFIELD_WIDTH - 1) ) // accessibility[v] = false; // } -// +// // for(ui32 g=0; galive() || (stackToOmmit && stacks[g]->ID==stackToOmmit->ID) || stacks[g]->position < 0) //we don't want to lock position of this stack (eg. if it's a turret) // continue; -// +// // accessibility[stacks[g]->position] = false; // if(stacks[g]->doubleWide()) //if it's a double hex creature // { @@ -76,7 +76,7 @@ const CStack * BattleInfo::getNextStack() const // accessibility[hex] = false; // } // } -// +// // //walls // if(siege > 0) // { @@ -85,7 +85,7 @@ const CStack * BattleInfo::getNextStack() const // { // accessibility[permanentlyLocked[b]] = false; // } -// +// // static const std::pair lockedIfNotDestroyed[] = //(which part of wall, which hex is blocked if this part of wall is not destroyed // {std::make_pair(2, BattleHex(182)), std::make_pair(3, BattleHex(130)), // std::make_pair(4, BattleHex(62)), std::make_pair(5, BattleHex(29))}; @@ -96,14 +96,14 @@ const CStack * BattleInfo::getNextStack() const // accessibility[lockedIfNotDestroyed[b].second] = false; // } // } -// +// // //gate // if(attackerOwned && si.wallState[7] < 3) //if it attacker's unit and gate is not destroyed // { // accessibility[95] = accessibility[96] = false; //block gate's hexes // } // } -// +// // //occupyability // if(addOccupiable && twoHex) // { @@ -131,7 +131,7 @@ const CStack * BattleInfo::getNextStack() const // { // if(flying && !lastPos) // return true; -// +// // if(twoHex) // { // //if given hex is accessible and appropriate adjacent one is free too @@ -146,13 +146,13 @@ const CStack * BattleInfo::getNextStack() const // void BattleInfo::makeBFS(BattleHex start, bool *accessibility, BattleHex *predecessor, int *dists, bool twoHex, bool attackerOwned, bool flying, bool fillPredecessors) const //both pointers must point to the at least 187-elements int arrays // { // std::set quicksands = getStoppers(!attackerOwned); -// +// // //inits // for(int b=0; b > hexq; //bfs queue (second filed used only if fillPredecessors is true) // hexq.push(std::make_pair(start, true)); // dists[hexq.front().first] = 0; @@ -164,7 +164,7 @@ const CStack * BattleInfo::getNextStack() const // hexq.pop(); // if(curHex.first != start && !flying && vstd::contains(quicksands, curHex.first)) //walking stack can't step past the quicksands // continue; -// +// // for(ui32 nr=0; nr=dists[curNext]) @@ -185,7 +185,7 @@ const CStack * BattleInfo::getNextStack() const // } // } // }; -// +// BattleHex BattleInfo::getClosestTile (bool attackerOwned, int initialPos, std::set & possibilities) const { @@ -224,18 +224,18 @@ BattleHex BattleInfo::getClosestTile (bool attackerOwned, int initialPos, std::s int BattleInfo::getAvaliableHex(TCreature creID, bool attackerOwned, int initialPos) const { bool twoHex = VLC->creh->creatures[creID]->isDoubleWide(); - bool flying = VLC->creh->creatures[creID]->isFlying(); + //bool flying = VLC->creh->creatures[creID]->isFlying(); - int pos; + int pos; if (initialPos > -1) pos = initialPos; else //summon elementals depending on player side - { - if (attackerOwned) - pos = 0; //top left - else - pos = GameConstants::BFIELD_WIDTH - 1; //top right - } + { + if (attackerOwned) + pos = 0; //top left + else + pos = GameConstants::BFIELD_WIDTH - 1; //top right + } auto accessibility = getAccesibility(); @@ -255,7 +255,7 @@ int BattleInfo::getAvaliableHex(TCreature creID, bool attackerOwned, int initial std::pair< std::vector, int > BattleInfo::getPath(BattleHex start, BattleHex dest, const CStack *stack) { auto reachability = getReachability(stack); - + if(reachability.predecessors[dest] == -1) //cannot reach destination { return std::make_pair(std::vector(), 0); @@ -450,16 +450,16 @@ CStack * BattleInfo::generateNewStack(const CStackBasicDescriptor &base, bool at } // std::pair BattleInfo::getNearestStack(const CStack * closest, boost::logic::tribool attackerOwned) const -// { +// { // bool ac[GameConstants::BFIELD_SIZE]; // std::set occupyable; -// +// // getAccessibilityMap(ac, closest->doubleWide(), closest->attackerOwned, false, occupyable, closest->hasBonusOfType(Bonus::FLYING), closest); -// +// // BattleHex predecessor[GameConstants::BFIELD_SIZE]; // int dist[GameConstants::BFIELD_SIZE]; // makeBFS(closest->position, ac, predecessor, dist, closest->doubleWide(), closest->attackerOwned, closest->hasBonusOfType(Bonus::FLYING), true); -// +// // std::vector< std::pair< std::pair, const CStack *> > stackPairs; //pairs <, stack> // for(int g=0; g 0) // { // std::vector< std::pair< std::pair, const CStack *> > minimalPairs; // minimalPairs.push_back(stackPairs[0]); -// +// // for(int b=1; b, const CStack *> minPair = minimalPairs[minimalPairs.size()/2]; -// +// // return std::make_pair(minPair.second, predecessor[minPair.first.second]); // } -// +// // return std::make_pair(NULL, BattleHex::INVALID); // } ui32 BattleInfo::calculateSpellBonus(ui32 baseDamage, const CSpell * sp, const CGHeroInstance * caster, const CStack * affectedCreature) const @@ -584,7 +584,7 @@ ui32 BattleInfo::calculateHealedHP(const CGHeroInstance * caster, const CSpell * int healedHealth; if (spell->id == Spells::SACRIFICE && sacrificedStack) healedHealth = (caster->getPrimSkillLevel(2) + sacrificedStack->MaxHealth() + spell->powers[caster->getSpellSchoolLevel(spell)]) * sacrificedStack->count; - else + else healedHealth = caster->getPrimSkillLevel(2) * spell->power + spell->powers[caster->getSpellSchoolLevel(spell)]; healedHealth = calculateSpellBonus(healedHealth, spell, caster, stack); return std::min(healedHealth, stack->MaxHealth() - stack->firstHPleft + (resurrect ? stack->baseAmount * stack->MaxHealth() : 0)); @@ -610,9 +610,9 @@ const CStack * BattleInfo::battleGetStack(BattleHex pos, bool onlyAlive) CStack * stack = NULL; for(ui32 g=0; gposition == pos - || (stacks[g]->doubleWide() - &&( (stacks[g]->attackerOwned && stacks[g]->position-1 == pos) + if(stacks[g]->position == pos + || (stacks[g]->doubleWide() + &&( (stacks[g]->attackerOwned && stacks[g]->position-1 == pos) || (!stacks[g]->attackerOwned && stacks[g]->position+1 == pos) ) ) ) { @@ -633,7 +633,7 @@ const CGHeroInstance * BattleInfo::battleGetOwner(const CStack * stack) const void BattleInfo::localInit() { belligerents[0]->battle = belligerents[1]->battle = this; - + BOOST_FOREACH(CArmedInstance *b, belligerents) b->attachTo(this); @@ -767,7 +767,7 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int battlefieldTyp curB->castSpells[0] = curB->castSpells[1] = 0; curB->sides[0] = armies[0]->tempOwner; curB->sides[1] = armies[1]->tempOwner; - if(curB->sides[1] == 254) + if(curB->sides[1] == 254) curB->sides[1] = 255; std::vector & stacks = (curB->stacks); @@ -830,7 +830,7 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int battlefieldTyp if(r.rand(1,100) <= 40) //put cliff-like obstacle { RangeGenerator obidgen(0, ABSOLUTE_OBSTACLES_COUNT-1, ourRand); - + try { auto obstPtr = make_shared(); @@ -911,7 +911,7 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int battlefieldTyp CGH::readBattlePositions(positions[3]["levels"], defenderTight); CGH::readBattlePositions(positions[4]["levels"], attackerCreBank); CGH::readBattlePositions(positions[5]["levels"], defenderCreBank); - + BOOST_FOREACH (auto position, config["commanderPositions"]["field"].Vector()) { commanderField.push_back (position.Float()); @@ -922,7 +922,7 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int battlefieldTyp } //battleStartpos read - int k = 0; //stack serial + int k = 0; //stack serial for(TSlots::const_iterator i = armies[0]->Slots().begin(); i!=armies[0]->Slots().end(); i++, k++) { int pos; @@ -953,7 +953,7 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, int terrain, int battlefieldTyp } //shifting positions of two-hex creatures - for(unsigned g=0; gdoubleWide() && stacks[g]->attackerOwned) @@ -1211,8 +1211,8 @@ std::vector BattleInfo::calculateResistedStacks(const CSpell * sp, const C for(auto it = affectedCreatures.begin(); it != affectedCreatures.end(); ++it) { if( (*it)->hasBonusOfType(Bonus::SPELL_IMMUNITY, sp->id) //100% sure spell immunity - || ( (*it)->count - 1 ) * (*it)->MaxHealth() + (*it)->firstHPleft - > + || ( (*it)->count - 1 ) * (*it)->MaxHealth() + (*it)->firstHPleft + > usedSpellPower * 25 + sp->powers[spellLevel] ) { @@ -1244,7 +1244,7 @@ int BattleInfo::getIdForNewStack() const if(stacks.size()) { //stacks vector may be sorted not by ID and they may be not contiguous -> find stack with max ID - auto highestIDStack = *std::max_element(stacks.begin(), stacks.end(), + auto highestIDStack = *std::max_element(stacks.begin(), stacks.end(), [](const CStack *a, const CStack *b) { return a->ID < b->ID; }); return highestIDStack->ID + 1; @@ -1294,7 +1294,7 @@ BattleInfo::BattleInfo() } CStack::CStack(const CStackInstance *Base, int O, int I, bool AO, int S) - : base(Base), ID(I), owner(O), slot(S), attackerOwned(AO), + : base(Base), ID(I), owner(O), slot(S), attackerOwned(AO), counterAttacks(1) { assert(base); @@ -1360,7 +1360,7 @@ ui32 CStack::Speed( int turn /*= 0*/ , bool useBind /* = false*/) const speed = ((100 + percentBonus) * speed)/100; //bind effect check - doesn't influence stack initiative - if (useBind && getEffect (Spells::BIND)) + if (useBind && getEffect (Spells::BIND)) { return 0; } @@ -1404,11 +1404,11 @@ const Bonus * CStack::getEffect( ui16 id, int turn /*= 0*/ ) const } void CStack::stackEffectToFeature(std::vector & sf, const Bonus & sse) -{ +{ si32 power = VLC->spellh->spells[sse.sid]->powers[sse.val]; switch(sse.sid) { - case 27: //shield + case 27: //shield sf.push_back(featureGenerator(Bonus::GENERAL_DAMAGE_REDUCTION, 0, power, sse.turnsRemain)); sf.back().sid = sse.sid; break; @@ -1627,7 +1627,7 @@ BattleHex CStack::occupiedHex(BattleHex assumedPos) const return assumedPos - 1; else return assumedPos + 1; - } + } else { return BattleHex::INVALID; @@ -1819,12 +1819,12 @@ bool CStack::isMeleeAttackPossible(const CStack * attacker, const CStack * defen && BattleHex::mutualPosition(attackerPos, defenderPos + (defender->attackerOwned ? -1 : 1)) >= 0) || (defender->doubleWide() && attacker->doubleWide()//back <=> back && BattleHex::mutualPosition(attackerPos + (attacker->attackerOwned ? -1 : 1), defenderPos + (defender->attackerOwned ? -1 : 1)) >= 0); - + } bool CStack::ableToRetaliate() const { - return alive() + return alive() && (counterAttacks > 0 || hasBonusOfType(Bonus::UNLIMITED_RETALIATIONS)) && !hasBonusOfType(Bonus::SIEGE_WEAPON) && !hasBonusOfType(Bonus::HYPNOTIZED) diff --git a/lib/CBattleCallback.cpp b/lib/CBattleCallback.cpp index 30e276524..275948ab6 100644 --- a/lib/CBattleCallback.cpp +++ b/lib/CBattleCallback.cpp @@ -8,6 +8,9 @@ #define RETURN_IF_NOT_BATTLE(X) if(!duringBattle()) {tlog1 << __FUNCTION__ << " called when no battle!\n"; return X; } +//allocate static member +const int ReachabilityInfo::INFINITE_DIST; + namespace SiegeStuffThatShouldBeMovedToHandlers // <=== TODO { static int lineToWallHex(int line) //returns hex with wall in given line (y coordinate) @@ -31,7 +34,7 @@ namespace SiegeStuffThatShouldBeMovedToHandlers // <=== TODO static int getMoatDamage(int townType) { //TODO move to config file - static const int dmgs[] = {70, 70, -1, + static const int dmgs[] = {70, 70, -1, 90, 70, 90, 70, 90, 70}; @@ -41,26 +44,26 @@ namespace SiegeStuffThatShouldBeMovedToHandlers // <=== TODO tlog1 << "No moat info for town " << townType << std::endl; return 0; } - static EWallParts::EWallParts hexToWallPart(BattleHex hex) + static EWallParts::EWallParts hexToWallPart(BattleHex hex) { //potentially attackable parts of wall // -2 - indestructible walls - static const std::pair attackable[] = + static const std::pair attackable[] = { - std::make_pair(50, EWallParts::KEEP), - std::make_pair(183, EWallParts::BOTTOM_TOWER), - std::make_pair(182, EWallParts::BOTTOM_WALL), + std::make_pair(50, EWallParts::KEEP), + std::make_pair(183, EWallParts::BOTTOM_TOWER), + std::make_pair(182, EWallParts::BOTTOM_WALL), std::make_pair(130, EWallParts::BELOW_GATE), - std::make_pair(62, EWallParts::OVER_GATE), - std::make_pair(29, EWallParts::UPPER_WAL), - std::make_pair(12, EWallParts::UPPER_TOWER), - std::make_pair(95, EWallParts::GATE), + std::make_pair(62, EWallParts::OVER_GATE), + std::make_pair(29, EWallParts::UPPER_WAL), + std::make_pair(12, EWallParts::UPPER_TOWER), + std::make_pair(95, EWallParts::GATE), std::make_pair(96, EWallParts::GATE), - std::make_pair(45, EWallParts::INDESTRUCTIBLE_PART), - std::make_pair(78, EWallParts::INDESTRUCTIBLE_PART), - std::make_pair(112, EWallParts::INDESTRUCTIBLE_PART), + std::make_pair(45, EWallParts::INDESTRUCTIBLE_PART), + std::make_pair(78, EWallParts::INDESTRUCTIBLE_PART), + std::make_pair(112, EWallParts::INDESTRUCTIBLE_PART), std::make_pair(147, EWallParts::INDESTRUCTIBLE_PART) - }; + }; for(int g = 0; g < ARRAY_COUNT(attackable); ++g) { @@ -105,7 +108,7 @@ std::vector > CBattleInfoEssentials::battleG { std::vector > ret; RETURN_IF_NOT_BATTLE(ret); - + if(!perspective) { //if no particular perspective request, use default one @@ -185,7 +188,7 @@ int CBattleInfoEssentials::battleGetMoatDmg() const const CGTownInstance * CBattleInfoEssentials::battleGetDefendedTown() const { RETURN_IF_NOT_BATTLE(nullptr); - + if(!getBattle() || getBattle()->town == NULL) return NULL; @@ -307,14 +310,14 @@ bool CBattleInfoEssentials::battleCanFlee(int player) const { RETURN_IF_NOT_BATTLE(false); ui8 mySide = playerToSide(player); - const CGHeroInstance *myHero = battleGetFightingHero(mySide), + const CGHeroInstance *myHero = battleGetFightingHero(mySide), *enemyHero = battleGetFightingHero(!mySide); //current player have no hero - if(!myHero) + if(!myHero) return false; - //TODo use bonus system + //TODo use bonus system //ie. one of heroes is wearing shakles of war if(NBonus::hasOfType(enemyHero, Bonus::ENEMY_CANT_ESCAPE) || NBonus::hasOfType(myHero, Bonus::ENEMY_CANT_ESCAPE)) return false; @@ -326,7 +329,7 @@ bool CBattleInfoEssentials::battleCanFlee(int player) const if(!(town->subID == 6 && town->hasBuilt(EBuilding::SPECIAL_1))) //not a stronghold with escape tunnel return false; } - + return true; } @@ -356,7 +359,7 @@ bool CBattleInfoEssentials::battleCanSurrender(int player) const bool CBattleInfoEssentials::battleHasHero(ui8 side) const { RETURN_IF_NOT_BATTLE(false); - assert(side >= 0 && side < 2); + assert(side < 2); return getBattle()->heroes[side]; } @@ -410,33 +413,33 @@ si8 CBattleInfoCallback::battleCanTeleportTo(const CStack * stack, BattleHex des // std::vector CBattleInfoCallback::battleGetDistances(const CStack * stack, BattleHex hex /*= BattleHex::INVALID*/, BattleHex * predecessors /*= NULL*/) // { // // FIXME - This method is broken, hex argument is not used. However AI depends on that wrong behaviour. -// +// // if(!hex.isValid()) // hex = stack->position; -// +// // std::vector ret(GameConstants::BFIELD_SIZE, -1); //fill initial ret with -1's -// +// // if(!hex.isValid()) //stack has bad position? probably castle turret, return initial values (they can't move) // return ret; -// +// // bool ac[GameConstants::BFIELD_SIZE] = {0}; // std::set occupyable; // getBattle()->getAccessibilityMap(ac, stack->doubleWide(), stack->attackerOwned, false, occupyable, stack->hasBonusOfType(Bonus::FLYING), stack); // BattleHex pr[GameConstants::BFIELD_SIZE]; // int dist[GameConstants::BFIELD_SIZE]; // getBattle()->makeBFS(stack->position, ac, pr, dist, stack->doubleWide(), stack->attackerOwned, stack->hasBonusOfType(Bonus::FLYING), false); -// +// // for(int i=0; i CBattleInfoCallback::battleGetAttackedHexes(const CStack* at } BOOST_FOREACH (BattleHex tile, at.friendlyCreaturePositions) { - if(const CStack * st = battleGetStackByPos(tile, true)) //friendly stacks can also be damaged by Dragon Breath + if(battleGetStackByPos(tile, true)) //friendly stacks can also be damaged by Dragon Breath { attackedHexes.insert(tile); } @@ -550,11 +553,11 @@ void CBattleInfoCallback::battleGetStackQueue(std::vector &out, }; //We'll split creatures with remaining movement to 4 buckets - // [0] - turrets/catapult, - // [1] - normal (unmoved) creatures, other war machines, - // [2] - waited cres that had morale, + // [0] - turrets/catapult, + // [1] - normal (unmoved) creatures, other war machines, + // [2] - waited cres that had morale, // [3] - rest of waited cres - std::vector phase[4]; + std::vector phase[4]; int toMove = 0; //how many stacks still has move const CStack *active = battleActiveStack(); @@ -697,7 +700,7 @@ std::vector CBattleInfoCallback::battleGetAvailableHexes(const CStack // Available hexes are already present in ret vector. auto availableNeighbor = boost::find_if(ret, [=] (BattleHex availableHex) { return BattleHex::mutualPosition(hex, availableHex) >= 0; }); - + return availableNeighbor != ret.end(); }; @@ -733,7 +736,7 @@ bool CBattleInfoCallback::battleCanShoot(const CStack * stack, BattleHex dest) c RETURN_IF_NOT_BATTLE(false); if(battleTacticDist()) //no shooting during tactics - return false; + return false; const CStack *dst = battleGetStackByPos(dest); @@ -757,17 +760,17 @@ bool CBattleInfoCallback::battleCanShoot(const CStack * stack, BattleHex dest) c return false; } -TDmgRange CBattleInfoCallback::calculateDmgRange(const CStack* attacker, const CStack* defender, bool shooting, +TDmgRange CBattleInfoCallback::calculateDmgRange(const CStack* attacker, const CStack* defender, bool shooting, ui8 charge, bool lucky, bool deathBlow, bool ballistaDoubleDmg) const { return calculateDmgRange(attacker, defender, attacker->count, shooting, charge, lucky, deathBlow, ballistaDoubleDmg); } -TDmgRange CBattleInfoCallback::calculateDmgRange( const CStack* attacker, const CStack* defender, TQuantity attackerCount, +TDmgRange CBattleInfoCallback::calculateDmgRange( const CStack* attacker, const CStack* defender, TQuantity attackerCount, bool shooting, ui8 charge, bool lucky, bool deathBlow, bool ballistaDoubleDmg ) const { double additiveBonus = 1.0, multBonus = 1.0, - minDmg = attacker->getMinDamage() * attackerCount, + minDmg = attacker->getMinDamage() * attackerCount, maxDmg = attacker->getMaxDamage() * attackerCount; if(attacker->getCreature()->idNumber == 149) //arrow turret @@ -794,8 +797,8 @@ TDmgRange CBattleInfoCallback::calculateDmgRange( const CStack* attacker, const }; - minDmg *= retreivePrimSkill(PrimarySkill::ATTACK) + 1; - maxDmg *= retreivePrimSkill(PrimarySkill::ATTACK) + 1; + minDmg *= retreivePrimSkill(PrimarySkill::ATTACK) + 1; + maxDmg *= retreivePrimSkill(PrimarySkill::ATTACK) + 1; } int attackDefenceDifference = 0; @@ -925,8 +928,8 @@ TDmgRange CBattleInfoCallback::calculateDmgRange( const CStack* attacker, const auto isAdvancedAirShield = [](const Bonus *bonus) { - return bonus->source == Bonus::SPELL_EFFECT - && bonus->sid == Spells::AIR_SHIELD + return bonus->source == Bonus::SPELL_EFFECT + && bonus->sid == Spells::AIR_SHIELD && bonus->val >= SecSkillLevel::ADVANCED; }; @@ -982,8 +985,8 @@ TDmgRange CBattleInfoCallback::battleEstimateDamage(const CStack * attacker, con RETURN_IF_NOT_BATTLE(std::make_pair(0, 0)); const bool shooting = battleCanShoot(attacker, defender->position); - const ui8 mySide = !attacker->attackerOwned; - + //const ui8 mySide = !attacker->attackerOwned; + TDmgRange ret = calculateDmgRange(attacker, defender, shooting, 0, false, false, false); if(retaliationDmg) @@ -1105,7 +1108,7 @@ ReachabilityInfo CBattleInfoCallback::makeBFS(const AccessibilityInfo &accessibi //walking stack can't step past the quicksands //TODO what if second hex of two-hex creature enters quicksand - if(curHex != params.startPosition && vstd::contains(quicksands, curHex)) + if(curHex != params.startPosition && vstd::contains(quicksands, curHex)) continue; const int costToNeighbour = ret.distances[curHex] + 1; @@ -1298,7 +1301,7 @@ AttackableTiles CBattleInfoCallback::getPotentiallyAttackableHexes(const CStack* BOOST_FOREACH (BattleHex tile, hexes) { //friendly stacks can also be damaged by Dragon Breath - if(const CStack * st = battleGetStackByPos(tile, true)) + if(battleGetStackByPos(tile, true)) at.friendlyCreaturePositions.insert(tile); } } @@ -1402,7 +1405,7 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleIsImmune(const C case Spells::BLESS: case Spells::CURSE: //undeads are immune to bless & curse if (subject->hasBonusOfType(Bonus::UNDEAD)) - return ESpellCastProblem::STACK_IMMUNE_TO_SPELL; + return ESpellCastProblem::STACK_IMMUNE_TO_SPELL; break; case Spells::HASTE: case Spells::SLOW: @@ -1502,17 +1505,17 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleIsImmune(const C immunities->remove_if([](const Bonus* b){ return b->source == Bonus::CREATURE_ABILITY; }); } - if(subject->hasBonusOfType(Bonus::SPELL_IMMUNITY, spell->id) + if(subject->hasBonusOfType(Bonus::SPELL_IMMUNITY, spell->id) || ( immunities->size() > 0 && immunities->totalValue() >= spell->level && spell->level)) - { + { return ESpellCastProblem::STACK_IMMUNE_TO_SPELL; } } else //no target stack on this tile { - if(spell->getTargetType() == CSpell::CREATURE - || (spell->getTargetType() == CSpell::CREATURE_EXPERT_MASSIVE - && mode == ECastingMode::HERO_CASTING + if(spell->getTargetType() == CSpell::CREATURE + || (spell->getTargetType() == CSpell::CREATURE_EXPERT_MASSIVE + && mode == ECastingMode::HERO_CASTING && caster && caster->getSpellSchoolLevel(spell) < SecSkillLevel::EXPERT)) { @@ -1528,7 +1531,7 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell RETURN_IF_NOT_BATTLE(ESpellCastProblem::INVALID); const ui8 side = playerToSide(player); if(!battleDoWeKnowAbout(side)) - ESpellCastProblem::INVALID; + return ESpellCastProblem::INVALID; ESpellCastProblem::ESpellCastProblem genProblem = battleCanCastSpell(player, mode); if(genProblem != ESpellCastProblem::OK) @@ -1558,7 +1561,7 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell return ESpellCastProblem::ADVMAP_SPELL_INSTEAD_OF_BATTLE_SPELL; //TODO? - //if(NBonus::hasOfType(heroes[1-cside], Bonus::SPELL_IMMUNITY, spell->id)) //non - casting hero provides immunity for this spell + //if(NBonus::hasOfType(heroes[1-cside], Bonus::SPELL_IMMUNITY, spell->id)) //non - casting hero provides immunity for this spell // return ESpellCastProblem::SECOND_HEROS_SPELL_IMMUNITY; if(spell->isNegative()) { @@ -1581,10 +1584,10 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell return ESpellCastProblem::SPELL_LEVEL_LIMIT_EXCEEDED; //IDs of summon elemental spells (fire, earth, water, air) - int spellIDs[] = { Spells::SUMMON_FIRE_ELEMENTAL, Spells::SUMMON_EARTH_ELEMENTAL, - Spells::SUMMON_WATER_ELEMENTAL, Spells::SUMMON_AIR_ELEMENTAL }; + int spellIDs[] = { Spells::SUMMON_FIRE_ELEMENTAL, Spells::SUMMON_EARTH_ELEMENTAL, + Spells::SUMMON_WATER_ELEMENTAL, Spells::SUMMON_AIR_ELEMENTAL }; //(fire, earth, water, air) elementals - int creIDs[] = {114, 113, 115, 112}; + int creIDs[] = {114, 113, 115, 112}; int arpos = vstd::find_pos(spellIDs, spell->id); if(arpos < ARRAY_COUNT(spellIDs)) @@ -1688,8 +1691,8 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell if(spell->getTargetType() == CSpell::OBSTACLE) { //isObstacleOnTile(dest) - // - // + // + // //TODO //assert that it's remove obstacle //rules whether we can remove spell-created obstacle @@ -1706,7 +1709,7 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell { if(!deadStack && !aliveStack) return ESpellCastProblem::NO_APPROPRIATE_TARGET; - if(spell->id == Spells::ANIMATE_DEAD && deadStack && !deadStack->hasBonusOfType(Bonus::UNDEAD)) + if(spell->id == Spells::ANIMATE_DEAD && deadStack && !deadStack->hasBonusOfType(Bonus::UNDEAD)) return ESpellCastProblem::NO_APPROPRIATE_TARGET; if(deadStack && deadStack->owner != player) //you can resurrect only your own stacks //FIXME: it includes alive stacks as well return ESpellCastProblem::NO_APPROPRIATE_TARGET; @@ -1733,7 +1736,7 @@ const CStack * CBattleInfoCallback::getStackIf(boost::functionisPositive()) //only positive { - if (subject->hasBonusFrom(Bonus::SPELL_EFFECT, spell->id) + if (subject->hasBonusFrom(Bonus::SPELL_EFFECT, spell->id) || battleCanCastThisSpellHere(subject->owner, spell, ECastingMode::CREATURE_ACTIVE_CASTING, subject->position) != ESpellCastProblem::OK) continue; @@ -1832,7 +1835,7 @@ TSpell CBattleInfoCallback::getRandomBeneficialSpell(const CStack * subject) con { auto kingMonster = getStackIf([&](const CStack *stack) //look for enemy, non-shooting stack { - return stack->owner != subject->owner + return stack->owner != subject->owner && (stack->hasBonus(Selector::type(Bonus::KING1) || Selector::type(Bonus::KING2) || Selector::type(Bonus::KING3))); }); @@ -1906,7 +1909,7 @@ si8 CBattleInfoCallback::battleMaxSpellLevel() const node = h; //TODO else use battle node if(!node) - return GameConstants::SPELL_LEVELS; + return GameConstants::SPELL_LEVELS; //We can't "just get value" - it'd be 0 if there are bonuses (and all would be blocked) auto b = node->getBonuses(Selector::type(Bonus::BLOCK_MAGIC_ABOVE)); @@ -1994,8 +1997,8 @@ TStacks CPlayerBattleCallback::battleGetStacks(EStackOwnership whose /*= MINE_AN RETURN_IF_NOT_BATTLE(ret); vstd::copy_if(battleGetAllStacks(), std::back_inserter(ret), [=](const CStack *s) -> bool { - const bool ownerMatches = (whose == MINE_AND_ENEMY) - || (whose == ONLY_MINE && s->owner == player) + const bool ownerMatches = (whose == MINE_AND_ENEMY) + || (whose == ONLY_MINE && s->owner == player) || (whose == ONLY_ENEMY && s->owner != player); const bool alivenessMatches = s->alive() || !onlyAlive; return ownerMatches && alivenessMatches; diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 18a1e1917..5a372bcbd 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -17,6 +17,7 @@ set(lib_SRCS BattleHex.cpp BattleState.cpp CArtHandler.cpp + CBattleCallback.cpp CBuildingHandler.cpp CCampaignHandler.cpp CConsoleHandler.cpp @@ -29,7 +30,7 @@ set(lib_SRCS CHeroHandler.cpp CLogger.cpp CMapInfo.cpp - CModHandler.cpp + CModHandler.cpp CObjectHandler.cpp CObstacleInstance.cpp Connection.cpp diff --git a/lib/Makefile.am b/lib/Makefile.am index 3f9510da3..f7987feda 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -21,6 +21,8 @@ libvcmi_la_SOURCES = \ BattleState.h \ CArtHandler.cpp \ CArtHandler.h \ + CBattleCallback.cpp \ + CBattleCallback.h \ CBuildingHandler.cpp \ CBuildingHandler.h \ CCampaignHandler.cpp \ diff --git a/lib/Makefile.in b/lib/Makefile.in index f05bd8a91..6ee3bc7a3 100644 --- a/lib/Makefile.in +++ b/lib/Makefile.in @@ -91,20 +91,20 @@ am_libvcmi_la_OBJECTS = libvcmi_la-CBinaryReader.lo \ libvcmi_la-CLodArchiveLoader.lo libvcmi_la-CMemoryStream.lo \ libvcmi_la-CResourceLoader.lo libvcmi_la-BattleAction.lo \ libvcmi_la-BattleState.lo libvcmi_la-CArtHandler.lo \ - libvcmi_la-CBuildingHandler.lo libvcmi_la-CCampaignHandler.lo \ - libvcmi_la-CConsoleHandler.lo libvcmi_la-CCreatureHandler.lo \ - libvcmi_la-CCreatureSet.lo libvcmi_la-CDefObjInfoHandler.lo \ - libvcmi_la-CGameInterface.lo libvcmi_la-CGameState.lo \ - libvcmi_la-CGeneralTextHandler.lo libvcmi_la-CHeroHandler.lo \ - libvcmi_la-CLogger.lo libvcmi_la-CMapInfo.lo \ - libvcmi_la-CModHandler.lo libvcmi_la-CObjectHandler.lo \ - libvcmi_la-CObstacleInstance.lo libvcmi_la-CSpellHandler.lo \ - libvcmi_la-CTownHandler.lo libvcmi_la-CThreadHelper.lo \ - libvcmi_la-Connection.lo libvcmi_la-HeroBonus.lo \ - libvcmi_la-IGameCallback.lo libvcmi_la-JsonNode.lo \ - libvcmi_la-NetPacksLib.lo libvcmi_la-ResourceSet.lo \ - libvcmi_la-BattleHex.lo libvcmi_la-VCMI_Lib.lo \ - libvcmi_la-map.lo + libvcmi_la-CBattleCallback.lo libvcmi_la-CBuildingHandler.lo \ + libvcmi_la-CCampaignHandler.lo libvcmi_la-CConsoleHandler.lo \ + libvcmi_la-CCreatureHandler.lo libvcmi_la-CCreatureSet.lo \ + libvcmi_la-CDefObjInfoHandler.lo libvcmi_la-CGameInterface.lo \ + libvcmi_la-CGameState.lo libvcmi_la-CGeneralTextHandler.lo \ + libvcmi_la-CHeroHandler.lo libvcmi_la-CLogger.lo \ + libvcmi_la-CMapInfo.lo libvcmi_la-CModHandler.lo \ + libvcmi_la-CObjectHandler.lo libvcmi_la-CObstacleInstance.lo \ + libvcmi_la-CSpellHandler.lo libvcmi_la-CTownHandler.lo \ + libvcmi_la-CThreadHelper.lo libvcmi_la-Connection.lo \ + libvcmi_la-HeroBonus.lo libvcmi_la-IGameCallback.lo \ + libvcmi_la-JsonNode.lo libvcmi_la-NetPacksLib.lo \ + libvcmi_la-ResourceSet.lo libvcmi_la-BattleHex.lo \ + libvcmi_la-VCMI_Lib.lo libvcmi_la-map.lo libvcmi_la_OBJECTS = $(am_libvcmi_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) @@ -313,6 +313,8 @@ libvcmi_la_SOURCES = \ BattleState.h \ CArtHandler.cpp \ CArtHandler.h \ + CBattleCallback.cpp \ + CBattleCallback.h \ CBuildingHandler.cpp \ CBuildingHandler.h \ CCampaignHandler.cpp \ @@ -454,6 +456,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libvcmi_la-BattleHex.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libvcmi_la-BattleState.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libvcmi_la-CArtHandler.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libvcmi_la-CBattleCallback.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libvcmi_la-CBinaryReader.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libvcmi_la-CBuildingHandler.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libvcmi_la-CCampaignHandler.Plo@am__quote@ @@ -587,6 +590,13 @@ libvcmi_la-CArtHandler.lo: CArtHandler.cpp @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libvcmi_la_CXXFLAGS) $(CXXFLAGS) -c -o libvcmi_la-CArtHandler.lo `test -f 'CArtHandler.cpp' || echo '$(srcdir)/'`CArtHandler.cpp +libvcmi_la-CBattleCallback.lo: CBattleCallback.cpp +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libvcmi_la_CXXFLAGS) $(CXXFLAGS) -MT libvcmi_la-CBattleCallback.lo -MD -MP -MF $(DEPDIR)/libvcmi_la-CBattleCallback.Tpo -c -o libvcmi_la-CBattleCallback.lo `test -f 'CBattleCallback.cpp' || echo '$(srcdir)/'`CBattleCallback.cpp +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libvcmi_la-CBattleCallback.Tpo $(DEPDIR)/libvcmi_la-CBattleCallback.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='CBattleCallback.cpp' object='libvcmi_la-CBattleCallback.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libvcmi_la_CXXFLAGS) $(CXXFLAGS) -c -o libvcmi_la-CBattleCallback.lo `test -f 'CBattleCallback.cpp' || echo '$(srcdir)/'`CBattleCallback.cpp + libvcmi_la-CBuildingHandler.lo: CBuildingHandler.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libvcmi_la_CXXFLAGS) $(CXXFLAGS) -MT libvcmi_la-CBuildingHandler.lo -MD -MP -MF $(DEPDIR)/libvcmi_la-CBuildingHandler.Tpo -c -o libvcmi_la-CBuildingHandler.lo `test -f 'CBuildingHandler.cpp' || echo '$(srcdir)/'`CBuildingHandler.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libvcmi_la-CBuildingHandler.Tpo $(DEPDIR)/libvcmi_la-CBuildingHandler.Plo