illarion-content/magic/arcane/castingRange.lua
2025-06-14 09:08:03 +02:00

111 lines
3.4 KiB
Lua

--[[
Illarion Server
This program is free software: you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option) any
later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU Affero General Public License for more
details.
You should have received a copy of the GNU Affero General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>.
]]
local runes = require("magic.arcane.runes")
local magic = require("base.magic")
local M = {}
function M.getCastingRange(user, spell, element)
local baseRange = 7
local wandbonus = 0
if user then
wandbonus = magic.checkElementBonus(user, element)
end
local range = baseRange
if wandbonus == 0.1 then -- Only elemental wands of the correct element for the spell get a range bonus
range = range + 1
end
if runes.checkSpellForRuneByName("KEL", spell) then
range = range + 1
end
return range
end
function M.isTargetInRange(user, spell, element, target)
local range = M.getCastingRange(user, spell, element)
local pos1 = user.pos
local pos2 = target
if target.pos then
pos2 = target.pos
end
local xdif = pos1.x - pos2.x
local ydif = pos1.y - pos2.y
if xdif > range or xdif < -range or ydif > range or ydif < -range or pos1.z ~= pos2.z then
return false
end
return true
end
function M.checkForObstacles(user, spell, pos)
local startingpos = user.pos
local FHAN = runes.checkSpellForRuneByName("FHAN", spell)
local PEN = runes.checkSpellForRuneByName("PEN", spell)
local JUS = runes.checkSpellForRuneByName("JUS", spell)
local obstacleBypass = FHAN and not PEN and not JUS
local blockList = world:LoS(startingpos, pos)
local next = next
if (next(blockList)~=nil) then
if not obstacleBypass then
return true
else
local listIndex = next(blockList)
local object = blockList[listIndex].OBJECT
local objectPos = object.pos
local tileToCheck1 = position(objectPos.x, objectPos.y+2, objectPos.z)
local tileToCheck2 = position(objectPos.x, objectPos.y-2, objectPos.z)
local tileToCheck3 = position(objectPos.x+2, objectPos.y, objectPos.z)
local tileToCheck4 = position(objectPos.x-2, objectPos.y, objectPos.z)
local newBlockList = {}
newBlockList[1] = world:LoS(objectPos, tileToCheck1)
newBlockList[2] = world:LoS(objectPos, tileToCheck2)
newBlockList[3] = world:LoS(objectPos, tileToCheck3)
newBlockList[4] = world:LoS(objectPos, tileToCheck4)
local count = 0
for i = 1, #newBlockList do
if next(newBlockList[i]) then
if newBlockList[i][next(newBlockList[i])].TYPE == "ITEM" then
count = count+1
end
end
end
if count >= 2 then -- if more than two solid objects are found directly adjacent to the first, obstacle will not be ignored to prevent shooting through walls
return true
end
end
end
return false
end
return M