diff --git a/basic_machines/ball.lua b/basic_machines/ball.lua deleted file mode 100644 index 844ecbe..0000000 --- a/basic_machines/ball.lua +++ /dev/null @@ -1,669 +0,0 @@ --- 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"} - -- } --- }) \ No newline at end of file