• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!
  • 2026 staff recruitment is open! Check it out and consider applying!

Real ethereal shot

Evan

A splendid one to behold
Senator
Premium User
Joined
May 6, 2009
Messages
7,018
Solutions
1
Reaction score
1,040
Location
United States
I'm looking for this script:

You have a crossbow in your hands + bolts
When you control-click the crossbow, it does the ethereal spear spell (exori con). But only if you have bolts and is attacking a monster.
It should have exhaust for about 3 seconds and takes 20 mana

Get what I mean?





It may be horrible, but this is what I could try, but it didn't work.
local ID = 2455

local exhaust = createConditionObject(CONDITION_EXHAUST)
setConditionParam(exhaust, CONDITION_PARAM_TICKS, (getConfigInfo('timeBetweenExActions') - 100))

local condition = createConditionObject(CONDITION_HASTE)
setConditionParam(condition, CONDITION_PARAM_TICKS, 22000)
setConditionFormula(condition, 1.0, -50, 1.0, -50)

local combat = createCombatObject()
setCombatParam(combat, COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE)
setCombatParam(combat, COMBAT_PARAM_BLOCKARMOR, true)
setCombatParam(combat, COMBAT_PARAM_DISTANCEEFFECT, CONST_ANI_ETHEREALSPEAR)

function onGetFormulaValues(cid, level, skill, attack, factor)
return -(((skill + 25) / 3) + (level / 5)), -((skill + 25) + (level / 5))
end

setCombatCallback(combat, CALLBACK_PARAM_SKILLVALUE, "onGetFormulaValues")

function onUse(cid, item, fromPosition, itemEx, toPosition, var, combat)

if(hasCondition(cid, CONDITION_EXHAUST_HEAL)) == false and item.itemid == ID then
doAddCondition(cid, exhaust)
return doCombat(cid, combat, var)
end
end
 
Last edited:
Easy :/
Code:
local exhaust = createConditionObject(CONDITION_EXHAUST)
setConditionParam(exhaust, CONDITION_PARAM_TICKS, 3000)

local combat = createCombatObject()
setCombatParam(combat, COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE)
setCombatParam(combat, COMBAT_PARAM_BLOCKARMOR, true)
setCombatParam(combat, COMBAT_PARAM_DISTANCEEFFECT, CONST_ANI_ETHEREALSPEAR)
function onGetFormulaValues(cid, level, skill, attack, factor)
	return -(((skill + 25) / 3) + (level / 5)), -((skill + 25) + (level / 5))
end
setCombatCallback(combat, CALLBACK_PARAM_SKILLVALUE, "onGetFormulaValues")

function onUse(cid, item, fromPosition, itemEx, toPosition)
	if getPlayerMana(cid) >= 20 then
		if not hasCondition(cid, CONDITION_EXHAUST) then
			if getCreatureTarget(cid) > 0 then
				if getPlayerSlotItem(cid, CONST_SLOT_AMMO).itemid == 2543 then
					doAddCondition(cid, exhaust)
					doRemoveItem(getPlayerSlotItem(cid, CONST_SLOT_AMMO).uid, 1)
					doPlayerAddSkillTry(cid, SKILL_DISTANCE, 1)
					doCreatureAddMana(cid, -20)
					return doCombat(cid, combat, numberToVariant(getCreatureTarget(cid)))
				else
					return doPlayerSendCancel(cid, 'You don\'t have any ammunition.')
				end
			else
				return doPlayerSendDefaultCancel(cid, RETURNVALUE_YOUCANONLYUSEITONCREATURES)
			end
		else
			return doPlayerSendDefaultCancel(cid, RETURNVALUE_YOUAREEXHAUSTED)
		end
	else
		return doPlayerSendDefaultCancel(cid, RETURNVALUE_NOTENOUGHMANA)
	end
end
It doesn't check whether the crossbow is in your hands :p
 
Last edited:
Okay, let me test it

EDIT:
works awesome and crystal clear!

god dammit, i can't rep you, already gave you one, but when i get the chance to, I will rep you again

EDIT2:
it doesn't take away 20 mana

EDIT3:
fixed it by adding
doPlayerAddMana(cid, -20)
 
Last edited:
Now what if I want to have a magic effect on the target when I use the crossbow?

local exhaust = createConditionObject(CONDITION_EXHAUST)
setConditionParam(exhaust, CONDITION_PARAM_TICKS, 3000)

local combat = createCombatObject()
setCombatParam(combat, COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE)
setCombatParam(combat, COMBAT_PARAM_BLOCKARMOR, true)
setCombatParam(combat, COMBAT_PARAM_DISTANCEEFFECT, CONST_ANI_FLAMMINGARROW)
function onGetFormulaValues(cid, level, skill, attack, factor)
return -(((skill + 125) / 3) + (level / 5)), -((skill + 125) + (level / 5))
end
setCombatCallback(combat, CALLBACK_PARAM_SKILLVALUE, "onGetFormulaValues")

local atk = getCreatureTarget(cid)
local target = getCreaturePosition(atk)


function onUse(cid, item, fromPosition, itemEx, toPosition)
if getPlayerMana(cid) >= 20 then
if not hasCondition(cid, CONDITION_EXHAUST) then
if getCreatureTarget(cid) > 0 then
if getPlayerSlotItem(cid, CONST_SLOT_AMMO).itemid == 2543 then
doAddCondition(cid, exhaust)
doSendMagicEffect(target, 31)
doRemoveItem(getPlayerSlotItem(cid, CONST_SLOT_AMMO).uid, 1)
doPlayerAddSkillTry(cid, SKILL_DISTANCE, 1)
doCreatureAddMana(cid, -20)
return doCombat(cid, combat, numberToVariant(getCreatureTarget(cid)))
else
return doPlayerSendCancel(cid, 'You don\'t have any ammunition.')
end
else
return doPlayerSendDefaultCancel(cid, RETURNVALUE_YOUCANONLYUSEITONCREATURES)
end
else
return doPlayerSendDefaultCancel(cid, RETURNVALUE_YOUAREEXHAUSTED)
end
else
return doPlayerSendDefaultCancel(cid, RETURNVALUE_NOTENOUGHMANA)
end
end


The things in red is what I added, but unfortunately, it's not working.
 
omg use
Code:
 tags instead of [QUOTE]
[CODE]local exhaust = createConditionObject(CONDITION_EXHAUST)
setConditionParam(exhaust, CONDITION_PARAM_TICKS, 3000)

local combat = createCombatObject()
setCombatParam(combat, COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE)
setCombatParam(combat, COMBAT_PARAM_BLOCKARMOR, true)
setCombatParam(combat, COMBAT_PARAM_DISTANCEEFFECT, CONST_ANI_ETHEREALSPEAR)
function onGetFormulaValues(cid, level, skill, attack, factor)
	return -(((skill + 25) / 3) + (level / 5)), -((skill + 25) + (level / 5))
end
setCombatCallback(combat, CALLBACK_PARAM_SKILLVALUE, "onGetFormulaValues")

function onUse(cid, item, fromPosition, itemEx, toPosition)
	if getPlayerMana(cid) >= 20 then
		if not hasCondition(cid, CONDITION_EXHAUST) then
			if getCreatureTarget(cid) > 0 then
				if getPlayerSlotItem(cid, CONST_SLOT_AMMO).itemid == 2543 then
					doAddCondition(cid, exhaust)
					doSendMagicEffect(getThingPos(getCreatureTarget(cid)), CONST_ME_STUN)
					doRemoveItem(getPlayerSlotItem(cid, CONST_SLOT_AMMO).uid, 1)
					doPlayerAddSkillTry(cid, SKILL_DISTANCE, 1)
					doCreatureAddMana(cid, -20)
					return doCombat(cid, combat, numberToVariant(getCreatureTarget(cid)))
				else
					return doPlayerSendCancel(cid, 'You don\'t have any ammunition.')
				end
			else
				return doPlayerSendDefaultCancel(cid, RETURNVALUE_YOUCANONLYUSEITONCREATURES)
			end
		else
			return doPlayerSendDefaultCancel(cid, RETURNVALUE_YOUAREEXHAUSTED)
		end
	else
		return doPlayerSendDefaultCancel(cid, RETURNVALUE_NOTENOUGHMANA)
	end
end
 
lol, sorry :D

thanks and it works :)
looking forward to finishing a good war server, it's going to be interesting (no spells+no runes and many other stuff)
 
is in the way! but too bad there's no such Lua function
Code:
function canThrowObjectTo(fromPos, toPos, checkLineOfSight, rangex, rangey)
	local checkLineOfSight, rangex, rangey = checkLineOfSight == nil and true or checkLineOfSight, rangex or 7, rangey or 5
	--z checks
	--underground 8->15
	--ground level and above 7->0
	if((fromPos.z >= 8 and toPos.z < 8) or (toPos.z >= 8 and fromPos.z < 8) or fromPos.z - fromPos.z > 2) then
		return false
	end

	local deltax, deltay, deltaz = math.abs(fromPos.x - toPos.x), math.abs(fromPos.y - toPos.y), math.abs(fromPos.z - toPos.z)
	if(deltax - deltaz > rangex or deltay - deltaz > rangey) then
		return false
	end

	if(not checkLineOfSight) then
		return true
	end

	return isSightClear(fromPos, toPos, false)
end
	
function checkSightLine(fromPos, toPos)
	local start = {x=fromPos.x,y=fromPos.y,z=fromPos.z}
	local _end = {x=toPos.x,y=fromPos.y,z=fromPos.z}

	local x, y, z, dx, dy, dz, sx, sy, sz, ey, ez, max, dir = nil, nil, nil, math.abs(start.x - _end.x), math.abs(start.y - _end.y), math.abs(start.z - _end.z), nil, nil, nil, nil, nil, nil, 0
	max = dx

	if(dy > max) then
		max = dy
		dir = 1
	end

	if(dz > max) then
		max = dz
		dir = 2
	end

	if(dir == 1) then
		-- x -> y
		-- y -> x
		-- z -> z
		start.x, start.y = start.y, start.x
		_end.x, _end.y = _end.y, _end.x
		dy, dy = dy, dx
	elseif(dir == 2) then
		-- x -> z
		-- y -> y
		-- z -> x
		start.x, start.z = start.z, start.x
		_end.x, _end.z = _end.z, _end.x
		dx, dz = dz, dx
	end

	sx = ((start.x < _end.x) and 1 or -1)
	sy = ((start.y < _end.y) and 1 or -1)
	sz = ((start.z < _end.z) and 1 or -1)

	ey, ez = 0, 0
	x = start.x
	y = start.y
	z = start.z

	local lastrx, lastry, lastrz = 0, 0, 0
	while(x ~= _end.x + sx) do
		local rx, ry, rz = nil, nil, nil
		if(dir == 1) then
			rx, ry, rz = y, x, z
		elseif(dir == 1) then
			rx, ry, rz = z, y, x
		else
			rx, ry, rz = x, y, z
		end

		if(not lastrx and not lastry and not lastrz) then
			lastrx = rx
			lastry = ry
			lastrz = rz
		end

		if(lastrz ~= rz or ((toPos.x ~= rx or toPos.y ~= ry or toPos.z ~= rz) and (fromPos.x ~= rx or fromPos.y ~= ry or fromPos.z ~= rz))) then
			if(lastrz ~= rz and getTileThingByPos({x = lastrx, y = lastry, z = math.min(lastrz, rz), stackpos = 0}).uid > 0) then
				return false
			end

			lastrx, lastry, lastrz = rx, ry, rz
			local tile = getTileThingByPos({x = rx, y = ry, z = rz, stackpos = 0}).uid
			if(tile > 0 and hasProperty(tile, CONST_PROP_BLOCKPROJECTILE)) then
				return false
			end
		end

		ey = ey + dy
		ez = ez + dz

		if(2 * ey >= dx) then
			y = y + sy;
			ey = ey - dx;
		end

		if(2 * ez >= dx) then
			z = z + sz;
			ez = ez - dx;
		end

		x = x + sx
	end
	
	return true
end

function isSightClear(fromPos, toPos, floorCheck)
	if(floorCheck and fromPos.z ~= toPos.z) then
		return false
	end

	-- Cast two converging rays and see if either yields a result.
	return checkSightLine(fromPos, toPos) or checkSightLine(toPos, fromPos)
end
:/ from map.cpp
 
Last edited:
Complete script:
Code:
local range = 5 -- set to -1 for unlimited

local exhaust = createConditionObject(CONDITION_EXHAUST)
setConditionParam(exhaust, CONDITION_PARAM_TICKS, 3000)

local combat = createCombatObject()
setCombatParam(combat, COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE)
setCombatParam(combat, COMBAT_PARAM_BLOCKARMOR, true)
setCombatParam(combat, COMBAT_PARAM_DISTANCEEFFECT, CONST_ANI_ETHEREALSPEAR)
function onGetFormulaValues(cid, level, skill, attack, factor)
	return -(((skill + 25) / 3) + (level / 5)), -((skill + 25) + (level / 5))
end
setCombatCallback(combat, CALLBACK_PARAM_SKILLVALUE, "onGetFormulaValues")

function canThrowObjectTo(fromPos, toPos, checkLineOfSight, rangex, rangey)
	local checkLineOfSight, rangex, rangey = checkLineOfSight == nil and true or checkLineOfSight, rangex or 7, rangey or 5
	--z checks
	--underground 8->15
	--ground level and above 7->0
	if((fromPos.z >= 8 and toPos.z < 8) or (toPos.z >= 8 and fromPos.z < 8) or fromPos.z - fromPos.z > 2) then
		return false
	end

	local deltax, deltay, deltaz = math.abs(fromPos.x - toPos.x), math.abs(fromPos.y - toPos.y), math.abs(fromPos.z - toPos.z)
	if(deltax - deltaz > rangex or deltay - deltaz > rangey) then
		return false
	end

	if(not checkLineOfSight) then
		return true
	end

	return isSightClear(fromPos, toPos, false)
end
	
function checkSightLine(fromPos, toPos)
	local start = fromPos
	local _end = toPos

	local x, y, z, dx, dy, dz, sx, sy, sz, ey, ez, max, dir = nil, nil, nil, math.abs(start.x - _end.x), math.abs(start.y - _end.y), math.abs(start.z - _end.z), nil, nil, nil, nil, nil, nil, 0
	max = dx

	if(dy > max) then
		max = dy
		dir = 1
	end

	if(dz > max) then
		max = dz
		dir = 2
	end

	if(dir == 1) then
		-- x -> y
		-- y -> x
		-- z -> z
		start.x, start.y = start.y, start.x
		_end.x, _end.y = _end.y, _end.x
		dy, dy = dy, dx
	elseif(dir == 2) then
		-- x -> z
		-- y -> y
		-- z -> x
		start.x, start.z = start.z, start.x
		_end.x, _end.z = _end.z, _end.x
		dx, dz = dz, dx
	end

	sx = ((start.x < _end.x) and 1 or -1)
	sy = ((start.y < _end.y) and 1 or -1)
	sz = ((start.z < _end.z) and 1 or -1)

	ey, ez = 0, 0
	x = start.x
	y = start.y
	z = start.z

	local lastrx, lastry, lastrz = 0, 0, 0
	while(x ~= _end.x + sx) do
		local rx, ry, rz = nil, nil, nil
		if(dir == 1) then
			rx, ry, rz = y, x, z
		elseif(dir == 1) then
			rx, ry, rz = z, y, x
		else
			rx, ry, rz = x, y, z
		end

		if(not lastrx and not lastry and not lastrz) then
			lastrx = rx
			lastry = ry
			lastrz = rz
		end

		if(lastrz ~= rz or ((toPos.x ~= rx or toPos.y ~= ry or toPos.z ~= rz) and (fromPos.x ~= rx or fromPos.y ~= ry or fromPos.z ~= rz))) then
			if(lastrz ~= rz and getTileThingByPos({x = lastrx, y = lastry, z = math.min(lastrz, rz), stackpos = 0}).uid > 0) then
				return false
			end

			lastrx, lastry, lastrz = rx, ry, rz
			local tile = getTileThingByPos({x = rx, y = ry, z = rz, stackpos = 0}).uid
			if(tile > 0 and hasProperty(tile, CONST_PROP_BLOCKPROJECTILE)) then
				return false
			end
		end

		ey = ey + dy
		ez = ez + dz

		if(2 * ey >= dx) then
			y = y + sy;
			ey = ey - dx;
		end

		if(2 * ez >= dx) then
			z = z + sz;
			ez = ez - dx;
		end

		x = x + sx
	end
	
	return true
end

function isSightClear(fromPos, toPos, floorCheck)
	if(floorCheck and fromPos.z ~= toPos.z) then
		return false
	end

	-- Cast two converging rays and see if either yields a result.
	return checkSightLine(fromPos, toPos)
end

function onUse(cid, item, fromPosition, itemEx, toPosition)
	if getPlayerMana(cid) >= 20 then
		if not hasCondition(cid, CONDITION_EXHAUST) then
			local target = getCreatureTarget(cid)
			if target > 0 then
				if getPlayerSlotItem(cid, CONST_SLOT_AMMO).itemid == 2543 then
					local fromPos = getThingPos(cid)
					local toPos = getThingPos(target)
					local v = (not(fromPos.z ~= toPos.z or (range == -1 and not canThrowObjectTo(fromPos, toPos, true)) or (range ~= -1 and not canThrowObjectTo(fromPos, toPos, true, range, range))))
					if v then
						doAddCondition(cid, exhaust)
						doRemoveItem(getPlayerSlotItem(cid, CONST_SLOT_AMMO).uid, 1)
						doPlayerAddSkillTry(cid, SKILL_DISTANCE, 1)
						return doCombat(cid, combat, numberToVariant(target))
					else
						return doPlayerSendDefaultCancel(cid, isPlayer(target) and RETURNVALUE_PLAYERISNOTREACHABLE or RETURNVALUE_CREATUREISNOTREACHABLE)
					end
				else
					return doPlayerSendCancel(cid, 'You don\'t have any ammunition.')
				end
			else
				return doPlayerSendDefaultCancel(cid, RETURNVALUE_YOUCANONLYUSEITONCREATURES)
			end
		else
			return doPlayerSendDefaultCancel(cid, RETURNVALUE_YOUAREEXHAUSTED)
		end
	else
		return doPlayerSendDefaultCancel(cid, RETURNVALUE_NOTENOUGHMANA)
	end
end
:)
 
Complete script:
Code:
local range = 5 -- set to -1 for unlimited

local exhaust = createConditionObject(CONDITION_EXHAUST)
setConditionParam(exhaust, CONDITION_PARAM_TICKS, 3000)

local combat = createCombatObject()
setCombatParam(combat, COMBAT_PARAM_TYPE, COMBAT_PHYSICALDAMAGE)
setCombatParam(combat, COMBAT_PARAM_BLOCKARMOR, true)
setCombatParam(combat, COMBAT_PARAM_DISTANCEEFFECT, CONST_ANI_ETHEREALSPEAR)
function onGetFormulaValues(cid, level, skill, attack, factor)
	return -(((skill + 25) / 3) + (level / 5)), -((skill + 25) + (level / 5))
end
setCombatCallback(combat, CALLBACK_PARAM_SKILLVALUE, "onGetFormulaValues")

function canThrowObjectTo(fromPos, toPos, checkLineOfSight, rangex, rangey)
	local checkLineOfSight, rangex, rangey = checkLineOfSight == nil and true or checkLineOfSight, rangex or 7, rangey or 5
	--z checks
	--underground 8->15
	--ground level and above 7->0
	if((fromPos.z >= 8 and toPos.z < 8) or (toPos.z >= 8 and fromPos.z < 8) or fromPos.z - fromPos.z > 2) then
		return false
	end

	local deltax, deltay, deltaz = math.abs(fromPos.x - toPos.x), math.abs(fromPos.y - toPos.y), math.abs(fromPos.z - toPos.z)
	if(deltax - deltaz > rangex or deltay - deltaz > rangey) then
		return false
	end

	if(not checkLineOfSight) then
		return true
	end

	return isSightClear(fromPos, toPos, false)
end
	
function checkSightLine(fromPos, toPos)
	local start = fromPos
	local _end = toPos

	local x, y, z, dx, dy, dz, sx, sy, sz, ey, ez, max, dir = nil, nil, nil, math.abs(start.x - _end.x), math.abs(start.y - _end.y), math.abs(start.z - _end.z), nil, nil, nil, nil, nil, nil, 0
	max = dx

	if(dy > max) then
		max = dy
		dir = 1
	end

	if(dz > max) then
		max = dz
		dir = 2
	end

	if(dir == 1) then
		-- x -> y
		-- y -> x
		-- z -> z
		start.x, start.y = start.y, start.x
		_end.x, _end.y = _end.y, _end.x
		dy, dy = dy, dx
	elseif(dir == 2) then
		-- x -> z
		-- y -> y
		-- z -> x
		start.x, start.z = start.z, start.x
		_end.x, _end.z = _end.z, _end.x
		dx, dz = dz, dx
	end

	sx = ((start.x < _end.x) and 1 or -1)
	sy = ((start.y < _end.y) and 1 or -1)
	sz = ((start.z < _end.z) and 1 or -1)

	ey, ez = 0, 0
	x = start.x
	y = start.y
	z = start.z

	local lastrx, lastry, lastrz = 0, 0, 0
	while(x ~= _end.x + sx) do
		local rx, ry, rz = nil, nil, nil
		if(dir == 1) then
			rx, ry, rz = y, x, z
		elseif(dir == 1) then
			rx, ry, rz = z, y, x
		else
			rx, ry, rz = x, y, z
		end

		if(not lastrx and not lastry and not lastrz) then
			lastrx = rx
			lastry = ry
			lastrz = rz
		end

		if(lastrz ~= rz or ((toPos.x ~= rx or toPos.y ~= ry or toPos.z ~= rz) and (fromPos.x ~= rx or fromPos.y ~= ry or fromPos.z ~= rz))) then
			if(lastrz ~= rz and getTileThingByPos({x = lastrx, y = lastry, z = math.min(lastrz, rz), stackpos = 0}).uid > 0) then
				return false
			end

			lastrx, lastry, lastrz = rx, ry, rz
			local tile = getTileThingByPos({x = rx, y = ry, z = rz, stackpos = 0}).uid
			if(tile > 0 and hasProperty(tile, CONST_PROP_BLOCKPROJECTILE)) then
				return false
			end
		end

		ey = ey + dy
		ez = ez + dz

		if(2 * ey >= dx) then
			y = y + sy;
			ey = ey - dx;
		end

		if(2 * ez >= dx) then
			z = z + sz;
			ez = ez - dx;
		end

		x = x + sx
	end
	
	return true
end

function isSightClear(fromPos, toPos, floorCheck)
	if(floorCheck and fromPos.z ~= toPos.z) then
		return false
	end

	-- Cast two converging rays and see if either yields a result.
	return checkSightLine(fromPos, toPos)
end

function onUse(cid, item, fromPosition, itemEx, toPosition)
	if getPlayerMana(cid) >= 20 then
		if not hasCondition(cid, CONDITION_EXHAUST) then
			local target = getCreatureTarget(cid)
			if target > 0 then
				if getPlayerSlotItem(cid, CONST_SLOT_AMMO).itemid == 2543 then
					local fromPos = getThingPos(cid)
					local toPos = getThingPos(target)
					local v = (not(fromPos.z ~= toPos.z or (range == -1 and not canThrowObjectTo(fromPos, toPos, true)) or (range ~= -1 and not canThrowObjectTo(fromPos, toPos, true, range, range))))
					if v then
						doAddCondition(cid, exhaust)
						doRemoveItem(getPlayerSlotItem(cid, CONST_SLOT_AMMO).uid, 1)
						doPlayerAddSkillTry(cid, SKILL_DISTANCE, 1)
						return doCombat(cid, combat, numberToVariant(target))
					else
						return doPlayerSendDefaultCancel(cid, isPlayer(target) and RETURNVALUE_PLAYERISNOTREACHABLE or RETURNVALUE_CREATUREISNOTREACHABLE)
					end
				else
					return doPlayerSendCancel(cid, 'You don\'t have any ammunition.')
				end
			else
				return doPlayerSendDefaultCancel(cid, RETURNVALUE_YOUCANONLYUSEITONCREATURES)
			end
		else
			return doPlayerSendDefaultCancel(cid, RETURNVALUE_YOUAREEXHAUSTED)
		end
	else
		return doPlayerSendDefaultCancel(cid, RETURNVALUE_NOTENOUGHMANA)
	end
end
:)
0mg;
Code:
bool Map::canThrowObjectTo(const Position& fromPos, const Position& toPos, bool checkLineOfSight /*= true*/,
	int32_t rangex /*= Map::maxClientViewportX*/, int32_t rangey /*= Map::maxClientViewportY*/)
{
	//z checks
	//underground 8->15
	//ground level and above 7->0
	if((fromPos.z >= 8 && toPos.z < 8) || (toPos.z >= 8 &&
		fromPos.z < 8) || fromPos.z - fromPos.z > 2)
		return false;

	int32_t deltax = std::abs(fromPos.x - toPos.x), deltay = std::abs(
		fromPos.y - toPos.y), deltaz = std::abs(fromPos.z - toPos.z);
	if(deltax - deltaz > rangex || deltay - deltaz > rangey)
		return false;

	if(!checkLineOfSight)
		return true;

	return isSightClear(fromPos, toPos, false);
}

bool Map::checkSightLine(const Position& fromPos, const Position& toPos) const
{
	Position start = fromPos;
	Position end = toPos;

	int32_t x, y, z, dx = std::abs(start.x - end.x), dy = std::abs(start.y - end.y),
		dz = std::abs(start.z - end.z), sx, sy, sz, ey, ez, max = dx, dir = 0;
	if(dy > max)
	{
		max = dy;
		dir = 1;
	}

	if(dz > max)
	{
		max = dz;
		dir = 2;
	}

	switch(dir)
	{
		case 1:
			//x -> y
			//y -> x
			//z -> z
			std::swap(start.x, start.y);
			std::swap(end.x, end.y);
			std::swap(dx, dy);
			break;
		case 2:
			//x -> z
			//y -> y
			//z -> x
			std::swap(start.x, start.z);
			std::swap(end.x, end.z);
			std::swap(dx, dz);
			break;
		default:
			//x -> x
			//y -> y
			//z -> z
			break;
	}

	sx = ((start.x < end.x) ? 1 : -1);
	sy = ((start.y < end.y) ? 1 : -1);
	sz = ((start.z < end.z) ? 1 : -1);

	ey = ez = 0;
	x = start.x;
	y = start.y;
	z = start.z;

	int32_t lastrx = 0, lastry = 0, lastrz = 0;
	for(; x != end.x + sx; x += sx)
	{
		int32_t rx, ry, rz;
		switch(dir)
		{
			case 1:
				rx = y; ry = x; rz = z;
				break;
			case 2:
				rx = z; ry = y; rz = x;
				break;
			default:
				rx = x; ry = y; rz = z;
				break;
		}

		if(!lastrx && !lastry && !lastrz)
		{
			lastrx = rx;
			lastry = ry;
			lastrz = rz;
		}

		if(lastrz != rz || ((toPos.x != rx || toPos.y != ry || toPos.z != rz) && (fromPos.x != rx || fromPos.y != ry || fromPos.z != rz)))
		{
			if(lastrz != rz && const_cast<Map*>(this)->getTile(lastrx, lastry, std::min(lastrz, rz)))
				return false;

			lastrx = rx; lastry = ry; lastrz = rz;
			const Tile* tile = const_cast<Map*>(this)->getTile(rx, ry, rz);
			if(tile && tile->hasProperty(BLOCKPROJECTILE))
				return false;
		}

		ey += dy;
		ez += dz;
		if(2 * ey >= dx)
		{
			y += sy;
			ey -= dx;
		}

		if(2 * ez >= dx)
		{
			z += sz;
			ez -= dx;
		}
	}

	return true;
}

bool Map::isSightClear(const Position& fromPos, const Position& toPos, bool floorCheck) const
{
	if(floorCheck && fromPos.z != toPos.z)
		return false;

	// Cast two converging rays and see if either yields a result.
	return checkSightLine(fromPos, toPos) || checkSightLine(toPos, fromPos);
}
kkkkkkkkkkkkkkkkk
 

Similar threads

Back
Top