diff --git a/data/scripts/runes/magic_wall.lua b/data/scripts/runes/magic_wall.lua index 26870e1d4a8..5d0fdc55b36 100644 --- a/data/scripts/runes/magic_wall.lua +++ b/data/scripts/runes/magic_wall.lua @@ -1,17 +1,29 @@ function onCreateMagicWall(creature, position) local tile = Tile(position) - if tile and tile:getTopCreature() and not tile:getTopCreature():isPlayer() then + if not tile then return false end + + if tile:hasFlag(TILESTATE_FLOORCHANGE) then + return false + end + + if tile:getTopCreature() and not tile:getTopCreature():isPlayer() then + return false + end + local magicWall if Game.getWorldType() == WORLD_TYPE_NO_PVP then magicWall = ITEM_MAGICWALL_SAFE else magicWall = ITEM_MAGICWALL end + local item = Game.createItem(magicWall, 1, position) - item:setDuration(16, 24) - item:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, string.format("Casted by: %s", creature:getName())) + if item then + item:setDuration(16, 24) + item:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, string.format("Casted by: %s", creature:getName())) + end end local combat = Combat() diff --git a/data/scripts/runes/wild_growth.lua b/data/scripts/runes/wild_growth.lua index 4cb81e2f615..09b0edf7876 100644 --- a/data/scripts/runes/wild_growth.lua +++ b/data/scripts/runes/wild_growth.lua @@ -1,17 +1,29 @@ function onCreateWildGrowth(creature, position) local tile = Tile(position) - if tile and tile:getTopCreature() and not tile:getTopCreature():isPlayer() then + if not tile then return false end + + if tile:hasFlag(TILESTATE_FLOORCHANGE) then + return false + end + + if tile:getTopCreature() and not tile:getTopCreature():isPlayer() then + return false + end + local wildGrowth if Game.getWorldType() == WORLD_TYPE_NO_PVP then wildGrowth = ITEM_WILDGROWTH_SAFE else wildGrowth = ITEM_WILDGROWTH end + local item = Game.createItem(wildGrowth, 1, position) - item:setDuration(30, 60) - item:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, string.format("Casted by: %s", creature:getName())) + if item then + item:setDuration(30) + item:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, string.format("Casted by: %s", creature:getName())) + end end local combat = Combat() diff --git a/src/creatures/combat/combat.cpp b/src/creatures/combat/combat.cpp index 273eb3d382d..396a58aaad5 100644 --- a/src/creatures/combat/combat.cpp +++ b/src/creatures/combat/combat.cpp @@ -121,7 +121,7 @@ void Combat::getCombatArea(const Position ¢erPos, const Position &targetPos, } if (area) { - area->getList(centerPos, targetPos, list); + area->getList(centerPos, targetPos, list, getDirectionTo(targetPos, centerPos)); } else { list.emplace_back(g_game().map.getOrCreateTile(targetPos)); } @@ -253,18 +253,14 @@ ReturnValue Combat::canTargetCreature(const std::shared_ptr &player, con ReturnValue Combat::canDoCombat(const std::shared_ptr &caster, const std::shared_ptr &tile, bool aggressive) { if (tile->hasProperty(CONST_PROP_BLOCKPROJECTILE)) { - return RETURNVALUE_NOTENOUGHROOM; + return RETURNVALUE_CANNOTTHROW; } if (aggressive && tile->hasFlag(TILESTATE_PROTECTIONZONE)) { return RETURNVALUE_ACTIONNOTPERMITTEDINPROTECTIONZONE; } - if (tile->hasFlag(TILESTATE_FLOORCHANGE)) { - return RETURNVALUE_NOTENOUGHROOM; - } - if (tile->getTeleportItem()) { - return RETURNVALUE_NOTENOUGHROOM; + return RETURNVALUE_CANNOTTHROW; } if (caster) { @@ -1886,7 +1882,9 @@ AreaCombat::~AreaCombat() { clear(); } -void AreaCombat::getList(const Position ¢erPos, const Position &targetPos, std::vector> &list) const { +void AreaCombat::getList(const Position ¢erPos, const Position &targetPos, std::vector> &list, const Direction dir) const { + auto casterPos = getNextPosition(dir, targetPos); + const std::unique_ptr &area = getArea(centerPos, targetPos); if (!area) { return; @@ -1898,17 +1896,27 @@ void AreaCombat::getList(const Position ¢erPos, const Position &targetPos, s const uint32_t rows = area->getRows(); const uint32_t cols = area->getCols(); - list.reserve(rows * cols); + list.reserve(rows * cols); Position tmpPos(targetPos.x - centerX, targetPos.y - centerY, targetPos.z); - for (uint32_t y = 0; y < rows; ++y, ++tmpPos.y, tmpPos.x -= cols) { - for (uint32_t x = 0; x < cols; ++x, ++tmpPos.x) { + + for (uint32_t y = 0; y < rows; ++y) { + for (uint32_t x = 0; x < cols; ++x) { if (area->getValue(y, x) != 0) { - if (g_game().isSightClear(targetPos, tmpPos, true)) { + std::shared_ptr tile = g_game().map.getTile(tmpPos); + if (tile && tile->hasFlag(TILESTATE_FLOORCHANGE)) { + ++tmpPos.x; + continue; + } + + if (g_game().isSightClear(casterPos, tmpPos, true)) { list.emplace_back(g_game().map.getOrCreateTile(tmpPos)); } } + ++tmpPos.x; } + ++tmpPos.y; + tmpPos.x -= cols; } } diff --git a/src/creatures/combat/combat.hpp b/src/creatures/combat/combat.hpp index 1b8af711235..3d269074dae 100644 --- a/src/creatures/combat/combat.hpp +++ b/src/creatures/combat/combat.hpp @@ -155,7 +155,7 @@ class AreaCombat { // non-assignable AreaCombat &operator=(const AreaCombat &) = delete; - void getList(const Position ¢erPos, const Position &targetPos, std::vector> &list) const; + void getList(const Position ¢erPos, const Position &targetPos, std::vector> &list, const Direction dir) const; void setupArea(const std::list &list, uint32_t rows); void setupArea(int32_t length, int32_t spread); diff --git a/src/creatures/combat/spells.cpp b/src/creatures/combat/spells.cpp index 2d611f3bfa6..b807d0fa0c2 100644 --- a/src/creatures/combat/spells.cpp +++ b/src/creatures/combat/spells.cpp @@ -549,14 +549,6 @@ bool Spell::playerInstantSpellCheck(const std::shared_ptr &player, const } const auto &tile = g_game().map.getOrCreateTile(toPos); - - ReturnValue ret = Combat::canDoCombat(player, tile, aggressive); - if (ret != RETURNVALUE_NOERROR) { - player->sendCancelMessage(ret); - g_game().addMagicEffect(player->getPosition(), CONST_ME_POFF); - return false; - } - if (blockingCreature && tile->getBottomVisibleCreature(player) != nullptr) { player->sendCancelMessage(RETURNVALUE_NOTENOUGHROOM); g_game().addMagicEffect(player->getPosition(), CONST_ME_POFF);