199 lines
4.3 KiB
Lua
199 lines
4.3 KiB
Lua
|
local function table_contains(t, v)
|
||
|
for _,i in pairs(t) do
|
||
|
if v == i then
|
||
|
return true
|
||
|
end
|
||
|
end
|
||
|
return false
|
||
|
end
|
||
|
|
||
|
local creative = minetest.settings:get_bool("creative_mode")
|
||
|
local function throw_pearl(item, player)
|
||
|
local playerpos = player:getpos()
|
||
|
playerpos.y = playerpos.y+1.625
|
||
|
local obj = minetest.add_entity(playerpos, "hell:pearl_entity")
|
||
|
local dir = player:get_look_dir()
|
||
|
obj:setvelocity(vector.multiply(dir, 30))
|
||
|
obj:setacceleration({x=dir.x*-3, y=-dir.y^8*80-10, z=dir.z*-3})
|
||
|
obj:get_luaentity().player = player:get_player_name()
|
||
|
if not creative then
|
||
|
item:take_item()
|
||
|
return item
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local function get_node(pos)
|
||
|
local name = minetest.get_node(pos).name
|
||
|
if name ~= "ignore" then
|
||
|
return name
|
||
|
end
|
||
|
minetest.get_voxel_manip():read_from_map(pos, pos)
|
||
|
name = minetest.get_node_or_nil(pos)
|
||
|
if not name then
|
||
|
return
|
||
|
end
|
||
|
return name.name
|
||
|
end
|
||
|
|
||
|
local softs = {}
|
||
|
local function is_soft(pos)
|
||
|
local name = get_node(pos)
|
||
|
if not name then
|
||
|
return false
|
||
|
end
|
||
|
local is_soft = softs[name]
|
||
|
if is_soft ~= nil then
|
||
|
return is_soft
|
||
|
end
|
||
|
if not minetest.registered_nodes[name] then
|
||
|
softs[name] = false
|
||
|
return false
|
||
|
end
|
||
|
is_soft = minetest.registered_nodes[name].walkable == false
|
||
|
softs[name] = is_soft
|
||
|
return is_soft
|
||
|
end
|
||
|
|
||
|
-- teleports the player there if there's free space
|
||
|
local function teleport_player(pos, player)
|
||
|
if not is_soft(pos) then
|
||
|
return false
|
||
|
end
|
||
|
if not is_soft({x=pos.x, y=pos.y+1, z=pos.z})
|
||
|
and not is_soft({x=pos.x, y=pos.y-1, z=pos.z}) then
|
||
|
return false
|
||
|
end
|
||
|
pos.y = pos.y+0.05
|
||
|
player:moveto(pos)
|
||
|
return true
|
||
|
end
|
||
|
|
||
|
--[[
|
||
|
local dg_ps = {}
|
||
|
local function forceload(pos)
|
||
|
dg_ps[#dg_ps+1] = pos
|
||
|
minetest.forceload_block(pos)
|
||
|
minetest.after(5, function(pos)
|
||
|
minetest.forceload_free_block(pos)
|
||
|
for i,p in pairs(dg_ps) do
|
||
|
if vector.equals(p, pos) then
|
||
|
dg_ps[i] = nil
|
||
|
return
|
||
|
end
|
||
|
end
|
||
|
end, pos)
|
||
|
end
|
||
|
minetest.register_on_shutdown(function()
|
||
|
for _,p in pairs(dg_ps) do
|
||
|
minetest.forceload_free_block(p)
|
||
|
end
|
||
|
end)--]]
|
||
|
|
||
|
minetest.register_entity("hell:pearl_entity", {
|
||
|
collisionbox = {0,0,0,0,0,0}, --not pointable
|
||
|
visual_size = {x=0.1, y=0.1},
|
||
|
physical = false, -- Collides with things
|
||
|
textures = {"hell_pearl.png"},
|
||
|
on_activate = function(self, staticdata)
|
||
|
if not staticdata
|
||
|
or staticdata == "" then
|
||
|
return
|
||
|
end
|
||
|
local tmp = minetest.deserialize(staticdata)
|
||
|
if not tmp then
|
||
|
minetest.log("error", "[hell] pearl: invalid staticdata ")
|
||
|
return
|
||
|
end
|
||
|
self.player = tmp.player
|
||
|
end,
|
||
|
get_staticdata = function(self)
|
||
|
--forceload(vector.round(self.object:getpos()))
|
||
|
return minetest.serialize({
|
||
|
player = self.player,
|
||
|
})
|
||
|
end,
|
||
|
timer = 0,
|
||
|
on_step = function(self, dtime)
|
||
|
self.timer = self.timer+dtime
|
||
|
|
||
|
--[[
|
||
|
local delay = self.delay
|
||
|
if delay < 0.1 then
|
||
|
self.delay = delay+dtime
|
||
|
return
|
||
|
end
|
||
|
self.delay = 0--]]
|
||
|
|
||
|
if self.timer > 20 then
|
||
|
self.object:remove()
|
||
|
return
|
||
|
end
|
||
|
|
||
|
local pos = self.object:getpos()
|
||
|
local rpos = vector.round(pos)
|
||
|
local lastpos = self.lastpos
|
||
|
if not lastpos then
|
||
|
self.lastpos = vector.new(rpos)
|
||
|
return
|
||
|
end
|
||
|
if lastpos.x
|
||
|
and vector.equals(vector.round(lastpos), rpos) then
|
||
|
return
|
||
|
end
|
||
|
|
||
|
local player = self.player
|
||
|
if not player then
|
||
|
minetest.log("error", "[hell] pearl: missing playername")
|
||
|
self.object:remove()
|
||
|
return
|
||
|
end
|
||
|
player = minetest.get_player_by_name(player)
|
||
|
if not player then
|
||
|
minetest.log("error", "[hell] pearl: missing player")
|
||
|
self.object:remove()
|
||
|
return
|
||
|
end
|
||
|
|
||
|
if not get_node(rpos) then
|
||
|
minetest.log("error", "[hell] pearl: missing node")
|
||
|
self.object:remove()
|
||
|
return
|
||
|
end
|
||
|
|
||
|
self.lastpos = vector.new(pos)
|
||
|
|
||
|
local free, p = minetest.line_of_sight(lastpos, pos)
|
||
|
if free then
|
||
|
return
|
||
|
end
|
||
|
if is_soft(p) then
|
||
|
return
|
||
|
end
|
||
|
self.object:remove()
|
||
|
minetest.after(0, function(p) --minetest.after is used that the sound is played after the teleportation
|
||
|
minetest.sound_play("hell_pearl", {pos=p, max_hear_distance=10})
|
||
|
end, p)
|
||
|
p.y = p.y+1
|
||
|
if teleport_player(vector.new(p), player) then
|
||
|
return
|
||
|
end
|
||
|
p.y = p.y-2
|
||
|
for i = -1,1,2 do
|
||
|
for _,j in pairs({{i, 0}, {0, i}}) do
|
||
|
if teleport_player({x=p.x+j[1], y=p.y, z=p.z+j[2]}, player) then
|
||
|
return
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
for i = -1,1,2 do
|
||
|
for j = -1,1,2 do
|
||
|
if teleport_player({x=p.x+j, y=p.y, z=p.z+i}, player) then
|
||
|
return
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
})
|
||
|
|
||
|
minetest.override_item("hell:pearl", {on_use = throw_pearl})
|