2019-12-14 17:47:31 +01:00
-- BALL: energy ball that flies around, can bounce and activate stuff
-- rnd 2016:
-- TO DO: move mode: ball just rolling around on ground without hopping, also if inside slope it would "roll down", just increased velocity in slope direction
-- SETTINGS
basic_machines.ball = { } ;
basic_machines.ball . maxdamage = 10 ; -- player health 20
basic_machines.ball . bounce_materials = { -- to be used with bounce setting 2 in ball spawner: 1: bounce in x direction, 2: bounce in z direction, otherwise it bounces in y direction
[ " default:wood " ] = 1 ,
[ " xpanes:bar_2 " ] = 1 ,
[ " xpanes:bar_10 " ] = 1 ,
[ " darkage:iron_bars " ] = 1 ,
[ " default:glass " ] = 2 ,
} ;
-- END OF SETTINGS
local ballcount = { } ;
local function round ( x )
if x < 0 then
return - math.floor ( - x + 0.5 ) ;
else
return math.floor ( x + 0.5 ) ;
end
end
local ball_spawner_update_form = function ( pos )
local meta = minetest.get_meta ( pos ) ;
local x0 , y0 , z0 ;
x0 = meta : get_int ( " x0 " ) ; y0 = meta : get_int ( " y0 " ) ; z0 = meta : get_int ( " z0 " ) ; -- direction of velocity
local energy , bounce , g , puncheable , gravity , hp , hurt , solid ;
local speed = meta : get_float ( " speed " ) ; -- if positive sets initial ball speed
energy = meta : get_float ( " energy " ) ; -- if positive activates, negative deactivates, 0 does nothing
bounce = meta : get_int ( " bounce " ) ; -- if nonzero bounces when hit obstacle, 0 gets absorbed
gravity = meta : get_float ( " gravity " ) ; -- gravity
hp = meta : get_float ( " hp " ) ;
2020-02-28 13:16:11 +01:00
2019-12-14 17:47:31 +01:00
puncheable = meta : get_int ( " puncheable " ) ; -- if 1 can be punched by players in protection, if 2 can be punched by anyone
solid = meta : get_int ( " solid " ) ; -- if 1 then entity is solid - cant be walked on
local texture = meta : get_string ( " texture " ) or " basic_machines_ball.png " ;
local visual = meta : get_string ( " visual " ) or " sprite " ;
local scale = meta : get_int ( " scale " ) ;
local form =
" size[4.25,4.75] " .. -- width, height
" field[0.25,0.5;1,1;x0;target; " .. x0 .. " ] field[1.25,0.5;1,1;y0;; " .. y0 .. " ] field[2.25,0.5;1,1;z0;; " .. z0 .. " ] " ..
" field[3.25,0.5;1,1;speed;speed; " .. speed .. " ] " ..
--speed, jump, gravity,sneak
" field[0.25,1.5;1,1;energy;energy; " .. energy .. " ] " ..
" field[1.25,1.5;1,1;bounce;bounce; " .. bounce .. " ] " ..
" field[2.25,1.5;1,1;gravity;gravity; " .. gravity .. " ] " ..
" field[3.25,1.5;1,1;puncheable;puncheable; " .. puncheable .. " ] " ..
" field[3.25,2.5;1,1;solid;solid; " .. solid .. " ] " ..
" field[0.25,2.5;1,1;hp;hp; " .. hp .. " ] " .. " field[1.25,2.5;1,1;hurt;hurt; " .. hurt .. " ] " ..
" field[0.25,3.5;4,1;texture;texture; " .. minetest.formspec_escape ( texture ) .. " ] " ..
" field[0.25,4.5;1,1;scale;scale; " .. scale .. " ] " .. " field[1.25,4.5;1,1;visual;visual; " .. visual .. " ] " ..
" button_exit[3.25,4.25;1,1;OK;OK] " ;
if meta : get_int ( " admin " ) == 1 then
local lifetime = meta : get_int ( " lifetime " ) ;
if lifetime <= 0 then lifetime = 20 end
form = form .. " field[2.25,2.5;1,1;lifetime;lifetime; " .. lifetime .. " ] "
end
meta : set_string ( " formspec " , form ) ;
end
minetest.register_entity ( " basic_machines:ball " , {
timer = 0 ,
lifetime = 20 , -- how long it exists before disappearing
energy = 0 , -- if negative it will deactivate stuff, positive will activate, 0 wont do anything
puncheable = 1 , -- can be punched by players in protection
bounce = 0 , -- 0: absorbs in block, 1 = proper bounce=lag buggy, -- to do: 2 = line of sight bounce
gravity = 0 ,
speed = 5 , -- velocity when punched
hurt = 0 , -- how much damage it does to target entity, if 0 damage disabled
owner = " " ,
state = false ,
origin = { x = 0 , y = 0 , z = 0 } ,
lastpos = { x = 0 , y = 0 , z = 0 } , -- last not-colliding position
hp_max = 100 ,
elasticity = 0.9 , -- speed gets multiplied by this after bounce
visual = " sprite " ,
visual_size = { x = .6 , y = .6 } ,
collisionbox = { - 0.5 , - 0.5 , - 0.5 , 0.5 , 0.5 , 0.5 } ,
physical = false ,
--textures={"basic_machines_ball"},
on_activate = function ( self , staticdata )
self.object : set_properties ( { textures = { " basic_machines_ball.png " } } )
self.object : set_properties ( { visual_size = { x = 1 , y = 1 } } ) ;
self.timer = 0 ; self.owner = " " ;
self.origin = self.object : getpos ( ) ;
self.lifetime = 20 ;
end ,
get_staticdata = function ( self ) -- this gets called before object put in world and before it hides
if not self.state then return nil end
self.object : remove ( ) ;
return nil
end ,
on_punch = function ( self , puncher , time_from_last_punch , tool_capabilities , dir )
if self.puncheable == 0 then return end
if self.puncheable == 1 then -- only those in protection
local name = puncher : get_player_name ( ) ;
local pos = self.object : getpos ( ) ;
if minetest.is_protected ( pos , name ) then return end
end
--minetest.chat_send_all(minetest.pos_to_string(dir))
if time_from_last_punch < 0.5 then return end
local v = self.speed or 1 ;
local velocity = dir ;
velocity.x = velocity.x * v ; velocity.y = velocity.y * v ; velocity.z = velocity.z * v ;
self.object : setvelocity ( velocity )
end ,
on_step = function ( self , dtime )
self.timer = self.timer + dtime
if self.timer > self.lifetime then
local count = ballcount [ self.owner ] or 1 ; count = count - 1 ; ballcount [ self.owner ] = count ;
self.object : remove ( )
return
end
if not self.state then self.state = true end
local pos = self.object : getpos ( )
local origin = self.origin ;
local r = 30 ; -- maximal distance when balls disappear
local dist = math.max ( math.abs ( pos.x - origin.x ) , math.abs ( pos.y - origin.y ) , math.abs ( pos.z - origin.z ) ) ;
if dist > r then -- remove if it goes too far
local count = ballcount [ self.owner ] or 1 ; count = count - 1 ; ballcount [ self.owner ] = count ;
self.object : remove ( )
return
end
local nodename = minetest.get_node ( pos ) . name ;
local walkable = false ;
if nodename ~= " air " then
walkable = minetest.registered_nodes [ nodename ] . walkable ;
if nodename == " basic_machines:ball_spawner " and dist > 0.5 then walkable = true end -- ball can activate spawner, just not originating one
end
if not walkable then
self.lastpos = pos
if self.hurt ~= 0 then -- check for coliding nearby objects
local objects = minetest.get_objects_inside_radius ( pos , 2 ) ;
if # objects > 1 then
for _ , obj in pairs ( objects ) do
local p = obj : getpos ( ) ;
local d = math.sqrt ( ( p.x - pos.x ) ^ 2 + ( p.y - pos.y ) ^ 2 + ( p.z - pos.z ) ^ 2 ) ;
if d > 0 then
--if minetest.is_protected(p,self.owner) then return end
if math.abs ( p.x ) < 32 and math.abs ( p.y ) < 32 and math.abs ( p.z ) < 32 then return end -- no damage around spawn
if obj : is_player ( ) then --player
if obj : get_player_name ( ) == self.owner then break end -- dont hurt owner
local hp = obj : get_hp ( )
local newhp = hp - self.hurt ;
if newhp <= 0 and boneworld and boneworld.killxp then
local killxp = boneworld.killxp [ self.owner ] ;
if killxp then
boneworld.killxp [ self.owner ] = killxp + 0.01 ;
end
end
obj : set_hp ( newhp )
else -- non player
local lua_entity = obj : get_luaentity ( ) ;
if lua_entity and lua_entity.itemstring then
local entname = lua_entity.itemstring ;
if entname == " robot " then
self.object : remove ( )
return ;
end
end
local hp = obj : get_hp ( )
local newhp = hp - self.hurt ;
minetest.chat_send_player ( self.owner , " #ball: target hp " .. newhp )
if newhp <= 0 then obj : remove ( ) else obj : set_hp ( newhp ) end
end
local count = ballcount [ self.owner ] or 1 ; count = count - 1 ; ballcount [ self.owner ] = count ;
self.object : remove ( ) ;
return
end
end
end
end
end
if walkable then -- we hit a node
--minetest.chat_send_all(" hit node at " .. minetest.pos_to_string(pos))
local node = minetest.get_node ( pos ) ;
local table = minetest.registered_nodes [ node.name ] ;
if table and table.mesecons and table.mesecons . effector then -- activate target
local energy = self.energy ;
if energy ~= 0 then
if minetest.is_protected ( pos , self.owner ) then return end
end
local effector = table.mesecons . effector ;
self.object : remove ( ) ;
if energy > 0 then
if not effector.action_on then return end
effector.action_on ( pos , node , 16 ) ;
elseif energy < 0 then
if not effector.action_off then return end
effector.action_off ( pos , node , 16 ) ;
end
else -- bounce ( copyright rnd, 2016 )
local bounce = self.bounce ;
if self.bounce == 0 then
local count = ballcount [ self.owner ] or 1 ; count = count - 1 ; ballcount [ self.owner ] = count ;
self.object : remove ( )
return end
local n = { x = 0 , y = 0 , z = 0 } ; -- this will be bounce normal
local v = self.object : getvelocity ( ) ;
local opos = { x = round ( pos.x ) , y = round ( pos.y ) , z = round ( pos.z ) } ; -- obstacle
local bpos = { x = ( pos.x - opos.x ) , y = ( pos.y - opos.y ) , z = ( pos.z - opos.z ) } ; -- boundary position on cube, approximate
if bounce == 2 then -- uses special blocks for non buggy lag proof bouncing: by default it bounces in y direction
local bounce_direction = basic_machines.ball . bounce_materials [ node.name ] or 0 ;
if bounce_direction == 0 then
if v.y >= 0 then n.y = - 1 else n.y = 1 end
elseif bounce_direction == 1 then
if v.x >= 0 then n.x = - 1 else n.x = 1 end
n.y = 0 ;
elseif bounce_direction == 2 then
if v.z >= 0 then n.z = - 1 else n.z = 1 end
n.y = 0 ;
end
else -- algorithm to determine bounce direction - problem: with lag its impossible to determine reliable which node was hit and which face ..
if v.x <= 0 then n.x = 1 else n.x = - 1 end -- possible bounce directions
if v.y <= 0 then n.y = 1 else n.y = - 1 end
if v.z <= 0 then n.z = 1 else n.z = - 1 end
local dpos = { } ;
dpos.x = 0.5 * n.x ; dpos.y = 0 ; dpos.z = 0 ; -- calculate distance to bounding surface midpoints
local d1 = ( bpos.x - dpos.x ) ^ 2 + ( bpos.y ) ^ 2 + ( bpos.z ) ^ 2 ;
dpos.x = 0 ; dpos.y = 0.5 * n.y ; dpos.z = 0 ;
local d2 = ( bpos.x ) ^ 2 + ( bpos.y - dpos.y ) ^ 2 + ( bpos.z ) ^ 2 ;
dpos.x = 0 ; dpos.y = 0 ; dpos.z = 0.5 * n.z ;
local d3 = ( bpos.x ) ^ 2 + ( bpos.y ) ^ 2 + ( bpos.z - dpos.z ) ^ 2 ;
local d = math.min ( d1 , d2 , d3 ) ; -- we obtain bounce direction from minimal distance
if d1 == d then --x
n.y = 0 ; n.z = 0
elseif d2 == d then --y
n.x = 0 ; n.z = 0
elseif d3 == d then --z
n.x = 0 ; n.y = 0
end
nodename = minetest.get_node ( { x = opos.x + n.x , y = opos.y + n.y , z = opos.z + n.z } ) . name -- verify normal
walkable = nodename ~= " air " ;
if walkable then -- problem, nonempty node - incorrect normal, fix it
if n.x ~= 0 then -- x direction is wrong, try something else
n.x = 0 ;
if v.y >= 0 then n.y = - 1 else n.y = 1 end -- try y
nodename = minetest.get_node ( { x = opos.x + n.x , y = opos.y + n.y , z = opos.z + n.z } ) . name -- verify normal
walkable = nodename ~= " air " ;
if walkable then -- still problem, only remaining is z
n.y = 0 ;
if v.z >= 0 then n.z = - 1 else n.z = 1 end
nodename = minetest.get_node ( { x = opos.x + n.x , y = opos.y + n.y , z = opos.z + n.z } ) . name -- verify normal
walkable = nodename ~= " air " ;
if walkable then -- messed up, just remove the ball
self.object : remove ( )
return
end
end
end
end
end
local elasticity = self.elasticity ;
-- bounce
if n.x ~= 0 then
v.x =- elasticity * v.x
elseif n.y ~= 0 then
v.y =- elasticity * v.y
elseif n.z ~= 0 then
v.z =- elasticity * v.z
end
local r = 0.2
bpos = { x = pos.x + n.x * r , y = pos.y + n.y * r , z = pos.z + n.z * r } ; -- point placed a bit further away from box
self.object : setpos ( bpos ) -- place object at last known outside point
self.object : setvelocity ( v ) ;
minetest.sound_play ( " default_dig_cracky " , { pos = pos , gain = 1.0 , max_hear_distance = 8 , } )
end
end
return
end ,
} )
minetest.register_node ( " basic_machines:ball_spawner " , {
description = " Spawns energy ball one block above " ,
tiles = { " basic_machines_ball.png " } ,
groups = { cracky = 3 , mesecon_effector_on = 1 } ,
drawtype = " allfaces " ,
paramtype = " light " ,
param1 = 1 ,
walkable = false ,
alpha = 150 ,
sounds = default.node_sound_wood_defaults ( ) ,
after_place_node = function ( pos , placer )
local meta = minetest.env : get_meta ( pos )
meta : set_string ( " owner " , placer : get_player_name ( ) ) ;
local privs = minetest.get_player_privs ( placer : get_player_name ( ) ) ; if privs.privs then meta : set_int ( " admin " , 1 ) end
if privs.machines then meta : set_int ( " machines " , 1 ) end
meta : set_float ( " hurt " , 0 ) ;
meta : set_string ( " texture " , " basic_machines_ball.png " ) ;
meta : set_float ( " hp " , 100 ) ;
meta : set_float ( " speed " , 5 ) ; -- if positive sets initial ball speed
meta : set_float ( " energy " , 1 ) ; -- if positive activates, negative deactivates, 0 does nothing
meta : set_int ( " bounce " , 0 ) ; -- if nonzero bounces when hit obstacle, 0 gets absorbed
meta : set_float ( " gravity " , 0 ) ; -- gravity
meta : set_int ( " puncheable " , 0 ) ; -- if 0 not puncheable, if 1 can be punched by players in protection, if 2 can be punched by anyone
meta : set_int ( " scale " , 100 ) ;
meta : set_string ( " visual " , " sprite " ) ;
ball_spawner_update_form ( pos ) ;
end ,
mesecons = { effector = {
action_on = function ( pos , node , ttl )
if type ( ttl ) ~= " number " then ttl = 1 end
if ttl < 0 then return end
local meta = minetest.get_meta ( pos ) ;
local t0 = meta : get_int ( " t " ) ;
local t1 = minetest.get_gametime ( ) ;
local T = meta : get_int ( " T " ) ; -- temperature
if t0 > t1 - 2 then -- activated before natural time
T = T + 1 ;
else
if T > 0 then
T = T - 1
if t1 - t0 > 5 then T = 0 end
end
end
meta : set_int ( " T " , T ) ;
meta : set_int ( " t " , t1 ) ; -- update last activation time
if T > 2 then -- overheat
minetest.sound_play ( " default_cool_lava " , { pos = pos , max_hear_distance = 16 , gain = 0.25 } )
meta : set_string ( " infotext " , " overheat: temperature " .. T )
return
end
if meta : get_int ( " machines " ) ~= 1 then -- no machines priv, limit ball count
local owner = meta : get_string ( " owner " ) ;
local count = ballcount [ owner ] ;
if not count or count < 0 then count = 0 end
if count >= 2 then
if t1 - t0 > 20 then count = 0
else return
end
end
count = count + 1 ;
ballcount [ owner ] = count ;
--minetest.chat_send_all("count " .. count);
end
pos.x = round ( pos.x ) ; pos.y = round ( pos.y ) ; pos.z = round ( pos.z ) ;
local obj = minetest.add_entity ( { x = pos.x , y = pos.y , z = pos.z } , " basic_machines:ball " ) ;
local luaent = obj : get_luaentity ( ) ;
local meta = minetest.get_meta ( pos ) ;
local speed , energy , bounce , gravity , puncheable , solid ;
speed = meta : get_float ( " speed " ) ;
energy = meta : get_float ( " energy " ) ; -- if positive activates, negative deactivates, 0 does nothing
bounce = meta : get_int ( " bounce " ) ; -- if nonzero bounces when hit obstacle, 0 gets absorbed
gravity = meta : get_float ( " gravity " ) ; -- gravity
puncheable = meta : get_int ( " puncheable " ) ; -- if 1 can be punched by players in protection, if 2 can be punched by anyone
solid = meta : get_int ( " solid " ) ;
if energy < 0 then
obj : set_properties ( { textures = { " basic_machines_ball.png^[colorize:blue:120 " } } )
end
luaent.bounce = bounce ;
luaent.energy = energy ;
if gravity > 0 then
obj : setacceleration ( { x = 0 , y =- gravity , z = 0 } ) ;
end
luaent.puncheable = puncheable ;
luaent.owner = meta : get_string ( " owner " ) ;
luaent.hurt = meta : get_float ( " hurt " ) ;
if solid == 1 then
luaent.physical = true
end
obj : set_hp ( meta : get_float ( " hp " ) ) ;
local x0 , y0 , z0 ;
if speed > 0 then luaent.speed = speed end
x0 = meta : get_int ( " x0 " ) ; y0 = meta : get_int ( " y0 " ) ; z0 = meta : get_int ( " z0 " ) ; -- direction of velocity
if speed ~= 0 and ( x0 ~= 0 or y0 ~= 0 or z0 ~= 0 ) then -- set velocity direction
local velocity = { x = x0 , y = y0 , z = z0 } ;
local v = math.sqrt ( velocity.x ^ 2 + velocity.y ^ 2 + velocity.z ^ 2 ) ; if v == 0 then v = 1 end
v = v / speed ;
velocity.x = velocity.x / v ; velocity.y = velocity.y / v ; velocity.z = velocity.z / v ;
obj : setvelocity ( velocity ) ;
end
if meta : get_int ( " admin " ) == 1 then
luaent.lifetime = meta : get_float ( " lifetime " ) ;
end
local visual = meta : get_string ( " visual " )
obj : set_properties ( { visual = visual } ) ;
local texture = meta : get_string ( " texture " ) ;
if visual == " sprite " then
obj : set_properties ( { textures = { texture } } )
elseif visual == " cube " then
obj : set_properties ( { textures = { texture , texture , texture , texture , texture , texture } } )
end
local scale = meta : get_int ( " scale " ) ; if scale <= 0 then scale = 1 else scale = scale / 100 end
obj : set_properties ( { visual_size = { x = scale , y = scale } } ) ;
end ,
action_off = function ( pos , node , ttl )
if type ( ttl ) ~= " number " then ttl = 1 end
if ttl < 0 then return end
pos.x = round ( pos.x ) ; pos.y = round ( pos.y ) ; pos.z = round ( pos.z ) ;
local obj = minetest.add_entity ( { x = pos.x , y = pos.y , z = pos.z } , " basic_machines:ball " ) ;
local luaent = obj : get_luaentity ( ) ;
luaent.energy = - 1 ;
obj : set_properties ( { textures = { " basic_machines_ball.png^[colorize:blue:120 " } } )
end
}
} ,
on_receive_fields = function ( pos , formname , fields , sender )
local name = sender : get_player_name ( ) ; if minetest.is_protected ( pos , name ) then return end
if fields.OK then
local privs = minetest.get_player_privs ( sender : get_player_name ( ) ) ;
local meta = minetest.get_meta ( pos ) ;
local x0 = 0 ; local y0 = 0 ; local z0 = 0 ;
--minetest.chat_send_all("form at " .. dump(pos) .. " fields " .. dump(fields))
if fields.x0 then x0 = tonumber ( fields.x0 ) or 0 end
if fields.y0 then y0 = tonumber ( fields.y0 ) or 0 end
if fields.z0 then z0 = tonumber ( fields.z0 ) or 0 end
if not privs.privs and ( math.abs ( x0 ) > 10 or math.abs ( y0 ) > 10 or math.abs ( z0 ) > 10 ) then return end
meta : set_int ( " x0 " , x0 ) ; meta : set_int ( " y0 " , y0 ) ; meta : set_int ( " z0 " , z0 ) ;
local speed , energy , bounce , gravity , puncheable , solid ;
energy = meta : get_float ( " energy " ) ; -- if positive activates, negative deactivates, 0 does nothing
bounce = meta : get_int ( " bounce " ) ; -- if nonzero bounces when hit obstacle, 0 gets absorbed
gravity = meta : get_float ( " gravity " ) ; -- gravity
puncheable = meta : get_int ( " puncheable " ) ; -- if 1 can be punched by players in protection, if 2 can be punched by anyone
solid = meta : get_int ( " solid " ) ;
if fields.speed then
local speed = tonumber ( fields.speed ) or 0 ;
if ( speed > 10 or speed < 0 ) and not privs.privs then return end
meta : set_float ( " speed " , speed )
end
if fields.energy then
local energy = tonumber ( fields.energy ) or 1 ;
meta : set_float ( " energy " , energy )
end
if fields.bounce then
local bounce = tonumber ( fields.bounce ) or 1 ;
meta : set_int ( " bounce " , bounce )
end
if fields.gravity then
local gravity = tonumber ( fields.gravity ) or 1 ;
if ( gravity < 0 or gravity > 30 ) and not privs.privs then return end
meta : set_float ( " gravity " , gravity )
end
if fields.puncheable then
meta : set_int ( " puncheable " , tonumber ( fields.puncheable ) or 0 )
end
if fields.solid then
meta : set_int ( " solid " , tonumber ( fields.solid ) or 0 )
end
if fields.lifetime then
meta : set_int ( " lifetime " , tonumber ( fields.lifetime ) or 0 )
end
if fields.hurt then
meta : set_float ( " hurt " , tonumber ( fields.hurt ) or 0 )
end
if fields.hp then
meta : set_float ( " hp " , math.abs ( tonumber ( fields.hp ) or 0 ) )
end
if fields.texture then
meta : set_string ( " texture " , fields.texture ) ;
end
if fields.scale then
local scale = math.abs ( tonumber ( fields.scale ) or 100 ) ;
if scale > 1000 and not privs.privs then scale = 1000 end
meta : set_int ( " scale " , scale )
end
if fields.visual then
local visual = fields.visual or " " ;
if visual ~= " sprite " and visual ~= " cube " then return end
meta : set_string ( " visual " , fields.visual ) ;
end
ball_spawner_update_form ( pos ) ;
end
end ,
after_dig_node = function ( pos , oldnode , oldmetadata , digger )
local name = digger : get_player_name ( ) ;
local inv = digger : get_inventory ( ) ;
inv : remove_item ( " main " , ItemStack ( " basic_machines:ball_spawner " ) ) ;
local stack = ItemStack ( " basic_machines:ball_spell " ) ;
local meta = oldmetadata [ " fields " ] ;
meta [ " formspec " ] = nil ;
stack : set_metadata ( minetest.serialize ( meta ) ) ;
inv : add_item ( " main " , stack ) ;
end
} )
local spelltime = { } ;
-- ball as magic spell user can cast
minetest.register_tool ( " basic_machines:ball_spell " , {
description = " ball spawner " ,
inventory_image = " basic_machines_ball.png " ,
tool_capabilities = {
full_punch_interval = 2 ,
max_drop_level = 0 ,
} ,
on_use = function ( itemstack , user , pointed_thing )
local pos = user : getpos ( ) ; pos.y = pos.y + 1 ;
local meta = minetest.deserialize ( itemstack : get_metadata ( ) ) ;
if not meta then return end
local owner = meta [ " owner " ] or " " ;
--if minetest.is_protected(pos,owner) then return end
local t0 = spelltime [ owner ] or 0 ;
local t1 = minetest.get_gametime ( ) ;
if t1 - t0 < 2 then return end -- too soon
spelltime [ owner ] = t1 ;
local obj = minetest.add_entity ( { x = pos.x , y = pos.y , z = pos.z } , " basic_machines:ball " ) ;
local luaent = obj : get_luaentity ( ) ;
local speed , energy , bounce , gravity , puncheable ;
speed = tonumber ( meta [ " speed " ] ) or 0 ;
energy = tonumber ( meta [ " energy " ] ) or 0 ; -- if positive activates, negative deactivates, 0 does nothing
bounce = tonumber ( meta [ " bounce " ] ) or 0 ; -- if nonzero bounces when hit obstacle, 0 gets absorbed
gravity = tonumber ( meta [ " gravity " ] ) or 0 ; -- gravity
puncheable = tonumber ( meta [ " puncheable " ] ) or 0 ; -- if 1 can be punched by players in protection, if 2 can be punched by anyone
if energy < 0 then
obj : set_properties ( { textures = { " basic_machines_ball.png^[colorize:blue:120 " } } )
end
luaent.bounce = bounce ;
luaent.energy = energy ;
if gravity > 0 then
obj : setacceleration ( { x = 0 , y =- gravity , z = 0 } ) ;
end
luaent.puncheable = puncheable ;
luaent.owner = meta [ " owner " ] ;
luaent.hurt = math.min ( tonumber ( meta [ " hurt " ] ) , basic_machines.ball . maxdamage ) ;
obj : set_hp ( tonumber ( meta [ " hp " ] ) ) ;
local x0 , y0 , z0 ;
if speed > 0 then luaent.speed = speed end
local v = user : get_look_dir ( ) ;
v.x = v.x * speed ; v.y = v.y * speed ; v.z = v.z * speed ;
obj : setvelocity ( v ) ;
if tonumber ( meta [ " admin " ] ) == 1 then
luaent.lifetime = tonumber ( meta [ " lifetime " ] ) ;
end
obj : set_properties ( { textures = { meta [ " texture " ] } } )
end ,
} )
-- minetest.register_craft({
-- output = "basic_machines:ball_spawner",
-- recipe = {
-- {"basic_machines:power_cell"},
-- {"basic_machines:keypad"}
-- }
-- })