From bc459b31539f66de413d931a7680a1e421f5e6ec Mon Sep 17 00:00:00 2001 From: pwwwa Date: Wed, 29 Apr 2026 05:12:38 +0300 Subject: [PATCH 1/4] Diagonal terrain melee Allow to hit terrain objects at diagonal directions. Features: switchable at Options -> Advanced -> BOXCE -> BattleScape -> Diagonal Terrain Melee. Alt+Click - addidional targetting helper (allow to hit weird stuff, underfoot stairs and "between" diagonal walls in some cases). --- bin/common/Language/BOXCE/en-US.yml | 3 + bin/common/Language/BOXCE/ru.yml | 3 + src/Battlescape/TileEngine.cpp | 244 +++++++++++++++++++--------- src/Engine/Options.cpp | 10 +- src/Engine/Options.inc.h | 2 +- 5 files changed, 187 insertions(+), 75 deletions(-) diff --git a/bin/common/Language/BOXCE/en-US.yml b/bin/common/Language/BOXCE/en-US.yml index 8916396a6c..65342597ce 100644 --- a/bin/common/Language/BOXCE/en-US.yml +++ b/bin/common/Language/BOXCE/en-US.yml @@ -113,3 +113,6 @@ en-US: WRT_VANILLA: "vanilla formula" hangarType: "Hangar Type" spaceOccupied: "Space Occupied" + # Diagonal Terrain melee + STR_DIAG_TERRAIN_MELEE: "Diagonal Terrain Melee" + STR_DIAG_TERRAIN_MELEE_DESC: "Hitting terrain objects at diagonal directions with melee.{NEWLINE}Requires activated \"TerrainMeleeExtended\" feature.{NEWLINE}{ALT}Alt+click{ALT} - to hit objects at current and adjacent tiles." \ No newline at end of file diff --git a/bin/common/Language/BOXCE/ru.yml b/bin/common/Language/BOXCE/ru.yml index e9a6a266ed..2053474080 100644 --- a/bin/common/Language/BOXCE/ru.yml +++ b/bin/common/Language/BOXCE/ru.yml @@ -111,3 +111,6 @@ ru: WRT_VANILLA: "Формула из оригинальной игры" hangarType: "Тип ангара" spaceOccupied: "Место занято" + # Diagonal Terrain melee + STR_DIAG_TERRAIN_MELEE: "Рукопашно местность по диагонали " + STR_DIAG_TERRAIN_MELEE_DESC: "Атака объектов ландшафта по диагонали в ближнем бою.{NEWLINE}Требует включения опции \"terrainMeleeExtended\".{NEWLINE}{ALT}Alt+клик{ALT} - бить объекты на текущей и соседних клетках." diff --git a/src/Battlescape/TileEngine.cpp b/src/Battlescape/TileEngine.cpp index e983ab2040..af8a2e779d 100644 --- a/src/Battlescape/TileEngine.cpp +++ b/src/Battlescape/TileEngine.cpp @@ -5968,53 +5968,75 @@ bool TileEngine::validTerrainMeleeRange(BattleAction* action) if (direction < 0 || direction > 7) { return false; - } - if (direction % 2 != 0) + } + if (!Options::diagTerrainMelee && direction % 2 != 0) { - // diagonal directions are not supported + // diagonal directions are not supported. pWWWa: if proper option is not activated return false; } + Position p; Pathfinding::directionToVector(direction, &p); - Tile* originTile = _save->getTile(pos); Tile* originTile2 = originTile; - if (originTile && originTile->getTerrainLevel() <= -16) + Tile* neighbouringTile = _save->getTile(pos + p); + Tile* neighbouringTile2 = nullptr; + Tile* neighbouringTile3 = nullptr; + int size = attacker->getArmor()->getSize(); + + if (originTile && originTile->getTerrainLevel() <= -16 && !Options::diagTerrainMelee && !_save->isAltPressed(true)) { - // if we are on the upper part of stairs, target one tile above + // if we are on the upper part of stairs, target one tile above. + Let leave at the same tile altitude with pressed Alt (if there are need to hit stair under feet). pos += Position(0, 0, 1); originTile = _save->getTile(pos); } - Tile* neighbouringTile = _save->getTile(pos + p); - Tile* neighbouringTile2 = nullptr; - int size = attacker->getArmor()->getSize(); + if (size > 1) - { - if (direction == 0) - { - // North - originTile2 = _save->getTile(pos + Position(1, 0, 0)); - neighbouringTile2 = _save->getTile(pos + p + Position(1, 0, 0)); - } - else if (direction == 2) - { - // East - neighbouringTile = _save->getTile(pos + p + Position(1, 0, 0)); - neighbouringTile2 = _save->getTile(pos + p + Position(1, 1, 0)); - } - else if (direction == 4) + { // Big units suggested tiles definition + switch (direction) { - // South - neighbouringTile = _save->getTile(pos + p + Position(0, 1, 0)); - neighbouringTile2 = _save->getTile(pos + p + Position(1, 1, 0)); - } - else if (direction == 6) - { - // West - originTile2 = _save->getTile(pos + Position(0, 1, 0)); - neighbouringTile2 = _save->getTile(pos + p + Position(0, 1, 0)); + case 0: // North + originTile2 = _save->getTile(pos + Position(1, 0, 0)); + neighbouringTile2 = _save->getTile(pos + p + Position(1, 0, 0)); + break; + case 2:// East + originTile = _save->getTile(pos + p); + originTile2 = _save->getTile(pos + p + Position(0, 1, 0)); + neighbouringTile = _save->getTile(pos + p + Position(1, 0, 0)); + neighbouringTile2 = _save->getTile(pos + p + Position(1, 1, 0)); + break; + case 4: // South + originTile = _save->getTile(pos + p); + originTile2 = _save->getTile(pos + p + Position(1, 0, 0)); + neighbouringTile = _save->getTile(pos + p + Position(0, 1, 0)); + neighbouringTile2 = _save->getTile(pos + p + Position(1, 1, 0)); + break; + case 6: // West + originTile2 = _save->getTile(pos + Position(0, 1, 0)); + neighbouringTile2 = _save->getTile(pos + p + Position(0, 1, 0)); + break; + case 1: // North-East + originTile = _save->getTile(pos + Position(1, 0, 0)); + neighbouringTile = _save->getTile(pos + Position(2, -1, 0)); + neighbouringTile2 = _save->getTile(pos + Position(1, -1, 0)); + neighbouringTile3 = _save->getTile(pos + Position(2, 0, 0)); + break; + case 3: // South-East + originTile = _save->getTile(pos + Position(1, 1, 0)); + neighbouringTile = _save->getTile(pos + Position(2, 2, 0)); + neighbouringTile2 = _save->getTile(pos + Position(1, 2, 0)); + neighbouringTile3 = _save->getTile(pos + Position(2, 1, 0)); + break; + case 5: // South-West + originTile = _save->getTile(pos + Position(0, 1, 0)); + neighbouringTile = _save->getTile(pos + Position(-1, 2, 0)); + neighbouringTile2 = _save->getTile(pos + Position(-1, 1, 0)); + neighbouringTile3 = _save->getTile(pos + Position(0, 2, 0)); } - if (!neighbouringTile2 || !originTile2) + + if (direction % 2 != 0) originTile2 = originTile; // "exclude" secondary originTile at diagonal directions for unexpected tile/object targeting + + if ( direction % 2 == 0 && (!neighbouringTile2 || !originTile2) ) { return false; } @@ -6026,14 +6048,18 @@ bool TileEngine::validTerrainMeleeRange(BattleAction* action) MapData* obj = tt->getMapData(tp); if (obj) { - if (dir > -1 && tp == O_OBJECT) - { + if (dir > -1 && tp == O_OBJECT && !(Options::diagTerrainMelee && tt->getSavedGame()->isAltPressed(true))) + { auto bigWall = obj->getBigWall(); if (dir == 0 /*north*/ && bigWall != Pathfinding::BIGWALLNORTH && bigWall != Pathfinding::BIGWALLWESTANDNORTH) return false; if (dir == 2 /*east */ && bigWall != Pathfinding::BIGWALLEAST && bigWall != Pathfinding::BIGWALLEASTANDSOUTH) return false; if (dir == 4 /*south*/ && bigWall != Pathfinding::BIGWALLSOUTH && bigWall != Pathfinding::BIGWALLEASTANDSOUTH) return false; if (dir == 6 /*west */ && bigWall != Pathfinding::BIGWALLWEST && bigWall != Pathfinding::BIGWALLWESTANDNORTH) return false; - } + if (dir == 1 /*NW */ && bigWall != Pathfinding::BIGWALLNWSE) return false; + if (dir == 3 /*NE */ && bigWall != Pathfinding::BIGWALLNESW && bigWall != Pathfinding::BIGWALLEASTANDSOUTH) return false; + if (dir == 5 /*SE */ && bigWall != Pathfinding::BIGWALLNWSE) return false; + if (dir == 7 /*SW */ && bigWall != Pathfinding::BIGWALLNESW && bigWall != Pathfinding::BIGWALLWESTANDNORTH) return false; + } if (tp != O_OBJECT && !obj->isDoor() && !obj->isUFODoor() && tt->getTUCost(tp, MT_WALK) != Pathfinding::INVALID_MOVE_COST) { // it is possible to walk through this (rubble) wall... no need to attack it @@ -6072,47 +6098,112 @@ bool TileEngine::validTerrainMeleeRange(BattleAction* action) } } - if (direction == 0 && setTarget(originTile, O_NORTHWALL, action)) - { - // North: target the north wall of the same tile - return true; - } - else if (direction == 2 && setTarget(neighbouringTile, O_WESTWALL, action)) - { - // East: target the west wall of the neighbouring tile - return true; - } - else if (direction == 4 && setTarget(neighbouringTile, O_NORTHWALL, action)) - { - // South: target the north wall of the neighbouring tile - return true; - } - else if (direction == 6 && setTarget(originTile, O_WESTWALL, action)) - { - // West: target the west wall of the same tile - return true; - } - if (size > 1) + switch (direction) { - if (direction == 0 && setTarget(originTile2, O_NORTHWALL, action)) - { - // North - return true; - } - else if (direction == 2 && setTarget(neighbouringTile2, O_WESTWALL, action)) - { - // East + case 0: // North: target the north wall of the same tile + if (setTarget(originTile, O_NORTHWALL, action)) return true; + break; + case 2: // East: target the west wall of the neighbouring tile + if (setTarget(neighbouringTile, O_WESTWALL, action)) return true; + break; + case 4: // South: target the north wall of the neighbouring tile + if (setTarget(neighbouringTile, O_NORTHWALL, action)) return true; + break; + case 6: // West: target the west wall of the same tile + if (setTarget(originTile, O_WESTWALL, action)) return true; + break; + case 7: + { // North-West targeting. Unified unit size + neighbouringTile2 = _save->getTile(pos + Position(-1, 0, 0)); + neighbouringTile3 = _save->getTile(pos + Position(0, -1, 0)); + + if (setTarget(originTile, O_WESTWALL, action) || + setTarget(originTile, O_NORTHWALL, action) || + setTarget(neighbouringTile2, O_NORTHWALL, action) || + setTarget(neighbouringTile3, O_WESTWALL, action)) return true; } - else if (direction == 4 && setTarget(neighbouringTile2, O_NORTHWALL, action)) + } + + if (size < 2) + { // diagonal targeting priority for small units + switch (direction) { - // South - return true; + case 1: + { // North-East + neighbouringTile2 = _save->getTile(pos + Position(1, 0, 0)); + neighbouringTile3 = _save->getTile(pos + Position(0, -1, 0)); + + if (setTarget(originTile, O_NORTHWALL, action) || + setTarget(neighbouringTile2, O_WESTWALL, action) || + setTarget(neighbouringTile, O_WESTWALL, action) || + setTarget(neighbouringTile2, O_NORTHWALL, action)) + return true; + break; + } + case 3: + { // South-East + neighbouringTile2 = _save->getTile(pos + Position(0, 1, 0)); + neighbouringTile3 = _save->getTile(pos + Position(1, 0, 0)); + + if (setTarget(neighbouringTile2, O_NORTHWALL, action) || + setTarget(neighbouringTile3, O_WESTWALL, action) || + setTarget(neighbouringTile, O_WESTWALL, action) || + setTarget(neighbouringTile, O_NORTHWALL, action)) + return true; + break; + } + case 5: + { // North-East + neighbouringTile2 = _save->getTile(pos + Position(0, 1, 0)); + neighbouringTile3 = _save->getTile(pos + Position(-1, 0, 0)); + + if (setTarget(neighbouringTile2, O_NORTHWALL, action) || + setTarget(originTile, O_WESTWALL, action) || + setTarget(neighbouringTile2, O_WESTWALL, action) || + setTarget(neighbouringTile, O_NORTHWALL, action)) + return true; + break; + } } - else if (direction == 6 && setTarget(originTile2, O_WESTWALL, action)) + } + + if (size > 1) + { // Big units targeting priority + switch (direction) { - // West - return true; + case 0: // North + if (setTarget(originTile2, O_NORTHWALL, action) || setTarget(neighbouringTile2, O_WESTWALL, action)) return true; + break; + case 2: // East + if (setTarget(neighbouringTile2, O_WESTWALL, action) || setTarget(neighbouringTile2, O_NORTHWALL, action)) return true; + break; + case 4: // South + if (setTarget(neighbouringTile2, O_NORTHWALL, action) || setTarget(neighbouringTile2, O_WESTWALL, action)) return true; + break; + case 6: // West + if (setTarget(originTile2, O_WESTWALL, action) || setTarget(neighbouringTile2, O_NORTHWALL, action)) return true; + break; + case 1: // NE + if (setTarget(originTile, O_NORTHWALL, action) || + setTarget(neighbouringTile3, O_WESTWALL, action) || + setTarget(neighbouringTile, O_WESTWALL, action) || + setTarget(neighbouringTile3, O_NORTHWALL, action)) + return true; + break; + case 3: // SE + if (setTarget(neighbouringTile2, O_NORTHWALL, action) || + setTarget(neighbouringTile3, O_WESTWALL, action) || + setTarget(neighbouringTile, O_WESTWALL, action) || + setTarget(neighbouringTile, O_NORTHWALL, action)) + return true; + break; + case 5: // SW + if (setTarget(originTile, O_WESTWALL, action) || + setTarget(neighbouringTile3, O_NORTHWALL, action) || + setTarget(neighbouringTile3, O_WESTWALL, action) || + setTarget(neighbouringTile, O_NORTHWALL, action)) + return true; } } @@ -6121,14 +6212,21 @@ bool TileEngine::validTerrainMeleeRange(BattleAction* action) // All directions: target the object on the neighbouring tile return true; } - if (size > 1) + if (size > 1 && direction % 2 == 0) { if (setTarget(neighbouringTile2, O_OBJECT, action)) { - // All directions + // All non diagonal directions: big unit's second part "want" to break something too. return true; } } + if (_save->isAltPressed(true) && direction % 2 != 0 && + (setTarget(neighbouringTile2, O_OBJECT, action) || + setTarget(neighbouringTile3, O_OBJECT, action))) + { + // Forced neighbour terrain object targeting. Suitable near big walls and terrain stuff targetting&hitting for diagonal directions. + return true; + } } return false; diff --git a/src/Engine/Options.cpp b/src/Engine/Options.cpp index 0b484caef6..b00cce5678 100644 --- a/src/Engine/Options.cpp +++ b/src/Engine/Options.cpp @@ -569,16 +569,21 @@ void createOptionsOTHER() void createAdvancedOptionsOTHER() { + // OTHER options General _info.push_back(OptionInfo(OPTION_OTHER, "showCraftHangar", &showCraftHangar, false, "STR_SHOW_CRAFT_HANGAR", "STR_GENERAL")); - _info.push_back(OptionInfo(OPTION_OTHER, "forcedAbsoluteCosts", &forcedAbsoluteCosts, false, "STR_FORCED_ABSOLUTE_COSTS", "STR_BATTLESCAPE")); + // OTHER options Geoscape _info.push_back(OptionInfo(OPTION_OTHER, "dogfightAI", &dogfightAI, true, "STR_DOGFIGHTAI", "STR_GEOSCAPE")); _info.push_back(OptionInfo(OPTION_OTHER, "aggressiveRetaliation", &aggressiveRetaliation, true, "STR_AGGRESSIVERETALIATION", "STR_GEOSCAPE")); _info.push_back(OptionInfo(OPTION_OTHER, "displayHiddenAlienActivity", &displayHiddenAlienActivity, 0, "STR_DISPLAY_HIDDEN_ALIEN_ACTIVITY", "STR_GEOSCAPE")); + // OTHER options Basescape _info.push_back(OptionInfo(OPTION_OTHER, "baseDefenseProbability", &baseDefenseProbability, false, "STR_DISPLAY_BASE_DEFENSE_PROBABILITY", "STR_BASESCAPE")); _info.push_back(OptionInfo(OPTION_OTHER, "baseDetectionProbability", &baseDetectionProbability, false, "STR_DISPLAY_BASE_DETECTION_PROBABILITY", "STR_BASESCAPE")); + // OTHER options Battlescape + _info.push_back(OptionInfo(OPTION_OTHER, "diagTerrainMelee", &diagTerrainMelee, false, "STR_DIAG_TERRAIN_MELEE", "STR_BATTLESCAPE")); + _info.push_back(OptionInfo(OPTION_OTHER, "forcedAbsoluteCosts", &forcedAbsoluteCosts, false, "STR_FORCED_ABSOLUTE_COSTS", "STR_BATTLESCAPE")); _info.push_back(OptionInfo(OPTION_OTHER, "shootingSpreadMode", &shootingSpreadMode, 1, "STR_SHOOTING_SPREAD_MODE", "STR_BATTLESCAPE")); _info.push_back(OptionInfo(OPTION_OTHER, "useChanceToHit", &useChanceToHit, true, "STR_BATTLECHANCETOHIT", "STR_BATTLESCAPE")); _info.push_back(OptionInfo(OPTION_OTHER, "battleRealisticAccuracy", &battleRealisticAccuracy, false, "STR_BATTLEREALISTICACCURACY", "STR_BATTLESCAPE")); @@ -599,6 +604,7 @@ void createAdvancedOptionsOTHER() _info.push_back(OptionInfo(OPTION_OTHER, "preprimeGrenades", &preprimeGrenades, 1, "STR_PREPRIMEGRENADES", "STR_BATTLESCAPE")); _info.push_back(OptionInfo(OPTION_OTHER, "updateTurnsSinceSeenByClue", &updateTurnsSinceSeenByClue, true, "STR_UPDATETURNSSINCESEENBYCLUE", "STR_BATTLESCAPE")); + // OTHER options AI _info.push_back(OptionInfo(OPTION_OTHER, "brutalAI", &brutalAI, 1, "STR_BRUTALAI", "STR_AI")); _info.push_back(OptionInfo(OPTION_OTHER, "brutalCivilians", &brutalCivilians, 0, "STR_BRUTALCIVILIANS", "STR_AI")); _info.push_back(OptionInfo(OPTION_OTHER, "ignoreDelay", &ignoreDelay, true, "STR_IGNOREDELAY", "STR_AI")); @@ -606,6 +612,8 @@ void createAdvancedOptionsOTHER() _info.push_back(OptionInfo(OPTION_OTHER, "avoidMines", &avoidMines, true, "STR_AVOIDMINES", "STR_AI")); _info.push_back(OptionInfo(OPTION_OTHER, "aiPeformance", &aiPerformanceOptimization, false, "STR_AI_PERFORMANCE", "STR_AI")); _info.push_back(OptionInfo(OPTION_OTHER, "aiCheatMode", &aiCheatMode, 0, "STR_AICHEATMODE", "STR_AI")); + + // OTHER options Autoplay _info.push_back(OptionInfo(OPTION_OTHER, "autoCombat", &autoCombat, false, "STR_AUTOCOMBAT", "STR_AUTO")); _info.push_back(OptionInfo(OPTION_OTHER, "autoCombatEachCombat", &autoCombatEachCombat, true, "STR_AUTOCOMBAT_EACH_COMBAT", "STR_AUTO")); _info.push_back(OptionInfo(OPTION_OTHER, "autoCombatEachTurn", &autoCombatEachTurn, true, "STR_AUTOCOMBAT_EACH_TURN", "STR_AUTO")); diff --git a/src/Engine/Options.inc.h b/src/Engine/Options.inc.h index a4a1e514be..35d9c66a0d 100644 --- a/src/Engine/Options.inc.h +++ b/src/Engine/Options.inc.h @@ -36,7 +36,7 @@ OPT PathPreview battleNewPreviewPath; OPT int shootingSpreadMode, battleRealisticShotDispersion, battleRealisticCoverEfficiency, battleScrollSpeed, battleDragScrollButton, battleFireSpeed, battleXcomSpeed, battleAlienSpeed, battleExplosionHeight, battlescapeScale, battleTerrainSquishyness, preprimeGrenades, battleThrownSpeed; OPT bool traceAI, battleInstantGrenade, battleNotifyDeath, battleTooltips, battleHairBleach, battleAutoEnd, strafe, forceFire, showMoreStatsInInventoryView, allowPsionicCapture, skipNextTurnScreen, disableAutoEquip, battleDragScrollInvert, - battleUFOExtenderAccuracy, useChanceToHit, battleRealisticAccuracy, battleRealisticImprovedAimed, battleRealisticImprovedLof, battleRealisticDisplayRolls, battleRealisticDisplayOthersRolls, battleAltGrenades, battleConfirmFireMode, battleSmoothCamera, noAlienPanicMessages, alienBleeding, instantPrime, strictBlockedChecking, updateTurnsSinceSeenByClue; + battleUFOExtenderAccuracy, useChanceToHit, battleRealisticAccuracy, battleRealisticImprovedAimed, battleRealisticImprovedLof, battleRealisticDisplayRolls, battleRealisticDisplayOthersRolls, battleAltGrenades, battleConfirmFireMode, battleSmoothCamera, noAlienPanicMessages, alienBleeding, instantPrime, strictBlockedChecking, updateTurnsSinceSeenByClue, diagTerrainMelee; OPT SDLKey keyBattleLeft, keyBattleRight, keyBattleUp, keyBattleDown, keyBattleLevelUp, keyBattleLevelDown, keyBattleCenterUnit, keyBattlePrevUnit, keyBattleNextUnit, keyBattleDeselectUnit, keyBattleUseLeftHand, keyBattleUseRightHand, keyBattleInventory, keyBattleMap, keyBattleOptions, keyBattleEndTurn, keyBattleAbort, keyBattleStats, keyBattleKneel, keyBattleReserveKneel, keyBattleReload, keyBattlePersonalLighting, keyBattleReserveNone, keyBattleReserveSnap, keyBattleReserveAimed, keyBattleReserveAuto, From dc4d7e421ca7d5fc343b688ef785339fb32fc107 Mon Sep 17 00:00:00 2001 From: pwwwa Date: Thu, 30 Apr 2026 00:13:01 +0300 Subject: [PATCH 2/4] Update TileEngine.cpp Diagonal Terrain melee refactoring: -separated tile definition and hit positions groups - removed some unuasable conditions; - fixed issue, which allowed to hit "unreachable" object at diagonal directions in some cases. --- src/Battlescape/TileEngine.cpp | 158 +++++++++++++++++++-------------- 1 file changed, 92 insertions(+), 66 deletions(-) diff --git a/src/Battlescape/TileEngine.cpp b/src/Battlescape/TileEngine.cpp index af8a2e779d..b0747fef9a 100644 --- a/src/Battlescape/TileEngine.cpp +++ b/src/Battlescape/TileEngine.cpp @@ -3231,6 +3231,23 @@ TileEngine::ReactionScore TileEngine::determineReactionType(BattleUnit *unit, Ba return reaction; } } + if (unit->isAkimbo() && + unit->getLeftHandWeapon()->getRules()->getConfigAkimbo()->shots < 2 && + unit->getRightHandWeapon()->getRules()->getConfigAkimbo()->shots < 2 && + _save->canUseWeapon(unit->getLeftHandWeapon(), unit, false, BA_AKIMBOSHOT) && + _save->canUseWeapon(unit->getRightHandWeapon(), unit, false, BA_AKIMBOSHOT) ) + { + // Is unit able to perform akimbo shooting with each gun`s ammo + if (BattleActionCost(BA_AKIMBOSHOT, unit, weapon).haveTU() && + !unit->getLeftHandWeapon()->getRules()->isOutOfRange(unit->distance3dToUnitSq(target)) && + !unit->getRightHandWeapon()->getRules()->isOutOfRange(unit->distance3dToUnitSq(target)) && + unit->getLeftHandWeapon()->getAmmoForAction(BA_AKIMBOSHOT) && + unit->getRightHandWeapon()->getAmmoForAction(BA_AKIMBOSHOT)) + { + setReaction(reaction, BA_AKIMBOSHOT, weapon); + return reaction; + } + } if (_save->canUseWeapon(weapon, unit, false, BA_SNAPSHOT)) { // has a gun capable of snap shot with ammo @@ -5991,6 +6008,30 @@ bool TileEngine::validTerrainMeleeRange(BattleAction* action) originTile = _save->getTile(pos); } + if (direction == 7) + { // North-West: Unified unit size North-West tiles definition + neighbouringTile2 = _save->getTile(pos + Position(-1, 0, 0)); + neighbouringTile3 = _save->getTile(pos + Position(0, -1, 0)); + } + + if (size < 2) + { // Small units suggested diagonal tiles definition + switch (direction) + { + case 1: // North-East + neighbouringTile2 = _save->getTile(pos + Position(1, 0, 0)); + neighbouringTile3 = _save->getTile(pos + Position(0, -1, 0)); + break; + case 3: // South-East + neighbouringTile2 = _save->getTile(pos + Position(0, 1, 0)); + neighbouringTile3 = _save->getTile(pos + Position(1, 0, 0)); + break; + case 5: // North-East + neighbouringTile2 = _save->getTile(pos + Position(0, 1, 0)); + neighbouringTile3 = _save->getTile(pos + Position(-1, 0, 0)); + } + } + if (size > 1) { // Big units suggested tiles definition switch (direction) @@ -5999,48 +6040,42 @@ bool TileEngine::validTerrainMeleeRange(BattleAction* action) originTile2 = _save->getTile(pos + Position(1, 0, 0)); neighbouringTile2 = _save->getTile(pos + p + Position(1, 0, 0)); break; + case 1: // North-East + originTile = _save->getTile(pos + Position(1, 0, 0)); + neighbouringTile = _save->getTile(pos + Position(2, -1, 0)); + neighbouringTile2 = _save->getTile(pos + Position(1, -1, 0)); + neighbouringTile3 = _save->getTile(pos + Position(2, 0, 0)); + break; case 2:// East originTile = _save->getTile(pos + p); originTile2 = _save->getTile(pos + p + Position(0, 1, 0)); neighbouringTile = _save->getTile(pos + p + Position(1, 0, 0)); neighbouringTile2 = _save->getTile(pos + p + Position(1, 1, 0)); break; + case 3: // South-East + originTile = _save->getTile(pos + Position(1, 1, 0)); + neighbouringTile = _save->getTile(pos + Position(2, 2, 0)); + neighbouringTile2 = _save->getTile(pos + Position(1, 2, 0)); + neighbouringTile3 = _save->getTile(pos + Position(2, 1, 0)); + break; case 4: // South originTile = _save->getTile(pos + p); originTile2 = _save->getTile(pos + p + Position(1, 0, 0)); neighbouringTile = _save->getTile(pos + p + Position(0, 1, 0)); neighbouringTile2 = _save->getTile(pos + p + Position(1, 1, 0)); break; - case 6: // West - originTile2 = _save->getTile(pos + Position(0, 1, 0)); - neighbouringTile2 = _save->getTile(pos + p + Position(0, 1, 0)); - break; - case 1: // North-East - originTile = _save->getTile(pos + Position(1, 0, 0)); - neighbouringTile = _save->getTile(pos + Position(2, -1, 0)); - neighbouringTile2 = _save->getTile(pos + Position(1, -1, 0)); - neighbouringTile3 = _save->getTile(pos + Position(2, 0, 0)); - break; - case 3: // South-East - originTile = _save->getTile(pos + Position(1, 1, 0)); - neighbouringTile = _save->getTile(pos + Position(2, 2, 0)); - neighbouringTile2 = _save->getTile(pos + Position(1, 2, 0)); - neighbouringTile3 = _save->getTile(pos + Position(2, 1, 0)); - break; case 5: // South-West - originTile = _save->getTile(pos + Position(0, 1, 0)); - neighbouringTile = _save->getTile(pos + Position(-1, 2, 0)); + originTile = _save->getTile(pos + Position(0, 1, 0)); + neighbouringTile = _save->getTile(pos + Position(-1, 2, 0)); neighbouringTile2 = _save->getTile(pos + Position(-1, 1, 0)); neighbouringTile3 = _save->getTile(pos + Position(0, 2, 0)); - } - - if (direction % 2 != 0) originTile2 = originTile; // "exclude" secondary originTile at diagonal directions for unexpected tile/object targeting - - if ( direction % 2 == 0 && (!neighbouringTile2 || !originTile2) ) - { - return false; + break; + case 6: // West + originTile2 = _save->getTile(pos + Position(0, 1, 0)); + neighbouringTile2 = _save->getTile(pos + p + Position(0, 1, 0)); } } + if (originTile && neighbouringTile) { auto setTarget = [](Tile* tt, TilePart tp, BattleAction* aa, int dir = -1) -> bool @@ -6099,7 +6134,7 @@ bool TileEngine::validTerrainMeleeRange(BattleAction* action) } switch (direction) - { + { // Unified size unit case 0: // North: target the north wall of the same tile if (setTarget(originTile, O_NORTHWALL, action)) return true; break; @@ -6112,59 +6147,41 @@ bool TileEngine::validTerrainMeleeRange(BattleAction* action) case 6: // West: target the west wall of the same tile if (setTarget(originTile, O_WESTWALL, action)) return true; break; - case 7: - { // North-West targeting. Unified unit size - neighbouringTile2 = _save->getTile(pos + Position(-1, 0, 0)); - neighbouringTile3 = _save->getTile(pos + Position(0, -1, 0)); - + case 7: // North-West targeting. Unified unit size if (setTarget(originTile, O_WESTWALL, action) || setTarget(originTile, O_NORTHWALL, action) || setTarget(neighbouringTile2, O_NORTHWALL, action) || setTarget(neighbouringTile3, O_WESTWALL, action)) - return true; - } + return true; } if (size < 2) { // diagonal targeting priority for small units switch (direction) { - case 1: - { // North-East - neighbouringTile2 = _save->getTile(pos + Position(1, 0, 0)); - neighbouringTile3 = _save->getTile(pos + Position(0, -1, 0)); - + case 1: // North-East if (setTarget(originTile, O_NORTHWALL, action) || setTarget(neighbouringTile2, O_WESTWALL, action) || setTarget(neighbouringTile, O_WESTWALL, action) || setTarget(neighbouringTile2, O_NORTHWALL, action)) return true; - break; - } - case 3: - { // South-East - neighbouringTile2 = _save->getTile(pos + Position(0, 1, 0)); - neighbouringTile3 = _save->getTile(pos + Position(1, 0, 0)); - + break; + + case 3: // South-East if (setTarget(neighbouringTile2, O_NORTHWALL, action) || setTarget(neighbouringTile3, O_WESTWALL, action) || setTarget(neighbouringTile, O_WESTWALL, action) || setTarget(neighbouringTile, O_NORTHWALL, action)) return true; break; - } - case 5: - { // North-East - neighbouringTile2 = _save->getTile(pos + Position(0, 1, 0)); - neighbouringTile3 = _save->getTile(pos + Position(-1, 0, 0)); - + + case 5: // North-East if (setTarget(neighbouringTile2, O_NORTHWALL, action) || setTarget(originTile, O_WESTWALL, action) || setTarget(neighbouringTile2, O_WESTWALL, action) || setTarget(neighbouringTile, O_NORTHWALL, action)) return true; break; - } } } @@ -6173,16 +6190,24 @@ bool TileEngine::validTerrainMeleeRange(BattleAction* action) switch (direction) { case 0: // North - if (setTarget(originTile2, O_NORTHWALL, action) || setTarget(neighbouringTile2, O_WESTWALL, action)) return true; + if (setTarget(originTile2, O_NORTHWALL, action) || + setTarget(neighbouringTile2, O_WESTWALL, action)) + return true; break; case 2: // East - if (setTarget(neighbouringTile2, O_WESTWALL, action) || setTarget(neighbouringTile2, O_NORTHWALL, action)) return true; + if (setTarget(neighbouringTile2, O_WESTWALL, action) || + setTarget(neighbouringTile2, O_NORTHWALL, action)) + return true; break; case 4: // South - if (setTarget(neighbouringTile2, O_NORTHWALL, action) || setTarget(neighbouringTile2, O_WESTWALL, action)) return true; + if (setTarget(neighbouringTile2, O_NORTHWALL, action) || + setTarget(neighbouringTile2, O_WESTWALL, action)) + return true; break; case 6: // West - if (setTarget(originTile2, O_WESTWALL, action) || setTarget(neighbouringTile2, O_NORTHWALL, action)) return true; + if (setTarget(originTile2, O_WESTWALL, action) || + setTarget(neighbouringTile2, O_NORTHWALL, action)) + return true; break; case 1: // NE if (setTarget(originTile, O_NORTHWALL, action) || @@ -6208,23 +6233,24 @@ bool TileEngine::validTerrainMeleeRange(BattleAction* action) } if (setTarget(neighbouringTile, O_OBJECT, action)) - { - // All directions: target the object on the neighbouring tile - return true; + { + if (direction % 2 == 0 || (direction % 2 != 0 && isTileInLOS(action, neighbouringTile, true))) + { // All directions: target the object on the neighbouring tile (need visibility at diagonals) + return true; + } } if (size > 1 && direction % 2 == 0) - { + { if (setTarget(neighbouringTile2, O_OBJECT, action)) - { - // All non diagonal directions: big unit's second part "want" to break something too. + { // All non diagonal directions: big unit's second part "want" to break something too. return true; } } - if (_save->isAltPressed(true) && direction % 2 != 0 && - (setTarget(neighbouringTile2, O_OBJECT, action) || - setTarget(neighbouringTile3, O_OBJECT, action))) + if ( _save->isAltPressed(true) && direction % 2 != 0 && + ( setTarget(neighbouringTile2, O_OBJECT, action) || + setTarget(neighbouringTile3, O_OBJECT, action) ) ) { - // Forced neighbour terrain object targeting. Suitable near big walls and terrain stuff targetting&hitting for diagonal directions. + // Forced neighbour terrain object targeting helper. Suitable for big walls and terrain stuff targetting-hitting at diagonal directions. return true; } } From d7e2b83360b9515ff760e6f6aa54d9b6ed821f47 Mon Sep 17 00:00:00 2001 From: pwwwa Date: Thu, 30 Apr 2026 00:38:32 +0300 Subject: [PATCH 3/4] Update TileEngine.cpp Removed part of akimbo feature code (reaction shot). --- src/Battlescape/TileEngine.cpp | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/src/Battlescape/TileEngine.cpp b/src/Battlescape/TileEngine.cpp index b0747fef9a..965155ecfa 100644 --- a/src/Battlescape/TileEngine.cpp +++ b/src/Battlescape/TileEngine.cpp @@ -3231,23 +3231,7 @@ TileEngine::ReactionScore TileEngine::determineReactionType(BattleUnit *unit, Ba return reaction; } } - if (unit->isAkimbo() && - unit->getLeftHandWeapon()->getRules()->getConfigAkimbo()->shots < 2 && - unit->getRightHandWeapon()->getRules()->getConfigAkimbo()->shots < 2 && - _save->canUseWeapon(unit->getLeftHandWeapon(), unit, false, BA_AKIMBOSHOT) && - _save->canUseWeapon(unit->getRightHandWeapon(), unit, false, BA_AKIMBOSHOT) ) - { - // Is unit able to perform akimbo shooting with each gun`s ammo - if (BattleActionCost(BA_AKIMBOSHOT, unit, weapon).haveTU() && - !unit->getLeftHandWeapon()->getRules()->isOutOfRange(unit->distance3dToUnitSq(target)) && - !unit->getRightHandWeapon()->getRules()->isOutOfRange(unit->distance3dToUnitSq(target)) && - unit->getLeftHandWeapon()->getAmmoForAction(BA_AKIMBOSHOT) && - unit->getRightHandWeapon()->getAmmoForAction(BA_AKIMBOSHOT)) - { - setReaction(reaction, BA_AKIMBOSHOT, weapon); - return reaction; - } - } + if (_save->canUseWeapon(weapon, unit, false, BA_SNAPSHOT)) { // has a gun capable of snap shot with ammo From 30e3666653829a656e64dcce01ba806a17c5dccc Mon Sep 17 00:00:00 2001 From: pwwwa Date: Fri, 19 Jun 2026 21:30:44 +0300 Subject: [PATCH 4/4] Update TileEngine.cpp Diagonal Terrain Melee refactoring. --- src/Battlescape/TileEngine.cpp | 295 +++++++++++++-------------------- 1 file changed, 118 insertions(+), 177 deletions(-) diff --git a/src/Battlescape/TileEngine.cpp b/src/Battlescape/TileEngine.cpp index 965155ecfa..a1d321b178 100644 --- a/src/Battlescape/TileEngine.cpp +++ b/src/Battlescape/TileEngine.cpp @@ -5948,7 +5948,7 @@ bool TileEngine::validTerrainMeleeRange(BattleAction* action) action->terrainMeleeTilePart = 0; if (action->weapon) - { + { // is melee weapon able to hit terrain ? auto wRule = action->weapon->getRules(); if (wRule->getBattleType() == BT_MELEE) { @@ -5962,12 +5962,10 @@ bool TileEngine::validTerrainMeleeRange(BattleAction* action) } } - Position pos = action->actor->getPosition(); int direction = action->actor->getDirection(); - BattleUnit* attacker = action->actor; if (direction < 0 || direction > 7) - { + { // only horisontal direction are allowed return false; } if (!Options::diagTerrainMelee && direction % 2 != 0) @@ -5976,94 +5974,88 @@ bool TileEngine::validTerrainMeleeRange(BattleAction* action) return false; } + Position pos = action->actor->getPosition(); Position p; Pathfinding::directionToVector(direction, &p); Tile* originTile = _save->getTile(pos); - Tile* originTile2 = originTile; - Tile* neighbouringTile = _save->getTile(pos + p); - Tile* neighbouringTile2 = nullptr; - Tile* neighbouringTile3 = nullptr; - int size = attacker->getArmor()->getSize(); - if (originTile && originTile->getTerrainLevel() <= -16 && !Options::diagTerrainMelee && !_save->isAltPressed(true)) + if (originTile && originTile->getTerrainLevel() <= -16 && !_save->isAltPressed(true)) { - // if we are on the upper part of stairs, target one tile above. + Let leave at the same tile altitude with pressed Alt (if there are need to hit stair under feet). + // if we are on the upper part of stairs, target one tile above. pWWWa: let leave at the same tile altitude with pressed Alt (if there are need to hit stair under feet). pos += Position(0, 0, 1); originTile = _save->getTile(pos); } - if (direction == 7) - { // North-West: Unified unit size North-West tiles definition - neighbouringTile2 = _save->getTile(pos + Position(-1, 0, 0)); - neighbouringTile3 = _save->getTile(pos + Position(0, -1, 0)); - } + Tile* originTile2 = originTile; + Tile* neighbouringTile = _save->getTile(pos + p); + Tile* neighbouringTile2 = nullptr; + Tile* neighbouringTile3 = nullptr; + int size = action->actor->getArmor()->getSize() - 1; // pWWWa: attacker variable removed, cause it used only once - if (size < 2) - { // Small units suggested diagonal tiles definition - switch (direction) - { - case 1: // North-East - neighbouringTile2 = _save->getTile(pos + Position(1, 0, 0)); - neighbouringTile3 = _save->getTile(pos + Position(0, -1, 0)); + switch (direction) + { + case 0: // North + originTile2 = _save->getTile(pos + Position(size, 0, 0)); + neighbouringTile2 = _save->getTile(pos + p + Position(size, 0, 0)); break; - case 3: // South-East - neighbouringTile2 = _save->getTile(pos + Position(0, 1, 0)); - neighbouringTile3 = _save->getTile(pos + Position(1, 0, 0)); + + case 2: // East + originTile = _save->getTile(pos + Position(size, 0, 0)); + originTile2 = _save->getTile(pos + Position(size, size, 0)); + neighbouringTile = _save->getTile(pos + p + Position(size, 0, 0)); + neighbouringTile2 = _save->getTile(pos + p + Position(size, size, 0)); break; - case 5: // North-East - neighbouringTile2 = _save->getTile(pos + Position(0, 1, 0)); - neighbouringTile3 = _save->getTile(pos + Position(-1, 0, 0)); - } - } - if (size > 1) - { // Big units suggested tiles definition - switch (direction) - { - case 0: // North - originTile2 = _save->getTile(pos + Position(1, 0, 0)); - neighbouringTile2 = _save->getTile(pos + p + Position(1, 0, 0)); + case 4: // South + originTile = _save->getTile(pos + Position(0, size, 0)); + originTile2 = _save->getTile(pos + Position(size, size, 0)); + neighbouringTile = _save->getTile(pos + p + Position(0, size, 0)); + neighbouringTile2 = _save->getTile(pos + p + Position(size, size, 0)); break; - case 1: // North-East - originTile = _save->getTile(pos + Position(1, 0, 0)); - neighbouringTile = _save->getTile(pos + Position(2, -1, 0)); - neighbouringTile2 = _save->getTile(pos + Position(1, -1, 0)); - neighbouringTile3 = _save->getTile(pos + Position(2, 0, 0)); + + case 6: // West + originTile2 = _save->getTile(pos + Position(0, size, 0)); + neighbouringTile2 = _save->getTile(pos + p + Position(0, size, 0)); break; - case 2:// East - originTile = _save->getTile(pos + p); - originTile2 = _save->getTile(pos + p + Position(0, 1, 0)); - neighbouringTile = _save->getTile(pos + p + Position(1, 0, 0)); - neighbouringTile2 = _save->getTile(pos + p + Position(1, 1, 0)); + + case 1: // North-East + originTile = _save->getTile(pos + Position(size, 0, 0)); + neighbouringTile = _save->getTile(pos + p + Position(size, 0, 0)); + neighbouringTile2 = _save->getTile(pos + Position(size, -1, 0)); + neighbouringTile3 = _save->getTile(pos + Position(size + 1, 0, 0)); break; + case 3: // South-East - originTile = _save->getTile(pos + Position(1, 1, 0)); - neighbouringTile = _save->getTile(pos + Position(2, 2, 0)); - neighbouringTile2 = _save->getTile(pos + Position(1, 2, 0)); - neighbouringTile3 = _save->getTile(pos + Position(2, 1, 0)); - break; - case 4: // South - originTile = _save->getTile(pos + p); - originTile2 = _save->getTile(pos + p + Position(1, 0, 0)); - neighbouringTile = _save->getTile(pos + p + Position(0, 1, 0)); - neighbouringTile2 = _save->getTile(pos + p + Position(1, 1, 0)); + originTile = _save->getTile(pos + Position(size, size, 0)); + neighbouringTile = _save->getTile(pos + p + Position(size, size, 0)); + neighbouringTile2 = _save->getTile(pos + p + Position(size, size - 1, 0)); + neighbouringTile3 = _save->getTile(pos + p + Position(size - 1, size, 0)); break; + case 5: // South-West - originTile = _save->getTile(pos + Position(0, 1, 0)); - neighbouringTile = _save->getTile(pos + Position(-1, 2, 0)); - neighbouringTile2 = _save->getTile(pos + Position(-1, 1, 0)); - neighbouringTile3 = _save->getTile(pos + Position(0, 2, 0)); + originTile = _save->getTile(pos + Position(0, size, 0)); + neighbouringTile = _save->getTile(pos + p + Position(0, size, 0)); + neighbouringTile2 = _save->getTile(pos + Position(0, size + 1, 0)); + neighbouringTile3 = _save->getTile(pos + Position(- 1, size, 0)); break; - case 6: // West - originTile2 = _save->getTile(pos + Position(0, 1, 0)); - neighbouringTile2 = _save->getTile(pos + p + Position(0, 1, 0)); - } + + case 7: //North-West + neighbouringTile2 = _save->getTile(pos + Position(-1, 0, 0)); + neighbouringTile3 = _save->getTile(pos + Position(0, -1, 0)); } if (originTile && neighbouringTile) { auto setTarget = [](Tile* tt, TilePart tp, BattleAction* aa, int dir = -1) -> bool { + Position origin = tt->getSavedGame()->getTileEngine()->getSightOriginVoxel(aa->actor, tt) + Position(0, 0, -4); + Position target; + + if (!tt->getSavedGame()->getTileEngine()->canTargetTile(&origin, tt, tp, &target, aa->actor, false)) + { // is tile reachable (more predictable targeting queue at diagonals) + return false; + } + MapData* obj = tt->getMapData(tp); if (obj) { @@ -6103,138 +6095,87 @@ bool TileEngine::validTerrainMeleeRange(BattleAction* action) return false; }; - if (setTarget(originTile, O_OBJECT, action, direction)) + if (setTarget(originTile, O_OBJECT, action, direction) || + setTarget(originTile2, O_OBJECT, action, direction)) { // All directions: target the object (marked as big wall) on the current tile return true; } - if (size > 1) - { - if (setTarget(originTile2, O_OBJECT, action, direction)) - { - // All directions - return true; - } - } switch (direction) - { // Unified size unit - case 0: // North: target the north wall of the same tile - if (setTarget(originTile, O_NORTHWALL, action)) return true; - break; - case 2: // East: target the west wall of the neighbouring tile - if (setTarget(neighbouringTile, O_WESTWALL, action)) return true; + { + case 0: // North + if (setTarget(originTile, O_NORTHWALL, action) || + setTarget(originTile2, O_NORTHWALL, action) || + setTarget(neighbouringTile2, O_WESTWALL, action) && size) + return true; break; - case 4: // South: target the north wall of the neighbouring tile - if (setTarget(neighbouringTile, O_NORTHWALL, action)) return true; + + case 2: // East + if (setTarget(neighbouringTile, O_WESTWALL, action) || + setTarget(neighbouringTile2, O_WESTWALL, action) || + setTarget(neighbouringTile2, O_NORTHWALL, action) && size) + return true; break; - case 6: // West: target the west wall of the same tile - if (setTarget(originTile, O_WESTWALL, action)) return true; + + case 4: // South + if (setTarget(neighbouringTile, O_NORTHWALL, action) || + setTarget(neighbouringTile2, O_NORTHWALL, action) || + setTarget(neighbouringTile2, O_WESTWALL, action) && size) + return true; break; - case 7: // North-West targeting. Unified unit size + + case 6: // West if (setTarget(originTile, O_WESTWALL, action) || - setTarget(originTile, O_NORTHWALL, action) || - setTarget(neighbouringTile2, O_NORTHWALL, action) || - setTarget(neighbouringTile3, O_WESTWALL, action)) - return true; - } + setTarget(originTile2, O_WESTWALL, action) || + setTarget(neighbouringTile2, O_NORTHWALL, action) && size) + return true; + break; - if (size < 2) - { // diagonal targeting priority for small units - switch (direction) - { - case 1: // North-East - if (setTarget(originTile, O_NORTHWALL, action) || - setTarget(neighbouringTile2, O_WESTWALL, action) || - setTarget(neighbouringTile, O_WESTWALL, action) || - setTarget(neighbouringTile2, O_NORTHWALL, action)) - return true; - break; + case 1: // North-East + if (setTarget(neighbouringTile, O_WESTWALL, action) || // 3 + setTarget(neighbouringTile3, O_NORTHWALL, action) || // 4 + setTarget(originTile, O_NORTHWALL, action) || // 1 + setTarget(neighbouringTile3, O_WESTWALL, action)) // 2 + return true; + break; - case 3: // South-East - if (setTarget(neighbouringTile2, O_NORTHWALL, action) || - setTarget(neighbouringTile3, O_WESTWALL, action) || - setTarget(neighbouringTile, O_WESTWALL, action) || - setTarget(neighbouringTile, O_NORTHWALL, action)) - return true; - break; + case 3: // South-East + if (setTarget(neighbouringTile, O_WESTWALL, action) || // 3 + setTarget(neighbouringTile, O_NORTHWALL, action) || // 4 + setTarget(neighbouringTile3, O_NORTHWALL, action) || // 1 + setTarget(neighbouringTile2, O_WESTWALL, action)) // 2 + return true; + break; - case 5: // North-East - if (setTarget(neighbouringTile2, O_NORTHWALL, action) || - setTarget(originTile, O_WESTWALL, action) || - setTarget(neighbouringTile2, O_WESTWALL, action) || - setTarget(neighbouringTile, O_NORTHWALL, action)) - return true; - break; - } - } - - if (size > 1) - { // Big units targeting priority - switch (direction) - { - case 0: // North - if (setTarget(originTile2, O_NORTHWALL, action) || - setTarget(neighbouringTile2, O_WESTWALL, action)) - return true; - break; - case 2: // East - if (setTarget(neighbouringTile2, O_WESTWALL, action) || - setTarget(neighbouringTile2, O_NORTHWALL, action)) - return true; - break; - case 4: // South - if (setTarget(neighbouringTile2, O_NORTHWALL, action) || - setTarget(neighbouringTile2, O_WESTWALL, action)) - return true; - break; - case 6: // West - if (setTarget(originTile2, O_WESTWALL, action) || - setTarget(neighbouringTile2, O_NORTHWALL, action)) - return true; - break; - case 1: // NE - if (setTarget(originTile, O_NORTHWALL, action) || - setTarget(neighbouringTile3, O_WESTWALL, action) || - setTarget(neighbouringTile, O_WESTWALL, action) || - setTarget(neighbouringTile3, O_NORTHWALL, action)) - return true; - break; - case 3: // SE - if (setTarget(neighbouringTile2, O_NORTHWALL, action) || - setTarget(neighbouringTile3, O_WESTWALL, action) || - setTarget(neighbouringTile, O_WESTWALL, action) || - setTarget(neighbouringTile, O_NORTHWALL, action)) - return true; - break; - case 5: // SW - if (setTarget(originTile, O_WESTWALL, action) || - setTarget(neighbouringTile3, O_NORTHWALL, action) || - setTarget(neighbouringTile3, O_WESTWALL, action) || - setTarget(neighbouringTile, O_NORTHWALL, action)) - return true; - } - } + case 5: // North-East + if (setTarget(neighbouringTile, O_NORTHWALL, action) || // 4 + setTarget(neighbouringTile2, O_NORTHWALL, action) || // 1 + setTarget(neighbouringTile2, O_WESTWALL, action) || // 3 + setTarget(originTile, O_WESTWALL, action)) // 2 + return true; + break; - if (setTarget(neighbouringTile, O_OBJECT, action)) - { - if (direction % 2 == 0 || (direction % 2 != 0 && isTileInLOS(action, neighbouringTile, true))) - { // All directions: target the object on the neighbouring tile (need visibility at diagonals) + case 7: // North-West + if (setTarget(neighbouringTile3, O_WESTWALL, action) || // 4 + setTarget(neighbouringTile2, O_NORTHWALL, action) || // 3 + setTarget(originTile, O_NORTHWALL, action) || // 2 + setTarget(originTile, O_WESTWALL, action)) // 1 return true; - } } - if (size > 1 && direction % 2 == 0) + + if (setTarget(neighbouringTile, O_OBJECT, action) || + setTarget(neighbouringTile2, O_OBJECT, action) && size && !(direction % 2)) { - if (setTarget(neighbouringTile2, O_OBJECT, action)) - { // All non diagonal directions: big unit's second part "want" to break something too. - return true; - } + // All directions: target the object on the neighbouring tile + big unit's second part at non-diagonal direction included + return true; } - if ( _save->isAltPressed(true) && direction % 2 != 0 && + + if ( _save->isAltPressed(true) && direction % 2 && ( setTarget(neighbouringTile2, O_OBJECT, action) || setTarget(neighbouringTile3, O_OBJECT, action) ) ) { - // Forced neighbour terrain object targeting helper. Suitable for big walls and terrain stuff targetting-hitting at diagonal directions. + // Diagonal terrain object targeting helper. Suitable for hitting big walls and terrain stuff at adjacent tiles. return true; } }