diff --git a/AI/GeniusAI/BattleLogic.cpp b/AI/GeniusAI/BattleLogic.cpp index 4b16cc1bb..b19d1fc1a 100644 --- a/AI/GeniusAI/BattleLogic.cpp +++ b/AI/GeniusAI/BattleLogic.cpp @@ -519,7 +519,7 @@ BattleAction CBattleLogic::MakeAttack(int attackerID, int destinationID) } } - std::vector fields = m_cb->battleGetAvailableHexes(m_cb->battleGetStackByID(attackerID), false); + std::vector fields = m_cb->battleGetAvailableHexes(m_cb->battleGetStackByID(attackerID), false, false); if(fields.size() == 0) { diff --git a/AI/StupidAI/StupidAI.cpp b/AI/StupidAI/StupidAI.cpp index 73bad69ea..85e8be3ea 100644 --- a/AI/StupidAI/StupidAI.cpp +++ b/AI/StupidAI/StupidAI.cpp @@ -101,7 +101,7 @@ BattleAction CStupidAI::activeStack( const CStack * stack ) { //boost::this_thread::sleep(boost::posix_time::seconds(2)); print("activeStack called"); - std::vector avHexes = cb->battleGetAvailableHexes(stack, false); + std::vector avHexes = cb->battleGetAvailableHexes(stack, false, false); std::vector dists = cb->battleGetDistances(stack); std::vector enemiesShootable, enemiesReachable, enemiesUnreachable; @@ -248,7 +248,7 @@ BattleAction CStupidAI::goTowards(const CStack * stack, THex hex) } dists = cb->battleGetDistances(stack, realDest, predecessors); - std::vector avHexes = cb->battleGetAvailableHexes(stack, false); + std::vector avHexes = cb->battleGetAvailableHexes(stack, false, false); while(1) { diff --git a/CCallback.cpp b/CCallback.cpp index 95a81e651..83ac32698 100644 --- a/CCallback.cpp +++ b/CCallback.cpp @@ -570,7 +570,7 @@ void CBattleCallback::getStackQueue( std::vector &out, int howMa gs->curB->getStackQueue(out, howMany); } -std::vector CBattleCallback::battleGetAvailableHexes(const CStack * stack, bool addOccupiable) +std::vector CBattleCallback::battleGetAvailableHexes(const CStack * stack, bool addOccupiable, std::vector * attackable) { boost::shared_lock lock(*gs->mx); if(!gs->curB) @@ -578,7 +578,7 @@ std::vector CBattleCallback::battleGetAvailableHexes(const CStack * stack, tlog2<<"battleGetAvailableHexes called when there is no battle!"<(); } - return gs->curB->getAccessibility(stack, addOccupiable); + return gs->curB->getAccessibility(stack, addOccupiable, attackable); //return gs->battleGetRange(ID); } diff --git a/CCallback.h b/CCallback.h index 25e10f1f5..8580c4371 100644 --- a/CCallback.h +++ b/CCallback.h @@ -93,7 +93,7 @@ public: virtual int battleMakeAction(BattleAction* action)=0;//for casting spells by hero - DO NOT use it for moving active stack virtual TStacks battleGetStacks(EStackOwnership whose = MINE_AND_ENEMY, bool onlyAlive = true)=0; //returns stacks on battlefield virtual void getStackQueue( std::vector &out, int howMany )=0; //returns vector of stack in order of their move sequence - virtual std::vector battleGetAvailableHexes(const CStack * stack, bool addOccupiable)=0; //returns numbers of hexes reachable by creature with id ID + virtual std::vector battleGetAvailableHexes(const CStack * stack, bool addOccupiable, std::vector * attackable = NULL)=0; //returns numbers of hexes reachable by creature with id ID virtual std::vector battleGetDistances(const CStack * stack, THex hex = THex::INVALID, THex * predecessors = NULL)=0; //returns vector of distances to [dest hex number] virtual bool battleCanShoot(const CStack * stack, THex dest)=0; //returns true if unit with id ID can shoot to dest virtual bool battleCanCastSpell()=0; //returns true, if caller can cast a spell @@ -231,7 +231,7 @@ public: int battleMakeAction(BattleAction* action) OVERRIDE;//for casting spells by hero - DO NOT use it for moving active stack TStacks battleGetStacks(EStackOwnership whose = MINE_AND_ENEMY, bool onlyAlive = true) OVERRIDE; //returns stacks on battlefield void getStackQueue( std::vector &out, int howMany ) OVERRIDE; //returns vector of stack in order of their move sequence - std::vector battleGetAvailableHexes(const CStack * stack, bool addOccupiable) OVERRIDE; //reutrns numbers of hexes reachable by creature with id ID + std::vector battleGetAvailableHexes(const CStack * stack, bool addOccupiable, std::vector * attackable = NULL) OVERRIDE; //returns numbers of hexes reachable by creature with id ID std::vector battleGetDistances(const CStack * stack, THex hex = THex::INVALID, THex * predecessors = NULL) OVERRIDE; //returns vector of distances to [dest hex number]; if predecessors is not null, it must point to BFIELD_SIZE * sizeof(int) of allocated memory bool battleCanShoot(const CStack * stack, THex dest) OVERRIDE; //returns true if unit with id ID can shoot to dest bool battleCanCastSpell() OVERRIDE; //returns true, if caller can cast a spell diff --git a/client/CBattleInterface.cpp b/client/CBattleInterface.cpp index e79923143..46b3aff2e 100644 --- a/client/CBattleInterface.cpp +++ b/client/CBattleInterface.cpp @@ -1804,7 +1804,7 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent) } else { - if(std::find(shadedHexes.begin(),shadedHexes.end(),myNumber) == shadedHexes.end()) + if(std::find(occupyableHexes.begin(),occupyableHexes.end(),myNumber) == occupyableHexes.end()) { const CStack *shere = curInt->cb->battleGetStackByPos(myNumber); const CStack *sactive = activeStack; @@ -1881,7 +1881,7 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent) // Exclude directions which cannot be attacked from. // Check to the left. - if (myNumber%BFIELD_WIDTH <= 1 || !vstd::contains(shadedHexes, myNumber - 1)) + if (myNumber%BFIELD_WIDTH <= 1 || !vstd::contains(occupyableHexes, myNumber - 1)) { sectorCursor[0] = -1; } @@ -1898,13 +1898,13 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent) { bool attackRow[4] = {true, true, true, true}; - if (myNumber%BFIELD_WIDTH <= 1 || !vstd::contains(shadedHexes, myNumber - BFIELD_WIDTH - 2 + zigzagCorrection)) + if (myNumber%BFIELD_WIDTH <= 1 || !vstd::contains(occupyableHexes, myNumber - BFIELD_WIDTH - 2 + zigzagCorrection)) attackRow[0] = false; - if (!vstd::contains(shadedHexes, myNumber - BFIELD_WIDTH - 1 + zigzagCorrection)) + if (!vstd::contains(occupyableHexes, myNumber - BFIELD_WIDTH - 1 + zigzagCorrection)) attackRow[1] = false; - if (!vstd::contains(shadedHexes, myNumber - BFIELD_WIDTH + zigzagCorrection)) + if (!vstd::contains(occupyableHexes, myNumber - BFIELD_WIDTH + zigzagCorrection)) attackRow[2] = false; - if (myNumber%BFIELD_WIDTH >= BFIELD_WIDTH - 2 || !vstd::contains(shadedHexes, myNumber - BFIELD_WIDTH + 1 + zigzagCorrection)) + if (myNumber%BFIELD_WIDTH >= BFIELD_WIDTH - 2 || !vstd::contains(occupyableHexes, myNumber - BFIELD_WIDTH + 1 + zigzagCorrection)) attackRow[3] = false; if (!(attackRow[0] && attackRow[1])) @@ -1916,14 +1916,14 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent) } else { - if (!vstd::contains(shadedHexes, myNumber - BFIELD_WIDTH - 1 + zigzagCorrection)) + if (!vstd::contains(occupyableHexes, myNumber - BFIELD_WIDTH - 1 + zigzagCorrection)) sectorCursor[1] = -1; - if (!vstd::contains(shadedHexes, myNumber - BFIELD_WIDTH + zigzagCorrection)) + if (!vstd::contains(occupyableHexes, myNumber - BFIELD_WIDTH + zigzagCorrection)) sectorCursor[2] = -1; } } // Check to the right. - if (myNumber%BFIELD_WIDTH >= BFIELD_WIDTH - 2 || !vstd::contains(shadedHexes, myNumber + 1)) + if (myNumber%BFIELD_WIDTH >= BFIELD_WIDTH - 2 || !vstd::contains(occupyableHexes, myNumber + 1)) { sectorCursor[3] = -1; } @@ -1940,13 +1940,13 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent) { bool attackRow[4] = {true, true, true, true}; - if (myNumber%BFIELD_WIDTH <= 1 || !vstd::contains(shadedHexes, myNumber + BFIELD_WIDTH - 2 + zigzagCorrection)) + if (myNumber%BFIELD_WIDTH <= 1 || !vstd::contains(occupyableHexes, myNumber + BFIELD_WIDTH - 2 + zigzagCorrection)) attackRow[0] = false; - if (!vstd::contains(shadedHexes, myNumber + BFIELD_WIDTH - 1 + zigzagCorrection)) + if (!vstd::contains(occupyableHexes, myNumber + BFIELD_WIDTH - 1 + zigzagCorrection)) attackRow[1] = false; - if (!vstd::contains(shadedHexes, myNumber + BFIELD_WIDTH + zigzagCorrection)) + if (!vstd::contains(occupyableHexes, myNumber + BFIELD_WIDTH + zigzagCorrection)) attackRow[2] = false; - if (myNumber%BFIELD_WIDTH >= BFIELD_WIDTH - 2 || !vstd::contains(shadedHexes, myNumber + BFIELD_WIDTH + 1 + zigzagCorrection)) + if (myNumber%BFIELD_WIDTH >= BFIELD_WIDTH - 2 || !vstd::contains(occupyableHexes, myNumber + BFIELD_WIDTH + 1 + zigzagCorrection)) attackRow[3] = false; if (!(attackRow[0] && attackRow[1])) @@ -1958,9 +1958,9 @@ void CBattleInterface::mouseMoved(const SDL_MouseMotionEvent &sEvent) } else { - if (!vstd::contains(shadedHexes, myNumber + BFIELD_WIDTH + zigzagCorrection)) + if (!vstd::contains(occupyableHexes, myNumber + BFIELD_WIDTH + zigzagCorrection)) sectorCursor[4] = -1; - if (!vstd::contains(shadedHexes, myNumber + BFIELD_WIDTH - 1 + zigzagCorrection)) + if (!vstd::contains(occupyableHexes, myNumber + BFIELD_WIDTH - 1 + zigzagCorrection)) sectorCursor[5] = -1; } } @@ -2389,9 +2389,9 @@ void CBattleInterface::giveCommand(ui8 action, THex tile, ui32 stack, si32 addit bool CBattleInterface::isTileAttackable(const THex & number) const { - for(size_t b=0; balive()) //no creature at that tile { - if(std::find(shadedHexes.begin(),shadedHexes.end(),whichOne)!=shadedHexes.end())// and it's in our range + if(std::find(occupyableHexes.begin(),occupyableHexes.end(),whichOne)!=occupyableHexes.end())// and it's in our range { CCS->curh->changeGraphic(1, 6); //cursor should be changed if(activeStack->doubleWide()) @@ -2536,16 +2536,16 @@ void CBattleInterface::hexLclicked(int whichOne) bool doubleWide = actStack->doubleWide(); int destHex = whichOne + ( (whichOne/BFIELD_WIDTH)%2 ? BFIELD_WIDTH : BFIELD_WIDTH+1 ) + (actStack->attackerOwned && doubleWide ? 1 : 0); - if(vstd::contains(shadedHexes, destHex)) + if(vstd::contains(occupyableHexes, destHex)) attackFromHex = destHex; else if(actStack->attackerOwned) //if we are attacker { - if(vstd::contains(shadedHexes, destHex+1)) + if(vstd::contains(occupyableHexes, destHex+1)) attackFromHex = destHex+1; } else //if we are defender { - if(vstd::contains(shadedHexes, destHex-1)) + if(vstd::contains(occupyableHexes, destHex-1)) attackFromHex = destHex-1; } break; @@ -2553,16 +2553,16 @@ void CBattleInterface::hexLclicked(int whichOne) case 7: //from bottom left { int destHex = whichOne + ( (whichOne/BFIELD_WIDTH)%2 ? BFIELD_WIDTH-1 : BFIELD_WIDTH ); - if(vstd::contains(shadedHexes, destHex)) + if(vstd::contains(occupyableHexes, destHex)) attackFromHex = destHex; else if(actStack->attackerOwned) //if we are attacker { - if(vstd::contains(shadedHexes, destHex+1)) + if(vstd::contains(occupyableHexes, destHex+1)) attackFromHex = destHex+1; } else //if we are defender { - if(vstd::contains(shadedHexes, destHex-1)) + if(vstd::contains(occupyableHexes, destHex-1)) attackFromHex = destHex-1; } break; @@ -2586,16 +2586,16 @@ void CBattleInterface::hexLclicked(int whichOne) case 9: //from top left { int destHex = whichOne - ( (whichOne/BFIELD_WIDTH)%2 ? BFIELD_WIDTH+1 : BFIELD_WIDTH ); - if(vstd::contains(shadedHexes, destHex)) + if(vstd::contains(occupyableHexes, destHex)) attackFromHex = destHex; else if(actStack->attackerOwned) //if we are attacker { - if(vstd::contains(shadedHexes, destHex+1)) + if(vstd::contains(occupyableHexes, destHex+1)) attackFromHex = destHex+1; } else //if we are defender { - if(vstd::contains(shadedHexes, destHex-1)) + if(vstd::contains(occupyableHexes, destHex-1)) attackFromHex = destHex-1; } break; @@ -2605,16 +2605,16 @@ void CBattleInterface::hexLclicked(int whichOne) bool doubleWide = actStack->doubleWide(); int destHex = whichOne - ( (whichOne/BFIELD_WIDTH)%2 ? BFIELD_WIDTH : BFIELD_WIDTH-1 ) + (actStack->attackerOwned && doubleWide ? 1 : 0); - if(vstd::contains(shadedHexes, destHex)) + if(vstd::contains(occupyableHexes, destHex)) attackFromHex = destHex; else if(actStack->attackerOwned) //if we are attacker { - if(vstd::contains(shadedHexes, destHex+1)) + if(vstd::contains(occupyableHexes, destHex+1)) attackFromHex = destHex+1; } else //if we are defender { - if(vstd::contains(shadedHexes, destHex-1)) + if(vstd::contains(occupyableHexes, destHex-1)) attackFromHex = destHex-1; } break; @@ -2638,16 +2638,16 @@ void CBattleInterface::hexLclicked(int whichOne) case 13: //from bottom { int destHex = whichOne + ( (whichOne/BFIELD_WIDTH)%2 ? BFIELD_WIDTH : BFIELD_WIDTH+1 ); - if(vstd::contains(shadedHexes, destHex)) + if(vstd::contains(occupyableHexes, destHex)) attackFromHex = destHex; else if(attackingHeroInstance->tempOwner == curInt->cb->getMyColor()) //if we are attacker { - if(vstd::contains(shadedHexes, destHex+1)) + if(vstd::contains(occupyableHexes, destHex+1)) attackFromHex = destHex+1; } else //if we are defender { - if(vstd::contains(shadedHexes, destHex-1)) + if(vstd::contains(occupyableHexes, destHex-1)) attackFromHex = destHex-1; } break; @@ -2655,16 +2655,16 @@ void CBattleInterface::hexLclicked(int whichOne) case 14: //from top { int destHex = whichOne - ( (whichOne/BFIELD_WIDTH)%2 ? BFIELD_WIDTH : BFIELD_WIDTH-1 ); - if(vstd::contains(shadedHexes, destHex)) + if(vstd::contains(occupyableHexes, destHex)) attackFromHex = destHex; else if(attackingHeroInstance->tempOwner == curInt->cb->getMyColor()) //if we are attacker { - if(vstd::contains(shadedHexes, destHex+1)) + if(vstd::contains(occupyableHexes, destHex+1)) attackFromHex = destHex+1; } else //if we are defender { - if(vstd::contains(shadedHexes, destHex-1)) + if(vstd::contains(occupyableHexes, destHex-1)) attackFromHex = destHex-1; } break; @@ -3207,7 +3207,8 @@ void CBattleInterface::showPieceOfWall(SDL_Surface * to, int hex, const std::vec void CBattleInterface::redrawBackgroundWithHexes(const CStack * activeStack) { - shadedHexes = curInt->cb->battleGetAvailableHexes(activeStack, true); + attackableHexes.clear(); + occupyableHexes = curInt->cb->battleGetAvailableHexes(activeStack, true, &attackableHexes); //preparating background graphic with hexes and shaded hexes blitAt(background, 0, 0, backgroundWithHexes); @@ -3216,10 +3217,12 @@ void CBattleInterface::redrawBackgroundWithHexes(const CStack * activeStack) if(curInt->sysOpts.printStackRange) { - for(size_t m=0; m hexesToShade = occupyableHexes; + hexesToShade.insert(hexesToShade.end(), attackableHexes.begin(), attackableHexes.end()); + BOOST_FOREACH(THex hex, hexesToShade) { - int i = shadedHexes[m]/BFIELD_WIDTH; //row - int j = shadedHexes[m]%BFIELD_WIDTH-1; //column + int i = hex.getY(); //row + int j = hex.getX()-1; //column int x = 58 + (i%2==0 ? 22 : 0) + 44*j; int y = 86 + 42 * i; CSDL_Ext::blit8bppAlphaTo24bpp(cellShade, NULL, backgroundWithHexes, &genRect(cellShade->h, cellShade->w, x, y)); diff --git a/client/CBattleInterface.h b/client/CBattleInterface.h index 6a4917eff..29c2331b8 100644 --- a/client/CBattleInterface.h +++ b/client/CBattleInterface.h @@ -414,7 +414,8 @@ private: const CStack * stackToActivate; //when animation is playing, we should wait till the end to make the next stack active; NULL of none void activateStack(); //sets activeStack to stackToActivate etc. int mouseHoveredStack; //stack hovered by mouse; if -1 -> none - std::vector shadedHexes; //hexes available for active stack + std::vector occupyableHexes, //hexes available for active stack + attackableHexes; //hexes attackable by active stack int previouslyHoveredHex; //number of hex that was hovered by the cursor a while ago int currentlyHoveredHex; //number of hex that is supposed to be hovered (for a while it may be inappropriately set, but will be renewed soon) float getAnimSpeedMultiplier() const; //returns multiplier for number of frames in a group diff --git a/lib/BattleState.cpp b/lib/BattleState.cpp index 246abb34a..045132687 100644 --- a/lib/BattleState.cpp +++ b/lib/BattleState.cpp @@ -270,7 +270,7 @@ void BattleInfo::makeBFS(THex start, bool *accessibility, THex *predecessor, int } }; -std::vector BattleInfo::getAccessibility(const CStack * stack, bool addOccupiable) const +std::vector BattleInfo::getAccessibility( const CStack * stack, bool addOccupiable, std::vector * attackable ) const { std::vector ret; bool ac[BFIELD_SIZE]; @@ -330,6 +330,48 @@ std::vector BattleInfo::getAccessibility(const CStack * stack, bool addOcc } } + if(attackable) + { + struct HLP + { + static bool meleeAttackable(THex hex, const std::vector & baseRng) + { + BOOST_FOREACH(THex h, baseRng) + { + if(THex::mutualPosition(h, hex) > 0) + return true; + } + + return false; + } + }; + BOOST_FOREACH(const CStack * otherSt, stacks) + { + if(otherSt->owner == stack->owner) + continue; + + std::vector occupiedBySecond; + occupiedBySecond.push_back(otherSt->position); + if(otherSt->doubleWide()) + occupiedBySecond.push_back(otherSt->occupiedHex()); + + if(battleCanShoot(stack, otherSt->position)) + { + attackable->insert(attackable->end(), occupiedBySecond.begin(), occupiedBySecond.end()); + + continue; + } + + + BOOST_FOREACH(THex he, occupiedBySecond) + { + if(HLP::meleeAttackable(he, ret)) + attackable->push_back(he); + } + + } + } + return ret; } bool BattleInfo::isStackBlocked(const CStack * stack) const diff --git a/lib/BattleState.h b/lib/BattleState.h index 31aa201c7..31882cbb7 100644 --- a/lib/BattleState.h +++ b/lib/BattleState.h @@ -90,7 +90,7 @@ struct DLL_EXPORT BattleInfo : public CBonusSystemNode static bool isAccessible(THex hex, bool * accessibility, bool twoHex, bool attackerOwned, bool flying, bool lastPos); //helper for makeBFS void makeBFS(THex start, bool*accessibility, THex *predecessor, int *dists, bool twoHex, bool attackerOwned, bool flying, bool fillPredecessors) const; //*accessibility must be prepared bool[187] array; last two pointers must point to the at least 187-elements int arrays - there is written result std::pair< std::vector, int > getPath(THex start, THex dest, bool*accessibility, bool flyingCreature, bool twoHex, bool attackerOwned); //returned value: pair; length may be different than number of elements in path since flying vreatures jump between distant hexes - std::vector getAccessibility(const CStack * stack, bool addOccupiable) const; //returns vector of accessible tiles (taking into account the creature range) + std::vector getAccessibility(const CStack * stack, bool addOccupiable, std::vector * attackable = NULL) const; //returns vector of accessible tiles (taking into account the creature range) bool isStackBlocked(const CStack * stack) const; //returns true if there is neighboring enemy stack