diff --git a/config/bonuses_texts.json b/config/bonuses_texts.json index 029bff1a8..8864751ce 100644 --- a/config/bonuses_texts.json +++ b/config/bonuses_texts.json @@ -150,12 +150,13 @@ "description": "Immune to all Fire school spells" }, - "FIRE_SHIELD": { - "name": "Fire Shield (${val}%)", - "description": "Reflects part of melee damage" - }, + "FIRE_SHIELD": + { + "name": "Fire Shield (${val}%)", + "description": "Reflects part of melee damage" + }, - "FIRST_STRIKE": + "FIRST_STRIKE": { "name": "First Strike", "description": "This creature attacks first instead of retaliating" @@ -352,6 +353,12 @@ "name": "Ranged", "description": "Creature can shoot" }, + + "SHOOTS_ALL_ADJACENT": + { + "name": "Shoot all around", + "description": "This creature's ranged attacks strike all targets in a small area" + }, "SOUL_STEAL": { @@ -400,13 +407,19 @@ "name": "Aura of Resistance", "description": "Nearby stacks get ${val}% resistance" }, - + "SUMMON_GUARDIANS": { "name": "Summon guardians", "description": "At battle start summons ${subtype.creature} (${val}%)" }, + "SYNERGY_TARGET": + { + "name": "Synergizable", + "description": "This creature is vulnerable to synergy effect" + }, + "TWO_HEX_ATTACK_BREATH": { "name": "Breath", diff --git a/lib/HeroBonus.h b/lib/HeroBonus.h index 5ba1e6cc6..1b9e46651 100644 --- a/lib/HeroBonus.h +++ b/lib/HeroBonus.h @@ -235,8 +235,10 @@ private: BONUS_NAME(CATAPULT_EXTRA_SHOTS) /*val - number of additional shots, requires CATAPULT bonus to work*/\ BONUS_NAME(RANGED_RETALIATION) /*allows shooters to perform ranged retaliation*/\ BONUS_NAME(BLOCKS_RANGED_RETALIATION) /*disallows ranged retaliation for shooter unit, BLOCKS_RETALIATION bonus is for melee retaliation only*/\ - BONUS_NAME(WIDE_BREATH) /* Kuririn skill */\ - BONUS_NAME(FIRST_STRIKE) /* Witchking skill */\ + BONUS_NAME(WIDE_BREATH) /* initial desigh: dragon breath affecting multiple nearby hexes */\ + BONUS_NAME(FIRST_STRIKE) /* first counterattack, then attack if possible */\ + BONUS_NAME(SYNERGY_TARGET) /* dummy skill for alternative upgrades mod */\ + BONUS_NAME(SHOOTS_ALL_ADJACENT) /* H4 Cyclops-like shoot (attacks all hexes neighboring with target) without spell-like mechanics */\ /* end of list */ diff --git a/lib/battle/CBattleInfoCallback.cpp b/lib/battle/CBattleInfoCallback.cpp index 9568fa41d..e4bade27e 100644 --- a/lib/battle/CBattleInfoCallback.cpp +++ b/lib/battle/CBattleInfoCallback.cpp @@ -186,7 +186,7 @@ std::set CBattleInfoCallback::battleGetAttackedHexes(const CStack* at { std::set attackedHexes; RETURN_IF_NOT_BATTLE(attackedHexes); - + AttackableTiles at = getPotentiallyAttackableHexes(attacker, destinationTile, attackerPos); for (BattleHex tile : at.hostileCreaturePositions) @@ -1120,7 +1120,7 @@ ReachabilityInfo CBattleInfoCallback::getFlyingReachability(const ReachabilityIn return ret; } -AttackableTiles CBattleInfoCallback::getPotentiallyAttackableHexes (const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos) const +AttackableTiles CBattleInfoCallback::getPotentiallyAttackableHexes (const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos, bool rangedAttack) const { //does not return hex attacked directly //TODO: apply rotation to two-hex attackers @@ -1129,210 +1129,221 @@ AttackableTiles CBattleInfoCallback::getPotentiallyAttackableHexes (const CStack AttackableTiles at; RETURN_IF_NOT_BATTLE(at); - const int WN = GameConstants::BFIELD_WIDTH; - BattleHex hex = (attackerPos != BattleHex::INVALID) ? attackerPos.hex : attacker->position.hex; //real or hypothetical (cursor) position - - //FIXME: dragons or cerbers can rotate before attack, making their base hex different (#1124) - bool reverse = isToReverse (hex, destinationTile, isAttacker, attacker->doubleWide(), isAttacker); - if (reverse && attacker->doubleWide()) + if(rangedAttack) { - hex = attacker->occupiedHex(hex); //the other hex stack stands on - } - if (attacker->hasBonusOfType(Bonus::ATTACKS_ALL_ADJACENT)) - { - boost::copy (attacker->getSurroundingHexes (attackerPos), vstd::set_inserter (at.hostileCreaturePositions)); - } - if (attacker->hasBonusOfType(Bonus::THREE_HEADED_ATTACK)) - { - std::vector hexes = attacker->getSurroundingHexes(attackerPos); - for (BattleHex tile : hexes) + if(attacker->hasBonusOfType(Bonus::SHOOTS_ALL_ADJACENT) && !vstd::contains(attackerPos.neighbouringTiles(), destinationTile)) { - if ((BattleHex::mutualPosition(tile, destinationTile) > -1 && BattleHex::mutualPosition (tile, hex) > -1)) //adjacent both to attacker's head and attacked tile + std::vector targetHexes = destinationTile.neighbouringTiles(); + targetHexes.push_back(destinationTile); + boost::copy(targetHexes, vstd::set_inserter(at.hostileCreaturePositions)); + } + } + + else + { + const int WN = GameConstants::BFIELD_WIDTH; + BattleHex hex = (attackerPos != BattleHex::INVALID) ? attackerPos.hex : attacker->position.hex; //real or hypothetical (cursor) position + + //FIXME: dragons or cerbers can rotate before attack, making their base hex different (#1124) + bool reverse = isToReverse(hex, destinationTile, isAttacker, attacker->doubleWide(), isAttacker); + if(reverse && attacker->doubleWide()) + { + hex = attacker->occupiedHex(hex); //the other hex stack stands on + } + if(attacker->hasBonusOfType(Bonus::ATTACKS_ALL_ADJACENT)) + { + boost::copy(attacker->getSurroundingHexes(attackerPos), vstd::set_inserter(at.hostileCreaturePositions)); + } + if(attacker->hasBonusOfType(Bonus::THREE_HEADED_ATTACK)) + { + std::vector hexes = attacker->getSurroundingHexes(attackerPos); + for(BattleHex tile : hexes) { - const CStack * st = battleGetStackByPos(tile, true); - if(st && st->owner != attacker->owner) //only hostile stacks - does it work well with Berserk? + if((BattleHex::mutualPosition(tile, destinationTile) > -1 && BattleHex::mutualPosition(tile, hex) > -1)) //adjacent both to attacker's head and attacked tile { - at.hostileCreaturePositions.insert(tile); + const CStack * st = battleGetStackByPos(tile, true); + if(st && st->owner != attacker->owner) //only hostile stacks - does it work well with Berserk? + { + at.hostileCreaturePositions.insert(tile); + } } } } - } - if (attacker->hasBonusOfType(Bonus::WIDE_BREATH)) - { - std::vector hexes; - const int WN = GameConstants::BFIELD_WIDTH; - // atack stand - if (hex == destinationTile.cloneInDirection(BattleHex::EDir::LEFT, false)) { - if (destinationTile.getY() % 2 == 0) - { - BattleHex::checkAndPush(destinationTile, hexes); - BattleHex::checkAndPush(destinationTile + 1, hexes); - BattleHex::checkAndPush(destinationTile + WN, hexes); - BattleHex::checkAndPush(destinationTile + WN + 1, hexes); - BattleHex::checkAndPush(destinationTile + (2 * WN) - 1, hexes); - BattleHex::checkAndPush(destinationTile + (2 * WN), hexes); - } - else { - BattleHex::checkAndPush(destinationTile, hexes); - BattleHex::checkAndPush(destinationTile + 1, hexes); - BattleHex::checkAndPush(destinationTile + WN, hexes); - BattleHex::checkAndPush(destinationTile + WN - 1, hexes); - BattleHex::checkAndPush(destinationTile + (2 * WN) - 1, hexes); - BattleHex::checkAndPush(destinationTile + (2 * WN), hexes); - } - - } - if (hex == destinationTile.cloneInDirection(BattleHex::EDir::RIGHT, false)) { - if (destinationTile.getY() % 2 == 0) - { - BattleHex::checkAndPush(destinationTile, hexes); - BattleHex::checkAndPush(destinationTile - 1, hexes); - BattleHex::checkAndPush(destinationTile + WN, hexes); - BattleHex::checkAndPush(destinationTile + WN + 1, hexes); - BattleHex::checkAndPush(destinationTile + (2 * WN), hexes); - BattleHex::checkAndPush(destinationTile + (2 * WN) + 1, hexes); - } - else - { - BattleHex::checkAndPush(destinationTile, hexes); - BattleHex::checkAndPush(destinationTile - 1, hexes); - BattleHex::checkAndPush(destinationTile + WN, hexes); - BattleHex::checkAndPush(destinationTile + WN - 1, hexes); - BattleHex::checkAndPush(destinationTile + (2 * WN), hexes); - BattleHex::checkAndPush(destinationTile + (2 * WN) + 1, hexes); - } - } - // atack down - if (hex == destinationTile.cloneInDirection(BattleHex::EDir::TOP_LEFT, false)) { - if (destinationTile.getY() % 2 == 1) - { - BattleHex::checkAndPush(destinationTile, hexes); - BattleHex::checkAndPush(destinationTile - 1, hexes); - BattleHex::checkAndPush(destinationTile - 2, hexes); - BattleHex::checkAndPush(destinationTile + WN, hexes); - BattleHex::checkAndPush(destinationTile + WN - 1, hexes); - BattleHex::checkAndPush(destinationTile + WN - 2, hexes); - } - else { - BattleHex::checkAndPush(destinationTile, hexes); - BattleHex::checkAndPush(destinationTile - 1, hexes); - BattleHex::checkAndPush(destinationTile - 2, hexes); - BattleHex::checkAndPush(destinationTile + WN, hexes); - BattleHex::checkAndPush(destinationTile + WN + 1, hexes); - BattleHex::checkAndPush(destinationTile + WN - 1, hexes); - } - } - if (hex == destinationTile.cloneInDirection(BattleHex::EDir::TOP_RIGHT, false)) { - - if (destinationTile.getY() % 2 == 1) - { - BattleHex::checkAndPush(destinationTile, hexes); - BattleHex::checkAndPush(destinationTile + 1, hexes); - BattleHex::checkAndPush(destinationTile + 2, hexes); - BattleHex::checkAndPush(destinationTile + WN - 1, hexes); - BattleHex::checkAndPush(destinationTile + WN, hexes); - BattleHex::checkAndPush(destinationTile + WN + 1, hexes); - } - else - { - BattleHex::checkAndPush(destinationTile, hexes); - BattleHex::checkAndPush(destinationTile + 1, hexes); - BattleHex::checkAndPush(destinationTile + 2, hexes); - BattleHex::checkAndPush(destinationTile + WN, hexes); - BattleHex::checkAndPush(destinationTile + WN + 1, hexes); - BattleHex::checkAndPush(destinationTile + WN + 2, hexes); - } - - } - // attack up - if (hex == destinationTile.cloneInDirection(BattleHex::EDir::BOTTOM_LEFT, false)) { - if (destinationTile.getY() % 2 == 1) - { - BattleHex::checkAndPush(destinationTile, hexes); - BattleHex::checkAndPush(destinationTile + 1, hexes); - BattleHex::checkAndPush(destinationTile + WN, hexes); - BattleHex::checkAndPush(destinationTile + WN + 1, hexes); - BattleHex::checkAndPush(destinationTile - WN, hexes); - BattleHex::checkAndPush(destinationTile - WN - 1, hexes); - } - else { - BattleHex::checkAndPush(destinationTile, hexes); - BattleHex::checkAndPush(destinationTile + 1, hexes); - BattleHex::checkAndPush(destinationTile + WN + 1, hexes); - BattleHex::checkAndPush(destinationTile + WN + 2, hexes); - BattleHex::checkAndPush(destinationTile - WN, hexes); - BattleHex::checkAndPush(destinationTile - WN + 1, hexes); - } - } - if (hex == destinationTile.cloneInDirection(BattleHex::EDir::BOTTOM_RIGHT, false)) { - - if (destinationTile.getY() % 2 == 1) - { - BattleHex::checkAndPush(destinationTile, hexes); - BattleHex::checkAndPush(destinationTile - 1, hexes); - BattleHex::checkAndPush(destinationTile + WN - 1, hexes); - BattleHex::checkAndPush(destinationTile + WN - 2, hexes); - BattleHex::checkAndPush(destinationTile - WN, hexes); - BattleHex::checkAndPush(destinationTile - WN - 1, hexes); - } - else - { - BattleHex::checkAndPush(destinationTile, hexes); - BattleHex::checkAndPush(destinationTile - 1, hexes); - BattleHex::checkAndPush(destinationTile + WN, hexes); - BattleHex::checkAndPush(destinationTile + WN - 1, hexes); - BattleHex::checkAndPush(destinationTile - WN, hexes); - BattleHex::checkAndPush(destinationTile - WN + 1, hexes); - } - - } - - for (BattleHex tile : hexes) + if(attacker->hasBonusOfType(Bonus::WIDE_BREATH)) { - //friendly stacks can also be damaged by Dragon Breath - if (battleGetStackByPos(tile, true)) - at.friendlyCreaturePositions.insert(tile); + std::vector hexes; + // attack stand + if(hex == destinationTile.cloneInDirection(BattleHex::EDir::LEFT, false)) { + if(destinationTile.getY() % 2 == 0) + { + BattleHex::checkAndPush(destinationTile, hexes); + BattleHex::checkAndPush(destinationTile + 1, hexes); + BattleHex::checkAndPush(destinationTile + WN, hexes); + BattleHex::checkAndPush(destinationTile + WN + 1, hexes); + BattleHex::checkAndPush(destinationTile + (2 * WN) - 1, hexes); + BattleHex::checkAndPush(destinationTile + (2 * WN), hexes); + } + else { + BattleHex::checkAndPush(destinationTile, hexes); + BattleHex::checkAndPush(destinationTile + 1, hexes); + BattleHex::checkAndPush(destinationTile + WN, hexes); + BattleHex::checkAndPush(destinationTile + WN - 1, hexes); + BattleHex::checkAndPush(destinationTile + (2 * WN) - 1, hexes); + BattleHex::checkAndPush(destinationTile + (2 * WN), hexes); + } + + } + if(hex == destinationTile.cloneInDirection(BattleHex::EDir::RIGHT, false)) { + if(destinationTile.getY() % 2 == 0) + { + BattleHex::checkAndPush(destinationTile, hexes); + BattleHex::checkAndPush(destinationTile - 1, hexes); + BattleHex::checkAndPush(destinationTile + WN, hexes); + BattleHex::checkAndPush(destinationTile + WN + 1, hexes); + BattleHex::checkAndPush(destinationTile + (2 * WN), hexes); + BattleHex::checkAndPush(destinationTile + (2 * WN) + 1, hexes); + } + else + { + BattleHex::checkAndPush(destinationTile, hexes); + BattleHex::checkAndPush(destinationTile - 1, hexes); + BattleHex::checkAndPush(destinationTile + WN, hexes); + BattleHex::checkAndPush(destinationTile + WN - 1, hexes); + BattleHex::checkAndPush(destinationTile + (2 * WN), hexes); + BattleHex::checkAndPush(destinationTile + (2 * WN) + 1, hexes); + } + } + // attack down + if(hex == destinationTile.cloneInDirection(BattleHex::EDir::TOP_LEFT, false)) { + if(destinationTile.getY() % 2 == 1) + { + BattleHex::checkAndPush(destinationTile, hexes); + BattleHex::checkAndPush(destinationTile - 1, hexes); + BattleHex::checkAndPush(destinationTile - 2, hexes); + BattleHex::checkAndPush(destinationTile + WN, hexes); + BattleHex::checkAndPush(destinationTile + WN - 1, hexes); + BattleHex::checkAndPush(destinationTile + WN - 2, hexes); + } + else { + BattleHex::checkAndPush(destinationTile, hexes); + BattleHex::checkAndPush(destinationTile - 1, hexes); + BattleHex::checkAndPush(destinationTile - 2, hexes); + BattleHex::checkAndPush(destinationTile + WN, hexes); + BattleHex::checkAndPush(destinationTile + WN + 1, hexes); + BattleHex::checkAndPush(destinationTile + WN - 1, hexes); + } + } + if(hex == destinationTile.cloneInDirection(BattleHex::EDir::TOP_RIGHT, false)) { + + if(destinationTile.getY() % 2 == 1) + { + BattleHex::checkAndPush(destinationTile, hexes); + BattleHex::checkAndPush(destinationTile + 1, hexes); + BattleHex::checkAndPush(destinationTile + 2, hexes); + BattleHex::checkAndPush(destinationTile + WN - 1, hexes); + BattleHex::checkAndPush(destinationTile + WN, hexes); + BattleHex::checkAndPush(destinationTile + WN + 1, hexes); + } + else + { + BattleHex::checkAndPush(destinationTile, hexes); + BattleHex::checkAndPush(destinationTile + 1, hexes); + BattleHex::checkAndPush(destinationTile + 2, hexes); + BattleHex::checkAndPush(destinationTile + WN, hexes); + BattleHex::checkAndPush(destinationTile + WN + 1, hexes); + BattleHex::checkAndPush(destinationTile + WN + 2, hexes); + } + + } + // attack up + if(hex == destinationTile.cloneInDirection(BattleHex::EDir::BOTTOM_LEFT, false)) { + if(destinationTile.getY() % 2 == 1) + { + BattleHex::checkAndPush(destinationTile, hexes); + BattleHex::checkAndPush(destinationTile + 1, hexes); + BattleHex::checkAndPush(destinationTile + WN, hexes); + BattleHex::checkAndPush(destinationTile + WN + 1, hexes); + BattleHex::checkAndPush(destinationTile - WN, hexes); + BattleHex::checkAndPush(destinationTile - WN - 1, hexes); + } + else { + BattleHex::checkAndPush(destinationTile, hexes); + BattleHex::checkAndPush(destinationTile + 1, hexes); + BattleHex::checkAndPush(destinationTile + WN + 1, hexes); + BattleHex::checkAndPush(destinationTile + WN + 2, hexes); + BattleHex::checkAndPush(destinationTile - WN, hexes); + BattleHex::checkAndPush(destinationTile - WN + 1, hexes); + } + } + if(hex == destinationTile.cloneInDirection(BattleHex::EDir::BOTTOM_RIGHT, false)) { + + if(destinationTile.getY() % 2 == 1) + { + BattleHex::checkAndPush(destinationTile, hexes); + BattleHex::checkAndPush(destinationTile - 1, hexes); + BattleHex::checkAndPush(destinationTile + WN - 1, hexes); + BattleHex::checkAndPush(destinationTile + WN - 2, hexes); + BattleHex::checkAndPush(destinationTile - WN, hexes); + BattleHex::checkAndPush(destinationTile - WN - 1, hexes); + } + else + { + BattleHex::checkAndPush(destinationTile, hexes); + BattleHex::checkAndPush(destinationTile - 1, hexes); + BattleHex::checkAndPush(destinationTile + WN, hexes); + BattleHex::checkAndPush(destinationTile + WN - 1, hexes); + BattleHex::checkAndPush(destinationTile - WN, hexes); + BattleHex::checkAndPush(destinationTile - WN + 1, hexes); + } + + } + + for(BattleHex tile : hexes) + { + //friendly stacks can also be damaged by Dragon Breath + if(battleGetStackByPos(tile, true)) + at.friendlyCreaturePositions.insert(tile); + } + } + + else if(attacker->hasBonusOfType(Bonus::TWO_HEX_ATTACK_BREATH) && BattleHex::mutualPosition(destinationTile.hex, hex) > -1) //only adjacent hexes are subject of dragon breath calculation + { + std::vector hexes; //only one, in fact + int pseudoVector = destinationTile.hex - hex; + switch(pseudoVector) + { + case 1: + case -1: + BattleHex::checkAndPush(destinationTile.hex + pseudoVector, hexes); + break; + case WN: //17 //left-down or right-down + case -WN: //-17 //left-up or right-up + case WN + 1: //18 //right-down + case -WN + 1: //-16 //right-up + BattleHex::checkAndPush(destinationTile.hex + pseudoVector + (((hex / WN) % 2) ? 1 : -1), hexes); + break; + case WN - 1: //16 //left-down + case -WN - 1: //-18 //left-up + BattleHex::checkAndPush(destinationTile.hex + pseudoVector + (((hex / WN) % 2) ? 1 : 0), hexes); + break; + } + for(BattleHex tile : hexes) + { + //friendly stacks can also be damaged by Dragon Breath + if(battleGetStackByPos(tile, true)) + at.friendlyCreaturePositions.insert(tile); + } } } - - else if (attacker->hasBonusOfType(Bonus::TWO_HEX_ATTACK_BREATH) && BattleHex::mutualPosition(destinationTile.hex, hex) > -1) //only adjacent hexes are subject of dragon breath calculation - { - std::vector hexes; //only one, in fact - int pseudoVector = destinationTile.hex - hex; - switch (pseudoVector) - { - case 1: - case -1: - BattleHex::checkAndPush(destinationTile.hex + pseudoVector, hexes); - break; - case WN: //17 //left-down or right-down - case -WN: //-17 //left-up or right-up - case WN + 1: //18 //right-down - case -WN + 1: //-16 //right-up - BattleHex::checkAndPush(destinationTile.hex + pseudoVector + (((hex / WN) % 2) ? 1 : -1), hexes); - break; - case WN - 1: //16 //left-down - case -WN - 1: //-18 //left-up - BattleHex::checkAndPush(destinationTile.hex + pseudoVector + (((hex / WN) % 2) ? 1 : 0), hexes); - break; - } - for (BattleHex tile : hexes) - { - //friendly stacks can also be damaged by Dragon Breath - if (battleGetStackByPos(tile, true)) - at.friendlyCreaturePositions.insert(tile); - } - } - return at; } -std::set CBattleInfoCallback::getAttackedCreatures(const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos) const +std::set CBattleInfoCallback::getAttackedCreatures(const CStack* attacker, BattleHex destinationTile, bool rangedAttack, BattleHex attackerPos) const { std::set attackedCres; RETURN_IF_NOT_BATTLE(attackedCres); - AttackableTiles at = getPotentiallyAttackableHexes(attacker, destinationTile, attackerPos); + AttackableTiles at = getPotentiallyAttackableHexes(attacker, destinationTile, attackerPos, rangedAttack); for (BattleHex tile : at.hostileCreaturePositions) //all around & three-headed attack { const CStack * st = battleGetStackByPos(tile, true); diff --git a/lib/battle/CBattleInfoCallback.h b/lib/battle/CBattleInfoCallback.h index 0f4ff00d9..e7b19dbaf 100644 --- a/lib/battle/CBattleInfoCallback.h +++ b/lib/battle/CBattleInfoCallback.h @@ -92,8 +92,8 @@ public: bool isInTacticRange(BattleHex dest) const; si8 battleGetTacticDist() const; //returns tactic distance for calling player or 0 if this player is not in tactic phase (for ALL_KNOWING actual distance for tactic side) - AttackableTiles getPotentiallyAttackableHexes(const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos) const; //TODO: apply rotation to two-hex attacker - std::set getAttackedCreatures(const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos = BattleHex::INVALID) const; //calculates range of multi-hex attacks + AttackableTiles getPotentiallyAttackableHexes(const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos, bool rangedAttack) const; //TODO: apply rotation to two-hex attacker + std::set getAttackedCreatures(const CStack* attacker, BattleHex destinationTile, bool rangedAttack, BattleHex attackerPos = BattleHex::INVALID) const; //calculates range of multi-hex attacks bool isToReverse(BattleHex hexFrom, BattleHex hexTo, bool curDir /*if true, creature is in attacker's direction*/, bool toDoubleWide, bool toDir) const; //determines if creature should be reversed (it stands on hexFrom and should 'see' hexTo) bool isToReverseHlp(BattleHex hexFrom, BattleHex hexTo, bool curDir) const; //helper for isToReverse diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 56f182339..ce6c90c41 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -892,16 +892,14 @@ void CGameHandler::prepareAttack(BattleAttack &bat, const CStack *att, const CSt // only primary target applyBattleEffects(bat, att, def, distance, false); - if (!bat.shot()) //multiple-hex attack - only in meele - { - std::set attackedCreatures = gs->curB->getAttackedCreatures(att, targetHex); //creatures other than primary target + //multiple-hex normal attack + std::set attackedCreatures = gs->curB->getAttackedCreatures(att, targetHex, bat.shot()); //creatures other than primary target - for (const CStack * stack : attackedCreatures) + for (const CStack * stack : attackedCreatures) + { + if (stack != def) //do not hit same stack twice { - if (stack != def) //do not hit same stack twice - { - applyBattleEffects(bat, att, stack, distance, true); - } + applyBattleEffects(bat, att, stack, distance, true); } } @@ -914,11 +912,11 @@ void CGameHandler::prepareAttack(BattleAttack &bat, const CStack *att, const CSt //TODO: should spell override creature`s projectile? - auto attackedCreatures = SpellID(bonus->subtype).toSpell()->getAffectedStacks(gs->curB, ECastingMode::SPELL_LIKE_ATTACK, att, bonus->val, targetHex); + auto affectedCreatures = SpellID(bonus->subtype).toSpell()->getAffectedStacks(gs->curB, ECastingMode::SPELL_LIKE_ATTACK, att, bonus->val, targetHex); //TODO: get exact attacked hex for defender - for (const CStack * stack : attackedCreatures) + for (const CStack * stack : affectedCreatures) { if (stack != def) //do not hit same stack twice {