Skip to content

Commit

Permalink
fix: spells and runes interactions (opentibiabr#3328)
Browse files Browse the repository at this point in the history
  • Loading branch information
kaleohanopahala authored Feb 9, 2025
1 parent 44dc283 commit ab32754
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 27 deletions.
18 changes: 15 additions & 3 deletions data/scripts/runes/magic_wall.lua
Original file line number Diff line number Diff line change
@@ -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()
Expand Down
18 changes: 15 additions & 3 deletions data/scripts/runes/wild_growth.lua
Original file line number Diff line number Diff line change
@@ -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()
Expand Down
50 changes: 38 additions & 12 deletions src/creatures/combat/combat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ void Combat::getCombatArea(const Position &centerPos, 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));
}
Expand Down Expand Up @@ -252,19 +252,33 @@ ReturnValue Combat::canTargetCreature(const std::shared_ptr<Player> &player, con
}

ReturnValue Combat::canDoCombat(const std::shared_ptr<Creature> &caster, const std::shared_ptr<Tile> &tile, bool aggressive) {
if (!aggressive) {
return RETURNVALUE_NOERROR;
}

if (tile->hasProperty(CONST_PROP_BLOCKPROJECTILE)) {
return RETURNVALUE_NOTENOUGHROOM;
bool canThrow = false;

if (const auto fieldList = tile->getItemList()) {
for (const auto &findfield : *fieldList) {
if (findfield && (findfield->getID() == ITEM_MAGICWALL || findfield->getID() == ITEM_MAGICWALL_SAFE)) {
canThrow = true;
break;
}
}
}

if (!canThrow) {
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) {
Expand Down Expand Up @@ -1886,7 +1900,9 @@ AreaCombat::~AreaCombat() {
clear();
}

void AreaCombat::getList(const Position &centerPos, const Position &targetPos, std::vector<std::shared_ptr<Tile>> &list) const {
void AreaCombat::getList(const Position &centerPos, const Position &targetPos, std::vector<std::shared_ptr<Tile>> &list, const Direction dir) const {
auto casterPos = getNextPosition(dir, targetPos);

const std::unique_ptr<MatrixArea> &area = getArea(centerPos, targetPos);
if (!area) {
return;
Expand All @@ -1898,17 +1914,27 @@ void AreaCombat::getList(const Position &centerPos, 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> 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;
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/creatures/combat/combat.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ class AreaCombat {
// non-assignable
AreaCombat &operator=(const AreaCombat &) = delete;

void getList(const Position &centerPos, const Position &targetPos, std::vector<std::shared_ptr<Tile>> &list) const;
void getList(const Position &centerPos, const Position &targetPos, std::vector<std::shared_ptr<Tile>> &list, const Direction dir) const;

void setupArea(const std::list<uint32_t> &list, uint32_t rows);
void setupArea(int32_t length, int32_t spread);
Expand Down
8 changes: 0 additions & 8 deletions src/creatures/combat/spells.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -549,14 +549,6 @@ bool Spell::playerInstantSpellCheck(const std::shared_ptr<Player> &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);
Expand Down

0 comments on commit ab32754

Please sign in to comment.