Use Raycast for mor fine hit-detection if available

This commit is contained in:
adrido
2017-07-18 15:15:56 +02:00
parent 1836df7205
commit 3b64b68e0d
2 changed files with 215 additions and 194 deletions

View File

@ -13,33 +13,24 @@ local exploding={
gravity=10,
velocity=30,
collisionbox = {-0.25,-0.25,-0.25, 0.25,0.25,0.25},
on_player_hit = function(self,pos,player)
local playername = player:get_player_name()
player:punch(self.object, 1.0, {
full_punch_interval=1.0,
damage_groups={fleshy=self.damage},
}, nil)
self.object:remove()
end,
on_mob_hit = function(self,pos,mob)
mob:punch(self.object, 1.0, {
full_punch_interval=1.0,
damage_groups={fleshy=self.damage},
}, nil)
self.object:remove()
end,
on_node_hit = function(self,pos,node)
cannons.nodehitparticles(pos,node)
cannons.destroy({x=pos.x, y=pos.y, z=pos.z},self.range)
on_player_hit = cannons.ball_player_hit_default,
on_mob_hit = cannons.ball_mob_hit_default,
on_node_hit = function(self, pointed_thing)
local pos = pointed_thing.under
local node = minetest.get_node(pos)
cannons.nodehitparticles(pos, node)
cannons.destroy(pos, self.range)
minetest.sound_play("cannons_shot",
{pos = pos, gain = 1.0, max_hear_distance = 32,})
self.object:remove()
end,
}
if cannons.config:get_bool("enable_explosion") then
cannons.register_muni("cannons:ball_exploding_stack_1",exploding)
end
local fire={
physical = false,
timer=0,
@ -52,26 +43,18 @@ local fire={
gravity=8,
velocity=35,
collisionbox = {-0.25,-0.25,-0.25, 0.25,0.25,0.25},
on_player_hit = function(self,pos,player)
local playername = player:get_player_name()
player:punch(self.object, 1.0, {
full_punch_interval=1.0,
damage_groups={fleshy=self.damage},
}, nil)
self.object:remove()
end,
on_mob_hit = function(self,pos,mob)
self.object:remove()
end,
on_node_hit = function(self,pos,node)
cannons.nodehitparticles(pos,node)
pos = self.lastpos
minetest.env:set_node({x=pos.x, y=pos.y, z=pos.z},{name="fire:basic_flame"})
on_player_hit = cannons.ball_player_hit_default,
on_mob_hit = cannons.ball_mob_hit_default,
on_node_hit = function(self, pointed_thing)
local pos = pointed_thing.under
local node = minetest.get_node(pos)
cannons.nodehitparticles(pos, node)
minetest.set_node(pointed_thing.above, {name="fire:basic_flame"})
minetest.sound_play("default_break_glass",
{pos = pos, gain = 1.0, max_hear_distance = 32,})
self.object:remove()
end,
}
if cannons.config:get_bool("enable_fire") then
cannons.register_muni("cannons:ball_fire_stack_1",fire)
@ -91,40 +74,9 @@ cannons.register_muni("cannons:ball_wood_stack_1",{
gravity=10,
velocity=40,
collisionbox = {-0.25,-0.25,-0.25, 0.25,0.25,0.25},
on_player_hit = function(self,pos,player)
local playername = player:get_player_name()
player:punch(self.object, 1.0, {
full_punch_interval=1.0,
damage_groups={fleshy=self.damage},
}, nil)
self.object:remove()
minetest.chat_send_all(playername .." tried to catch a cannonball")
end,
on_mob_hit = function(self,pos,mob)
mob:punch(self.object, 1.0, {
full_punch_interval=1.0,
damage_groups={fleshy=self.damage},
}, nil)
self.object:remove()
end,
on_node_hit = function(self,pos,node)
cannons.nodehitparticles(pos,node)
if node.name == "default:dirt_with_grass" then
minetest.env:set_node({x=pos.x, y=pos.y, z=pos.z},{name="default:dirt"})
minetest.sound_play("cannons_hit",
{pos = pos, gain = 1.0, max_hear_distance = 32,})
self.object:remove()
elseif node.name == "default:water_source" then
minetest.sound_play("cannons_splash",
{pos = pos, gain = 1.0, max_hear_distance = 32,})
self.object:remove()
else
minetest.sound_play("cannons_hit",
{pos = pos, gain = 1.0, max_hear_distance = 32,})
self.object:remove()
end
end,
on_player_hit = cannons.ball_player_hit_default,
on_mob_hit = cannons.ball_mob_hit_default,
on_node_hit = cannons.ball_node_hit_default,
})
--++++++++++++++++++++++++++++++++++++
@ -141,39 +93,9 @@ cannons.register_muni("cannons:ball_stone_stack_1",{
gravity=10,
velocity=40,
collisionbox = {-0.25,-0.25,-0.25, 0.25,0.25,0.25},
on_player_hit = function(self,pos,player)
local playername = player:get_player_name()
player:punch(self.object, 1.0, {
full_punch_interval=1.0,
damage_groups={fleshy=self.damage},
}, nil)
self.object:remove()
minetest.chat_send_all(playername .." tried to catch a cannonball")
end,
on_mob_hit = function(self,pos,mob)
mob:punch(self.object, 1.0, {
full_punch_interval=1.0,
damage_groups={fleshy=self.damage},
}, nil)
self.object:remove()
end,
on_node_hit = function(self,pos,node)
cannons.nodehitparticles(pos,node)
if node.name == "default:dirt_with_grass" then
minetest.env:set_node({x=pos.x, y=pos.y, z=pos.z},{name="default:dirt"})
minetest.sound_play("cannons_hit",
{pos = pos, gain = 1.0, max_hear_distance = 32,})
self.object:remove()
elseif node.name == "default:water_source" then
minetest.sound_play("cannons_splash",
{pos = pos, gain = 1.0, max_hear_distance = 32,})
self.object:remove()
else
minetest.sound_play("cannons_hit",
{pos = pos, gain = 1.0, max_hear_distance = 32,})
self.object:remove()
end
end,
on_player_hit = cannons.ball_player_hit_default,
on_mob_hit = cannons.ball_mob_hit_default,
on_node_hit = cannons.ball_node_hit_default,
})
@ -191,38 +113,40 @@ cannons.register_muni("cannons:ball_steel_stack_1",{
gravity=5,
velocity=50,
collisionbox = {-0.25,-0.25,-0.25, 0.25,0.25,0.25},
on_player_hit = function(self,pos,player)
on_player_hit = cannons.ball_player_hit_default,
on_mob_hit = cannons.ball_mob_hit_default,
on_node_hit = cannons.ball_node_hit_default,
})
cannons.register_muni("default:apple", {
physical = false,
timer=0,
textures = {"default_apple.png"},
lastpos={},
damage=-10,
range=2,
gravity=10,
velocity=30,
collisionbox = {-0.25,-0.25,-0.25, 0.25,0.25,0.25},
on_player_hit = function(self, pointed_thing)
local player = pointed_thing.ref
local playername = player:get_player_name()
player:punch(self.object, 1.0, {
full_punch_interval=1.0,
damage_groups={fleshy=self.damage},
}, nil)
self.object:remove()
minetest.chat_send_all(playername .." tried to catch a canonball")
minetest.chat_send_player(playername, "A apple a day keeps doctors away!")
end,
on_mob_hit = function(self,pos,mob)
mob:punch(self.object, 1.0, {
full_punch_interval=1.0,
damage_groups={fleshy=self.damage},
}, nil)
on_mob_hit = function(self, pointed_thing)
self.object:remove()
end,
on_node_hit = function(self,pos,node)
cannons.nodehitparticles(pos,node)
if node.name == "default:dirt_with_grass" then
minetest.env:set_node({x=pos.x, y=pos.y, z=pos.z},{name="default:dirt"})
minetest.sound_play("cannons_hit",
{pos = pos, gain = 1.0, max_hear_distance = 32,})
self.object:remove()
elseif node.name == "default:water_source" then
minetest.sound_play("cannons_splash",
{pos = pos, gain = 1.0, max_hear_distance = 32,})
self.object:remove()
else
minetest.sound_play("cannons_hit",
{pos = pos, gain = 1.0, max_hear_distance = 32,})
self.object:remove()
end
on_node_hit = function(self, pointed_thing)
minetest.set_node(pointed_thing.above,{name="default:apple"})
minetest.sound_play("canons_hit",
{pos = pointed_thing.above, gain = 1.0, max_hear_distance = 32,})
self.object:remove()
return true
end,
})

View File

@ -5,10 +5,7 @@ function cannons.destroy(pos,range)
for z=-range,range do
if x*x+y*y+z*z <= range * range + range then
local np={x=pos.x+x,y=pos.y+y,z=pos.z+z}
local n = minetest.env:get_node(np)
if n.name ~= "air" then
minetest.env:remove_node(np)
end
minetest.remove_node(np)
end
end
end
@ -269,16 +266,19 @@ function cannons.fire(pos,node,puncher)
local settings = cannons.get_settings(muni.name)
local obj=minetest.env:add_entity(pos, cannons.get_entity(muni.name))
local obj=minetest.add_entity(pos, cannons.get_entity_name(muni.name))
obj:get_luaentity().lastpos = pos
obj:get_luaentity().startpos = pos
obj:get_luaentity().shooter = puncher -- Warning! puncher may be nil
obj:setvelocity({x=dir.x*settings.velocity, y=-1, z=dir.z*settings.velocity})
obj:setacceleration({x=dir.x*-3, y=-settings.gravity, z=dir.z*-3})
minetest.add_particlespawner(50,0.5,
pos, pos,
{x=dir.x*settings.velocity, y=-1, z=dir.z*settings.velocity}, {x=dir.x*settings.velocity/2, y=-1, z=dir.z*settings.velocity/2},
{x=dir.x*-3/4, y=-settings.gravity*2, z=dir.z*-3/4}, {x=dir.x*-3/2, y=-settings.gravity, z=dir.z*-3/2},
0.1, 0.5,--time
0.5, 1,
false, "cannons_gunpowder.png")
pos, pos,
{x=dir.x*settings.velocity, y=-1, z=dir.z*settings.velocity}, {x=dir.x*settings.velocity/2, y=-1, z=dir.z*settings.velocity/2},
{x=dir.x*-3/4, y=-settings.gravity*2, z=dir.z*-3/4}, {x=dir.x*-3/2, y=-settings.gravity, z=dir.z*-3/2},
0.1, 0.5,--time
0.5, 1,
false, "cannons_gunpowder.png")
end
end
@ -299,51 +299,132 @@ end
--++++++++++++++++++++++++++++++++++++
--+ cannons.register_muni +
--++++++++++++++++++++++++++++++++++++
cannons.registered_muni = {}
function cannons.register_muni(node,entity)
cannons.registered_muni[node] = {}
cannons.registered_muni[node].entity = entity
local name = node:split(":")
cannons.registered_muni[node].entity.name ="cannons:entity_"..name[1].."_"..name[2]
cannons.registered_muni[node].entity.on_step = function(self, dtime)
if minetest.raycast then
minetest.log("info", "[cannons] Raycast is available. Using minetest.raycast for fine hit-detection")
function cannons.muni_on_step(self, dtime)
self.timer=self.timer+dtime
if self.timer >= 0.3 then
local pos = self.object:getpos()
if not self.lastpos.x then --this seems to happen in some obscure cases
minetest.log("error", "Error[cannons]: self.lastpos.x is nil!")
if self then
minetest.log("error", "Error[cannons]: dump of self:")
minetest.log("error", dump(self))
--self:remove();
end
return;
end
local raycast = minetest.raycast(self.lastpos, pos, true, true)
local pt = nil
repeat
pt = raycast:next()
if not pt then break end
if pt.type == "node" then
if pt.above.x == self.startpos.x and pt.above.y == self.startpos.y and pt.above.z == self.startpos.z then
pt = raycast:next()
else
if self:on_node_hit(pt) then
break
end
end
elseif pt.type == "object" then
local entity = pt.ref:get_luaentity()
if pt.ref:is_player() then --something other found
if self:on_player_hit(pt) then
break
end
elseif entity and entity ~= self and entity.name ~= "__builtin:item" then --player found
if self:on_mob_hit(pt) then
break
end
end
end
until pt == nil
self.lastpos=pos
end
end
else
function cannons.muni_on_step(self, dtime)
self.timer=self.timer+dtime
if self.timer >= 0.3 then --easiesst less laggiest way to find out that it left his start position
local pos = self.object:getpos()
local node = minetest.env:get_node(pos)
local node = minetest.get_node(pos)
if node.name == "air" then
local objs = minetest.get_objects_inside_radius({x=pos.x,y=pos.y,z=pos.z}, self.range)
for k, obj in pairs(objs) do
if obj:get_luaentity() ~= nil then
if obj:get_luaentity().name ~= self.name and obj:get_luaentity().name ~= "__builtin:item" then --something other found
local mob = obj
self.on_mob_hit(self,pos,mob)
end
elseif obj:is_player() then --player found
local player = obj
self.on_player_hit(self,pos,player)
end
local objs = minetest.get_objects_inside_radius(pos, self.range)
for i=1, #objs do
local obj = objs[i]
local entity = obj:get_luaentity()
if obj:is_player() then --something other found
local pointed_thing = { type = "object",
under = pos,
above = self.lastpos,
ref = obj}
self:on_player_hit(pointed_thing) -- obj == mob
elseif entity and entity ~= self and entity.name ~= "__builtin:item" then --player found
local pointed_thing = { type = "object",
under = pos,
above = self.lastpos,
ref = obj}
self:on_mob_hit(pointed_thing) -- obj == player
end
end
elseif node.name ~= "air" then
self.on_node_hit(self,pos,node)
end
self.lastpos={x=pos.x, y=pos.y, z=pos.z}
end
else
self:on_node_hit({ type = "node", under = pos, above = self.lastpos})
end
self.lastpos=pos
end
end
cannons.registered_muni[node].obj = entity.name
minetest.register_entity(entity.name, cannons.registered_muni[node].entity)
end
local muni_defaults = {
physical = false,
timer=0,
textures = {"cannons_bullet_iron.png"},
lastpos={},
damage=0,
range=0,
gravity=1,
velocity=1,
shooter=nil,
collisionbox = {-0.25,-0.25,-0.25, 0.25,0.25,0.25},
on_step = cannons.muni_on_step,
on_player_hit = cannons.ball_player_hit_default,
on_mob_hit = cannons.ball_mob_hit_default,
on_node_hit = cannons.ball_node_hit_default,
}
local function void() end
function cannons.register_muni(node, entity)
-- insert the defaults if they does not exist
for k,v in pairs(muni_defaults) do
if not entity[k] then
entity[k] = v
end
end
local name = node:split(":")
name = "cannons:entity_"..name[1].."_"..name[2]
cannons.registered_muni[node] = entity
minetest.register_entity(name, cannons.registered_muni[node])
end
function cannons.is_muni(node)
return cannons.registered_muni[node] ~= nil
end
function cannons.get_entity(node)
return cannons.registered_muni[node].obj
function cannons.get_entity_name(node)
return cannons.registered_muni[node].name
end
function cannons.get_settings(node)
return cannons.registered_muni[node].entity
return cannons.registered_muni[node]
end
--++++++++++++++++++++++++++++++++++++
@ -498,35 +579,51 @@ cannons.nodeboxes.stand = {
},
}
local apple={
physical = false,
timer=0,
textures = {"default_apple.png"},
lastpos={},
damage=-10,
range=2,
gravity=10,
velocity=30,
collisionbox = {-0.25,-0.25,-0.25, 0.25,0.25,0.25},
on_player_hit = function(self,pos,player)
local playername = player:get_player_name()
player:punch(self.object, 1.0, {
full_punch_interval=1.0,
damage_groups={fleshy=self.damage},
}, nil)
self.object:remove()
minetest.chat_send_player(playername ," this is not an easter egg!")
end,
on_mob_hit = function(self,pos,mob)
self.object:remove()
end,
on_node_hit = function(self,pos,node)
pos = self.lastpos
minetest.env:set_node({x=pos.x, y=pos.y, z=pos.z},{name="default:apple"})
minetest.sound_play("canons_hit",
cannons.ball_node_hit_default = function(self, pointed_thing)
local pos = pointed_thing.under
local node = minetest.get_node(pos)
cannons.nodehitparticles(pos, node)
if node.name == "default:dirt_with_grass" then
minetest.set_node(pos, {name="default:dirt"})
minetest.sound_play("cannons_hit",
{pos = pos, gain = 1.0, max_hear_distance = 32,})
self.object:remove()
end,
return true
elseif node.name == "default:water_source" then
minetest.sound_play("cannons_splash",
{pos = pos, gain = 1.0, max_hear_distance = 32,})
self.object:remove()
return true
else
minetest.sound_play("cannons_hit",
{pos = pos, gain = 1.0, max_hear_distance = 32,})
self.object:remove()
return true
end
end
cannons.ball_player_hit_default = function(self, pointed_thing)
local player = pointed_thing.ref
local playername = player:get_player_name()
player:punch(self.object, 1.0, {
full_punch_interval=1.0,
damage_groups={fleshy=self.damage},
}, nil)
self.object:remove()
minetest.chat_send_all(playername .." tried to catch a cannonball")
end
cannons.ball_mob_hit_default = function(self, pointed_thing)
local mob = pointed_thing.ref
minetest.chat_send_player(self.shooter:get_player_name() or "", "You hit a mob!")
mob:punch(self.object, 1.0, {
full_punch_interval=1.0,
damage_groups={fleshy=self.damage},
}, nil)
self.object:remove()
return true
end
}
cannons.register_muni("default:apple",apple)