669 lines
No EOL
22 KiB
Lua
669 lines
No EOL
22 KiB
Lua
-- 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");
|
|
hurt = meta:get_float("hurt");
|
|
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"}
|
|
-- }
|
|
-- }) |