321 lines
12 KiB
Lua
321 lines
12 KiB
Lua
function nssbombs:register_throwitem(
|
|
name, --used for the craftitem and the entity
|
|
descr, --used for the craftitem
|
|
def) --array containing the definition parameters
|
|
|
|
minetest.register_craftitem(name, {
|
|
description = descr,
|
|
inventory_image = def.textures,
|
|
on_use = function(itemstack, placer, pointed_thing)
|
|
local velocity = def.velocity or 15
|
|
|
|
local dir = placer:get_look_dir()
|
|
local playerpos = placer:getpos()
|
|
local obj = minetest.add_entity({x=playerpos.x+dir.x,y=playerpos.y+2+dir.y,z=playerpos.z+dir.z}, name.."_flying")
|
|
local vec = {x=dir.x*velocity,y=dir.y*velocity,z=dir.z*velocity}
|
|
local acc = {x=0, y=-9.8, z=0}
|
|
|
|
obj:setvelocity(vec)
|
|
obj:setacceleration(acc)
|
|
obj:get_luaentity().placer = placer
|
|
if not minetest.setting_getbool("creative_mode") then
|
|
itemstack:take_item()
|
|
end
|
|
return itemstack
|
|
end,
|
|
})
|
|
|
|
minetest.register_entity(name.."_flying",{
|
|
textures = {def.textures},
|
|
hp_max = 50,
|
|
placer = nil,
|
|
collisionbox = {-0.1,-0.1,-0.1, 0.1,0.1,0.1},
|
|
visual_size = def.visual_size or {x=1, y=1},
|
|
explosion = def.explosion or {},
|
|
on_step = function(self, dtime)
|
|
local pos = self.object:getpos()
|
|
local node = minetest.get_node(pos)
|
|
local name = node.name
|
|
if name ~= "air" then
|
|
if def.hit_node then
|
|
def.hit_node(self, pos)
|
|
else
|
|
if self.explosion then
|
|
default_hit_node(self, self.explosion)
|
|
else
|
|
minetest.chat_send_player(self.placer, "No hit_node function defined")
|
|
end
|
|
end
|
|
self.object:remove()
|
|
end
|
|
end,
|
|
})
|
|
local recepy
|
|
if def.recipe_block then
|
|
recepy = {
|
|
{def.recipe_block, def.recipe_block, def.recipe_block},
|
|
{"tnt:gunpowder", "default:mese_crystal_fragment", "tnt:gunpowder"},
|
|
{def.recipe_block, def.recipe_block, def.recipe_block},
|
|
}
|
|
end
|
|
|
|
local number = def.recipe_number or 1
|
|
minetest.register_craft({
|
|
output = name.." "..number,
|
|
type = def.recipe_type or nil,
|
|
recipe = def.recipe or recepy
|
|
})
|
|
|
|
end
|
|
|
|
function perpendicular_vector(vec) --returns a vector rotated of 90° in 2D (x and z directions)
|
|
local ang = math.pi/2
|
|
local c = math.cos(ang)
|
|
local s = math.sin(ang)
|
|
|
|
local i = vec.x*c - vec.z*s
|
|
local k = vec.x*s + vec.z*c
|
|
local j = 0
|
|
|
|
vec = {x=i, y=j, z=k}
|
|
return vec
|
|
end
|
|
|
|
function default_hit_node(self, explosion)
|
|
local radius = explosion.radius --size of the explosion
|
|
local shape = explosion.shape --to choose the explosion type
|
|
local block = explosion.block -- it can be a name of a block, of a schematic or of an entity
|
|
local particles = explosion.particles --if you want to use the particles (boolean)
|
|
local sound = explosion.sound -- sound for the explosion, true to use the default sound
|
|
|
|
local p = self.object:getpos() --position of the impact between the bomb and the ground
|
|
local center = {x=p.x, y=p.y, z=p.z}
|
|
|
|
if shape == "cube" then
|
|
for dx = -radius,radius do
|
|
for dy = -radius,radius do
|
|
for dz = -radius,radius do
|
|
local pos1 = {x = p.x+dx, y=p.y+dy, z=p.z+dz}
|
|
if not minetest.is_protected(pos1, "") or not minetest.get_item_group(minetest.get_node(pos1).name, "unbreakable") == 1 then
|
|
minetest.set_node(pos1, {name=block})
|
|
end
|
|
end
|
|
end
|
|
end
|
|
elseif shape == "pool" then
|
|
for dx = -radius,radius do
|
|
for dy = -1,0 do
|
|
for dz = -radius,radius do
|
|
local pos1 = {x = p.x+dx, y=p.y+dy, z=p.z+dz}
|
|
if not minetest.is_protected(pos1, "") or not minetest.get_item_group(minetest.get_node(pos1).name, "unbreakable") == 1 then
|
|
minetest.set_node(pos1, {name=block})
|
|
end
|
|
end
|
|
end
|
|
end
|
|
elseif shape == "sphere" then
|
|
for dx = -radius,radius do
|
|
for dy = -radius,radius do
|
|
for dz = -radius,radius do
|
|
local pos1 = {x = p.x+dx, y=p.y+dy, z=p.z+dz}
|
|
if math.abs(vector.length(vector.subtract(pos1,p))) <= radius then
|
|
if not minetest.is_protected(pos1, "") or not minetest.get_item_group(minetest.get_node(pos1).name, "unbreakable") == 1 then
|
|
minetest.set_node(pos1, {name=block})
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
elseif shape == "sphere_shell" then
|
|
center.y = p.y + radius
|
|
for dx = -radius,radius do
|
|
for dy = 0,2*radius do
|
|
for dz = -radius,radius do
|
|
local pos1 = {x = p.x+dx, y=p.y+dy, z=p.z+dz}
|
|
if round(math.abs(vector.length(vector.subtract(pos1,center)))) == radius then
|
|
if not minetest.is_protected(pos1, "") or not minetest.get_item_group(minetest.get_node(pos1).name, "unbreakable") == 1 then
|
|
minetest.set_node(pos1, {name=block})
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
elseif shape == "sphere_cover" then
|
|
for dx = -radius,radius do
|
|
for dy = radius,-radius,-1 do
|
|
for dz = -radius,radius do
|
|
local pos1 = {x = p.x+dx, y=p.y+dy, z=p.z+dz}
|
|
if math.abs(vector.length(vector.subtract(pos1,p))) <= radius then
|
|
local node_at = minetest.get_node_or_nil(pos1)
|
|
local node_below = minetest.get_node_or_nil({x=pos1.x, y=pos1.y-1, z=pos1.z})
|
|
if node_at and node_below and node_at.name == 'air' and node_below.name ~= 'air' then
|
|
if not minetest.is_protected(pos1, "") or not minetest.get_item_group(minetest.get_node(pos1).name, "unbreakable") == 1 then
|
|
minetest.set_node(pos1, {name=block})
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
elseif shape == "cubic_shell" then
|
|
center.y = p.y + radius
|
|
for dx = -radius,radius do
|
|
for dy = -radius,radius do
|
|
for dz = -radius,radius do
|
|
local pos1 = {x = p.x+dx, y=center.y+dy, z=p.z+dz}
|
|
if ((math.abs(dz)==radius)or(math.abs(dx)==radius)or(math.abs(dy)==radius)) then
|
|
if not minetest.is_protected(pos1, "") or not minetest.get_item_group(minetest.get_node(pos1).name, "unbreakable") == 1 then
|
|
minetest.set_node(pos1, {name=block})
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
elseif shape == "column" then
|
|
local base_side = 0
|
|
if round(radius/4) > 1 then
|
|
base_side = round(radius/4)
|
|
end
|
|
local height = radius
|
|
for dx = -base_side,base_side do
|
|
for dy = 0,height do
|
|
for dz = -base_side,base_side do
|
|
local pos1 = {x = p.x+dx, y=p.y+dy, z=p.z+dz}
|
|
if not minetest.is_protected(pos1, "") or not minetest.get_item_group(minetest.get_node(pos1).name, "unbreakable") == 1 then
|
|
minetest.set_node(pos1, {name=block})
|
|
end
|
|
end
|
|
end
|
|
end
|
|
elseif shape == "circle" then
|
|
center.y = p.y + 1
|
|
for dx = -radius,radius do
|
|
for dy = 0, 1 do
|
|
for dz = -radius,radius do
|
|
local pos1 = {x = p.x+dx, y=p.y+1+dy, z=p.z+dz}
|
|
if round(math.abs(vector.length(vector.subtract(pos1,center)))) == radius then
|
|
if not minetest.is_protected(pos1, "") or not minetest.get_item_group(minetest.get_node(pos1).name, "unbreakable") == 1 then
|
|
minetest.set_node(pos1, {name=block})
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
elseif shape == "wall" then
|
|
local vec = self.object:getvelocity()
|
|
vec.y = 0
|
|
vec = vector.normalize(vec)
|
|
local pr = perpendicular_vector(vec)
|
|
|
|
local m = radius/2
|
|
p = vector.subtract(p, vector.multiply(pr, m))
|
|
|
|
for i = 0, radius do
|
|
for dy = 0, round(radius/2) do
|
|
local pp = {x = p.x, y = p.y +dy, z = p.z}
|
|
if not minetest.is_protected(pp, "") or not minetest.get_item_group(minetest.get_node(pp).name, "unbreakable") == 1 then
|
|
minetest.set_node(pp, {name=block})
|
|
end
|
|
if radius >= 10 then
|
|
local pp2 = vector.add(pp,vec)
|
|
if not minetest.is_protected(pp2, "") or not minetest.get_item_group(minetest.get_node(pp2).name, "unbreakable") == 1 then
|
|
minetest.set_node(pp2, {name=block})
|
|
end
|
|
end
|
|
end
|
|
p = vector.add(p,pr)
|
|
end
|
|
elseif shape == "schematic" then
|
|
--[[
|
|
Adds a defined schematic in the landing position of the bomb.
|
|
If you want the schematic appear with its center in the landing pos of the bomb
|
|
you have to specify the dimensione of the base of the schematic using
|
|
explosion.radius parameter
|
|
--]]
|
|
if radius then
|
|
local angle = {x = p.x - radius/2, y = p.y, z = p.z - radius/2}
|
|
minetest.place_schematic(angle, block, "0", {}, true)
|
|
else
|
|
minetest.place_schematic(p, block, "0", {}, true)
|
|
end
|
|
elseif shape == "add_entity" then
|
|
--[[
|
|
Adds an entity in the landing position.
|
|
In this case "block" contains the name of the entity to be added.
|
|
]]
|
|
minetest.add_entity(p, block)
|
|
elseif shape == "tnt_explosion" then
|
|
tnt.boom(p, {damage_radius=radius,radius=radius,ignore_protection=false})
|
|
end
|
|
|
|
if particles and (shape ~= "tnt_explosion") then
|
|
add_effects(center, radius, block)
|
|
end
|
|
if sound and (shape ~= "tnt_explosion") then
|
|
if sound == true then
|
|
minetest.sound_play("tnt_explode",{
|
|
object = self.object,
|
|
max_hear_distance = radius*16
|
|
})
|
|
else
|
|
minetest.sound_play(sound,{
|
|
object = self.object,
|
|
max_hear_distance = radius*16
|
|
})
|
|
end
|
|
end
|
|
end
|
|
|
|
function add_effects(pos, radius, block)
|
|
local velocity = 1.9*math.log(radius)
|
|
local q = 20*math.log(radius)
|
|
|
|
minetest.add_particlespawner({
|
|
amount = q,
|
|
time = 0.3,
|
|
minpos = vector.subtract(pos, radius / 2),
|
|
maxpos = vector.add(pos, radius / 2),
|
|
minvel = {x = -velocity, y = -velocity, z = -velocity},
|
|
maxvel = {x = velocity, y = velocity, z = velocity},
|
|
minacc = vector.new(),
|
|
maxacc = vector.new(),
|
|
minexptime = 0.5,
|
|
maxexptime = 1,
|
|
minsize = 9,
|
|
maxsize = 10,
|
|
texture = "tnt_smoke.png",
|
|
})
|
|
|
|
local texture2 = "tnt_smoke.png"
|
|
local def = minetest.registered_nodes[block]
|
|
if def and def.tiles and def.tiles[1] and type(def.tiles[1])=="string" then
|
|
texture2 = def.tiles[1]
|
|
end
|
|
|
|
minetest.add_particlespawner({
|
|
amount = q,
|
|
time = 0.5,
|
|
minpos = vector.subtract(pos, radius / 2),
|
|
maxpos = vector.add(pos, radius / 2),
|
|
minvel = {x = -velocity, y = -velocity, z = -velocity},
|
|
maxvel = {x = velocity, y = velocity, z = velocity},
|
|
minacc = vector.new(),
|
|
maxacc = vector.new(),
|
|
minexptime = 0.5,
|
|
maxexptime = 1,
|
|
minsize = 9,
|
|
maxsize = 10,
|
|
texture = texture2,
|
|
})
|
|
end
|
|
|
|
function round(n)
|
|
if (n > 0) then
|
|
return n % 1 >= 0.5 and math.ceil(n) or math.floor(n)
|
|
else
|
|
n = -n
|
|
local t = n % 1 >= 0.5 and math.ceil(n) or math.floor(n)
|
|
return -t
|
|
end
|
|
end
|