nssbombs/bombs_api.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