diff --git a/Mods/vcmi/Data/CCNSSh2.png b/Mods/vcmi/Data/CCNSSh2.png new file mode 100644 index 000000000..2685b0351 Binary files /dev/null and b/Mods/vcmi/Data/CCNSSh2.png differ diff --git a/Mods/vcmi/Data/CCNSShd.png b/Mods/vcmi/Data/CCNSShd.png new file mode 100644 index 000000000..c85265c86 Binary files /dev/null and b/Mods/vcmi/Data/CCNSShd.png differ diff --git a/client/battle/BattleFieldController.cpp b/client/battle/BattleFieldController.cpp index c11d82a93..dc943d653 100644 --- a/client/battle/BattleFieldController.cpp +++ b/client/battle/BattleFieldController.cpp @@ -43,6 +43,7 @@ BattleFieldController::BattleFieldController(BattleInterface & owner): //preparing cells and hexes cellBorder = IImage::createFromFile("CCELLGRD.BMP", EImageBlitMode::COLORKEY); + cellUnitMovementHighlight = IImage::createFromFile("CCNSSHD.BMP", EImageBlitMode::COLORKEY); cellShade = IImage::createFromFile("CCELLSHD.BMP"); if(!owner.siegeController) @@ -138,7 +139,6 @@ void BattleFieldController::showBackground(Canvas & canvas) showBackgroundImage(canvas); showHighlightedHexes(canvas); - } void BattleFieldController::showBackgroundImage(Canvas & canvas) @@ -172,32 +172,39 @@ void BattleFieldController::redrawBackgroundWithHexes() { const CStack *activeStack = owner.stacksController->getActiveStack(); std::vector attackableHexes; - if (activeStack) + if(activeStack) occupyableHexes = owner.curInt->cb->battleGetAvailableHexes(activeStack, true, &attackableHexes); - //prepare background graphic with hexes and shaded hexes + auto accessibility = owner.curInt->cb->getAccesibility(); + + for(int i = 0; i < accessibility.size(); i++) + stackCountOutsideHexes[i] = (accessibility[i] == EAccessibility::ACCESSIBLE); + + // prepare background graphic with hexes and shaded hexes backgroundWithHexes->draw(background, Point(0,0)); owner.obstacleController->showAbsoluteObstacles(*backgroundWithHexes); - if ( owner.siegeController ) + if(owner.siegeController) owner.siegeController->showAbsoluteObstacles(*backgroundWithHexes); - if (settings["battle"]["stackRange"].Bool()) + // show shaded hexes for active's stack valid movement and the hexes that it can attack + if(settings["battle"]["stackRange"].Bool()) { std::vector hexesToShade = occupyableHexes; hexesToShade.insert(hexesToShade.end(), attackableHexes.begin(), attackableHexes.end()); - for (BattleHex hex : hexesToShade) + for(BattleHex hex : hexesToShade) { backgroundWithHexes->draw(cellShade, hexPositionLocal(hex).topLeft()); } } + // draw cell borders if(settings["battle"]["cellBorders"].Bool()) { - for (int i=0; idraw(cellBorder, hexPositionLocal(i).topLeft()); @@ -205,7 +212,7 @@ void BattleFieldController::redrawBackgroundWithHexes() } } -void BattleFieldController::showHighlightedHex(Canvas & canvas, BattleHex hex, bool darkBorder) +void BattleFieldController::showShadedHex(Canvas & canvas, BattleHex hex, bool darkBorder) { Point hexPos = hexPositionLocal(hex).topLeft(); @@ -214,14 +221,23 @@ void BattleFieldController::showHighlightedHex(Canvas & canvas, BattleHex hex, b canvas.draw(cellBorder, hexPos); } -std::set BattleFieldController::getHighlightedHexesStackRange() +void BattleFieldController::showHighlightedHexForMovement(Canvas & canvas, BattleHex hex, bool darkBorder) +{ + Point hexPos = hexPositionLocal(hex).topLeft(); + + canvas.draw(cellUnitMovementHighlight, hexPos); + if(!darkBorder && settings["battle"]["cellBorders"].Bool()) + canvas.draw(cellBorder, hexPos); +} + +std::set BattleFieldController::getHighlightedHexesForActiveStack() { std::set result; - if ( !owner.stacksController->getActiveStack()) + if(!owner.stacksController->getActiveStack()) return result; - if ( !settings["battle"]["stackRange"].Bool()) + if(!settings["battle"]["stackRange"].Bool()) return result; auto hoveredHex = getHoveredHex(); @@ -230,7 +246,22 @@ std::set BattleFieldController::getHighlightedHexesStackRange() for(BattleHex hex : set) result.insert(hex); - // display the movement shadow of stack under mouse + return result; +} + +std::set BattleFieldController::getMovementRangeForHoveredStack() +{ + std::set result; + + if (!owner.stacksController->getActiveStack()) + return result; + + if (!settings["battle"]["stackRange"].Bool()) + return result; + + auto hoveredHex = getHoveredHex(); + + // add possible movement hexes for stack under mouse const CStack * const hoveredStack = owner.curInt->cb->battleGetStackByPos(hoveredHex, true); if(hoveredStack && hoveredStack != owner.stacksController->getActiveStack()) { @@ -241,7 +272,7 @@ std::set BattleFieldController::getHighlightedHexesStackRange() return result; } -std::set BattleFieldController::getHighlightedHexesSpellRange() +std::set BattleFieldController::getHighlightedHexesForSpellRange() { std::set result; auto hoveredHex = getHoveredHex(); @@ -260,9 +291,9 @@ std::set BattleFieldController::getHighlightedHexesSpellRange() { // printing shaded hex(es) spells::BattleCast event(owner.curInt->cb.get(), caster, mode, spell); - auto shaded = spell->battleMechanics(&event)->rangeInHexes(hoveredHex); + auto shadedHexes = spell->battleMechanics(&event)->rangeInHexes(hoveredHex); - for(BattleHex shadedHex : shaded) + for(BattleHex shadedHex : shadedHexes) { if((shadedHex.getX() != 0) && (shadedHex.getX() != GameConstants::BFIELD_WIDTH - 1)) result.insert(shadedHex); @@ -276,72 +307,74 @@ std::set BattleFieldController::getHighlightedHexesMovementTarget() const CStack * stack = owner.stacksController->getActiveStack(); auto hoveredHex = getHoveredHex(); - if (stack) + if(!stack) + return {}; + + std::vector availableHexes = owner.curInt->cb->battleGetAvailableHexes(stack, false, nullptr); + + auto hoveredStack = owner.curInt->cb->battleGetStackByPos(hoveredHex, true); + if(owner.curInt->cb->battleCanAttack(stack, hoveredStack, hoveredHex)) { - std::vector v = owner.curInt->cb->battleGetAvailableHexes(stack, false, nullptr); - - auto hoveredStack = owner.curInt->cb->battleGetStackByPos(hoveredHex, true); - if(owner.curInt->cb->battleCanAttack(stack, hoveredStack, hoveredHex)) + if(isTileAttackable(hoveredHex)) { - if (isTileAttackable(hoveredHex)) - { - BattleHex attackFromHex = fromWhichHexAttack(hoveredHex); + BattleHex attackFromHex = fromWhichHexAttack(hoveredHex); - if (stack->doubleWide()) - return {attackFromHex, stack->occupiedHex(attackFromHex)}; - else - return {attackFromHex}; - } - } - - if (vstd::contains(v,hoveredHex)) - { - if (stack->doubleWide()) - return {hoveredHex, stack->occupiedHex(hoveredHex)}; + if(stack->doubleWide()) + return {attackFromHex, stack->occupiedHex(attackFromHex)}; else - return {hoveredHex}; - } - if (stack->doubleWide()) - { - for (auto const & hex : v) - { - if (stack->occupiedHex(hex) == hoveredHex) - return { hoveredHex, hex }; - } + return {attackFromHex}; } } + + if(vstd::contains(availableHexes, hoveredHex)) + { + if(stack->doubleWide()) + return {hoveredHex, stack->occupiedHex(hoveredHex)}; + else + return {hoveredHex}; + } + + if(stack->doubleWide()) + { + for(auto const & hex : availableHexes) + { + if(stack->occupiedHex(hex) == hoveredHex) + return {hoveredHex, hex}; + } + } + return {}; } void BattleFieldController::showHighlightedHexes(Canvas & canvas) { - std::set hoveredStack = getHighlightedHexesStackRange(); - std::set hoveredSpell = getHighlightedHexesSpellRange(); - std::set hoveredMove = getHighlightedHexesMovementTarget(); + //std::set hoveredStack = getHighlightedHexesForActiveStack(); + std::set hoveredStackHexes = getMovementRangeForHoveredStack(); + std::set hoveredSpellHexes = getHighlightedHexesForSpellRange(); + std::set hoveredMoveHexes = getHighlightedHexesMovementTarget(); - if (getHoveredHex() == BattleHex::INVALID) + if(getHoveredHex() == BattleHex::INVALID) return; - auto const & hoveredMouse = owner.actionsController->currentActionSpellcasting(getHoveredHex()) ? hoveredSpell : hoveredMove; + auto const & hoveredMouseHexes = owner.actionsController->currentActionSpellcasting(getHoveredHex()) ? hoveredSpellHexes : hoveredMoveHexes; for(int b=0; b background; std::shared_ptr cellBorder; + std::shared_ptr cellUnitMovementHighlight; std::shared_ptr cellShade; /// Canvas that contains background, hex grid (if enabled), absolute obstacles and movement range of active stack @@ -46,10 +47,12 @@ class BattleFieldController : public CIntObject /// hexes that when in front of a unit cause it's amount box to move back std::array stackCountOutsideHexes; - void showHighlightedHex(Canvas & to, BattleHex hex, bool darkBorder); + void showHighlightedHexForMovement(Canvas& canvas, BattleHex hex, bool darkBorder); + void showShadedHex(Canvas & to, BattleHex hex, bool darkBorder); - std::set getHighlightedHexesStackRange(); - std::set getHighlightedHexesSpellRange(); + std::set getHighlightedHexesForActiveStack(); + std::set getMovementRangeForHoveredStack(); + std::set getHighlightedHexesForSpellRange(); std::set getHighlightedHexesMovementTarget(); void showBackground(Canvas & canvas);