mirror of
https://bitbucket.org/kingarthursteam/cannons.git
synced 2025-03-01 02:04:36 +01:00
Use Raycast for mor fine hit-detection if available
This commit is contained in:
174
cannonballs.lua
174
cannonballs.lua
@ -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,
|
||||
|
||||
})
|
||||
|
235
functions.lua
235
functions.lua
@ -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)
|
Reference in New Issue
Block a user