disable_portal_stuff=false proportal_group_only = false portalgun={new=0,checkpoints={}} dofile(minetest.get_modpath("portalgun") .. "/gravityuse.lua") -- the gravity part of portalgun dofile(minetest.get_modpath("portalgun") .. "/craft.lua") dofile(minetest.get_modpath("portalgun") .. "/stuff.lua") -- security cam if disable_portal_stuff==false and minetest.get_modpath("mesecons")~=nil then dofile(minetest.get_modpath("portalgun") .. "/weightedstoragecube.lua") -- weighted storage cube dofile(minetest.get_modpath("portalgun") .. "/powerball.lua") -- the poweball dofile(minetest.get_modpath("portalgun") .. "/other.lua") end portalgun_portal={} portalgun_portal_tmp_user_abort=0 portalgun_portal_tmp_user="" local portalgun_timer=1.2 local portalgun_time=0 portalgun_lifelime=1200 --deletes portals that not used after a while portalgun_max_rage=100 portalgun_max_use_per_secund_time=4 --destroys the portal if excessive used portalgun_max_use_per_secund=25 --4 & 25 is default = teleported (teleported 25 times in 4 sec) function portalgun_param2(pos,param2,r) local pos2={x=pos.x,y=pos.y,z=pos.z} if r then if param2==0 then pos2.x=pos2.x-1 elseif param2==1 then pos2.z=pos2.z+1 elseif param2==2 then pos2.x=pos2.x+1 elseif param2==3 then pos2.z=pos2.z-1 end else if param2==0 then pos2.x=pos2.x+1 elseif param2==1 then pos2.z=pos2.z-1 elseif param2==2 then pos2.x=pos2.x-1 elseif param2==3 then pos2.z=pos2.z+1 end end return pos2 end local function portalgun_getLength(a)-- get length of an array / table local count = 0 for _ in pairs(a) do count = count + 1 end return count end function portal_delete(name,n) -- using set_hp & :punch instand of :remove ... no risk for crash if something attach it if portalgun_portal[name]==nil then return end if (n==1 or n==0) and portalgun_portal[name].portal1~=nil then if n==0 then local pos=portalgun_portal[name].portal1:get_pos() if pos~=nil then minetest.sound_play("portalgun_closeportals", {pos=pos,max_hear_distance = 20, gain = 1}) end end portalgun_portal[name].portal1_active=false portalgun_portal[name].portal1:set_hp(0) portalgun_portal[name].portal1:punch(portalgun_portal[name].portal1, {full_punch_interval=1.0,damage_groups={fleshy=9000}}, "default:bronze_pick", nil) end if (n==2 or n==0) and portalgun_portal[name].portal2~=nil then if n==0 then local pos=portalgun_portal[name].portal2:get_pos() if pos~=nil then minetest.sound_play("portalgun_closeportals", {pos=pos,max_hear_distance = 20, gain = 1}) end end portalgun_portal[name].portal2_active=false portalgun_portal[name].portal2:set_hp(0) portalgun_portal[name].portal2:punch(portalgun_portal[name].portal2, {full_punch_interval=1.0,damage_groups={fleshy=9000}}, "default:bronze_pick", nil) end if n==0 then portalgun_portal[name]=nil end end minetest.register_on_leaveplayer(function(player)-- deletes user the profile (saveing memory) local name=player:get_player_name() portal_delete(name,0) portalgun_portal[name]=nil end) minetest.register_on_dieplayer(function(player) local name=player:get_player_name() portal_delete(name,0) portalgun_portal[name]=nil end) portalgun_on_step=function(self, dtime) local name=self.user if portalgun_portal[self.user]==nil then self.object:remove() return self end if (self.project==1 and self.use~=portalgun_portal[self.user].portal1_use) or (self.project==2 and self.use~=portalgun_portal[self.user].portal2_use) then self.object:remove() return self end if portalgun_portal[name].lifelime<0 then portal_delete(name,0) return self end if portalgun_portal[name].portal1_active and portalgun_portal[name].portal2_active then -- makes lifetime equal when both is acive, or it will be half portalgun_portal[name].lifelime=portalgun_portal[name].lifelime-0.5 else portalgun_portal[name].lifelime=portalgun_portal[name].lifelime-1 return self -- abort when only 1 is active (saves cpu) end if portalgun_portal[name].timer>0 then -- makes teleported stuff wont move back at same time (bug fix) portalgun_portal[name].timer=portalgun_portal[name].timer-dtime return self end if self.portal_max_use>0 then -- makes teleported stuff wont move back at same time (bug fix) self.portal_max_use_time=self.portal_max_use_time+dtime if self.portal_max_use>=portalgun_max_use_per_secund then portal_delete(name,self.project) return self elseif self.portal_max_use_time>=portalgun_max_use_per_secund_time then self.portal_max_use_time=0 self.portal_max_use=0 end end local pos1=0 local pos2=0 local d1=0 local d2=0 if self.project==1 then pos1=portalgun_portal[name].portal1_pos pos2=portalgun_portal[name].portal2_pos d1=portalgun_portal[name].portal1_dir d2=portalgun_portal[name].portal2_dir else pos1=portalgun_portal[name].portal2_pos pos2=portalgun_portal[name].portal1_pos d1=portalgun_portal[name].portal2_dir d2=portalgun_portal[name].portal1_dir end -- portalgun_front_of_field should fix teleport through walls, but is not working in all directions -- waiting with this issue if pos2~=0 and pos1~=0 then for ii, ob in pairs(minetest.get_objects_inside_radius(pos1, self.area)) do if pos2~=0 then --and portalgun_front_of_field(self.object,ob) if (ob:is_player() ) or (ob:get_luaentity() and ob:get_luaentity().portalgun~=1 and ob:get_luaentity().name:find(":text",4)==nil) then if ob:get_attach() then ob:set_detach() ob:set_acceleration({x=0, y=-10, z=0}) end --set velocity then teleport local p=pos2 local x=0 local y=0 local z=0 local dis=2 if p==nil or p.x==nil then return self end if ob:is_player() then local v=ob:get_player_velocity() local player_name=ob:get_player_name() portalgun_power.user=player_name portalgun_power.target=ob local vv={x=v.x,y=v.y,z=v.z} -- get the highest velocity dis=2 if vv.x+vv.y+vv.z<=0.3 then if self.small==true then vv.x=1.4 else vv.x=2 end end if vv.x+vv.y+vv.z==0 then vv.x=2 end if vv.x<0 then vv.x=vv.x*-1 end if vv.y<0 then vv.y=vv.y*-1 end if vv.z<0 then vv.z=vv.z*-1 end if vv.x>vv.z then vv.a=vv.x else vv.a=vv.z end if vv.av.z then vv=v.x else vv=v.z end if vv8 then pos1.y=pos1.y+1 end if portalgun_portal[self.user].y>12 then pos1.y=pos1.y+1 end if self.project==1 then portalgun_portal[self.user].portal1_pos=pos1 else portalgun_portal[self.user].portal2_pos=pos1 end elseif string.find(d,"y",1)==nil and (portalgun_portal[self.user].x+portalgun_portal[self.user].z<2.5) then self.area=1.2 self.small=true self.object:set_properties({visual_size = {x=0.7, y=0.7},}) end end, on_step=portalgun_on_step, }) minetest.register_node("portalgun:gun1", { description = "Portalgun (blue)", range = 5, tiles={"portalgun_gun1.png"}, selection_box = { type = "fixed", fixed = { {-0.3, -0.5, -0.3, 0.3, -0.1,0.3}, } }, drawtype="mesh", mesh="portalgun_gun_wearing.obj", groups = {not_in_creative_inventory=1}, sunlight_propagates = true, paramtype="light", paramtype2="facedir", on_place=function(itemstack, user, pointed_thing) portalgun_mode(itemstack, user, pointed_thing) return itemstack end, on_use = function(itemstack, user, pointed_thing) portalgun_onuse(itemstack, user, pointed_thing) return itemstack end }) minetest.register_node("portalgun:gun2", { description = "Portalgun (orange)", range = 5, tiles={"portalgun_gun2.png"}, selection_box = { type = "fixed", fixed = { {-0.3, -0.5, -0.3, 0.3, -0.1,0.3}, } }, drawtype="mesh", mesh="portalgun_gun_wearing.obj", groups = {not_in_creative_inventory=1}, sunlight_propagates = true, paramtype="light", paramtype2="facedir", on_place=function(itemstack, user, pointed_thing) portalgun_mode(itemstack, user, pointed_thing) return itemstack end, on_use = function(itemstack, user, pointed_thing) portalgun_onuse(itemstack, user, pointed_thing) return itemstack end }) minetest.register_node("portalgun:gun", { description = "Portalgun", range = 5, tiles={"portalgun_gun0.png"}, selection_box = { type = "fixed", fixed = { {-0.3, -0.5, -0.3, 0.3, -0.1,0.3}, } }, drawtype="mesh", mesh="portalgun_gun_wearing.obj", sunlight_propagates = true, paramtype="light", paramtype2="facedir", on_place=function(itemstack, user, pointed_thing) portalgun_mode(itemstack, user, pointed_thing) return itemstack end, on_use = function(itemstack, user, pointed_thing) portalgun_onuse(itemstack, user, pointed_thing) return itemstack end }) minetest.register_node("portalgun:gun1_placed", { description = "Portalgun (blue)", range = 5, tiles={"portalgun_gun1.png"}, selection_box = { type = "fixed", fixed = { {-0.3, -0.5, -0.3, 0.3, -0.1,0.3}, } }, drawtype="mesh", mesh="portalgun_gun.obj", sunlight_propagates = true, paramtype="light", paramtype2="facedir", visual_scale=0.4, groups = {not_in_creative_inventory=1,dig_immediate = 3}, on_use = function(itemstack, user, pointed_thing) portalgun_onuse(itemstack, user, pointed_thing) return itemstack end }) minetest.register_node("portalgun:gun2_placed", { description = "Portalgun (orange)", range = 5, tiles={"portalgun_gun2.png"}, selection_box = { type = "fixed", fixed = { {-0.3, -0.5, -0.3, 0.3, -0.1,0.3}, } }, drawtype="mesh", mesh="portalgun_gun.obj", sunlight_propagates = true, paramtype="light", paramtype2="facedir", visual_scale=0.4, groups = {not_in_creative_inventory=1,dig_immediate = 3}, on_use = function(itemstack, user, pointed_thing) portalgun_onuse(itemstack, user, pointed_thing) return itemstack end }) minetest.register_node("portalgun:gun_placed", { description = "Portalgun", range = 5, tiles={"portalgun_gun0.png"}, selection_box = { type = "fixed", fixed = { {-0.3, -0.5, -0.3, 0.3, -0.1,0.3}, } }, drawtype="mesh", mesh="portalgun_gun.obj", sunlight_propagates = true, paramtype="light", paramtype2="facedir", visual_scale=0.4, groups = {not_in_creative_inventory=1,dig_immediate = 3}, on_use = function(itemstack, user, pointed_thing) portalgun_onuse(itemstack, user, pointed_thing) return itemstack end }) function portalgun_mode(itemstack, user, pointed_thing) -- change modes local item=itemstack:to_table() local meta=minetest.deserialize(item["metadata"]) local mode=0 if meta==nil then meta={} mode=1 minetest.chat_send_player(user:get_player_name(), " PLACE to change portal mode (or LEFT+RIGHTCLICK to use the other)") minetest.chat_send_player(user:get_player_name(), " LEFTCLICK on an object to carry it, CLICK AGAIN to release") minetest.chat_send_player(user:get_player_name(), " SHIFT+LEFTCLICK to close both portals (or wait 40sec until it removes it self)") end if meta.mode==nil then meta.mode=2 end mode=(meta.mode) if mode==1 then mode=2 else mode=1 end meta.mode=mode item.name="portalgun:gun"..mode item.metadata=minetest.serialize(meta) itemstack:replace(item) minetest.sound_play("portalgun_mode", {pos=user:get_pos(),max_hear_distance = 5, gain = 1}) end local function rnd(r) return math.floor(r+ 0.5) end function portalgun_onuse(itemstack, user, pointed_thing) -- using the gun if pointed_thing.type=="object" then portalgun_gravity(itemstack, user, pointed_thing) return itemstack end local pos = user:get_pos() local dir = user:get_look_dir() local key = user:get_player_control() local name=user:get_player_name() local exist=0 local item=itemstack:to_table() local mode=minetest.deserialize(item["metadata"]) if mode==nil then portalgun_mode(itemstack, user, pointed_thing) return itemstack else mode=mode.mode end local ob={} ob.project=1 ob.lifelime=portalgun_lifelime ob.portal1=0 ob.portal2=0 ob.portal1_dir=0 ob.portal2_dir=0 ob.portal2_pos=0 ob.portal1_pos=0 ob.user = user:get_player_name() if portalgun_portal[name]==nil then -- new portal profile portalgun_portal[name]={lifelime=portalgun_lifelime,project=1,timer=0,portal1_active=false,portal2_active=false,portal1_use=0,portal2_use=0} end if key.RMB and mode==2 then -- hold rmbutton to use the other one (like diplazer) mode=1 elseif key.RMB and mode==1 then mode=2 end if key.sneak then portal_delete(name,0) return itemstack end pos.y=pos.y+1.5 -- the project for i=1, portalgun_max_rage,0.5 do local nname=minetest.get_node({x=pos.x+(dir.x*i), y=pos.y+(dir.y*i), z=pos.z+(dir.z*i)}).name if minetest.registered_nodes[nname].walkable then portalgun_portal[name].lifelime=portalgun_lifelime if not proportal_group_only and minetest.get_node_group(nname, "antiportal") > 0 then minetest.sound_play("portalgun_error", {pos=pos,max_hear_distance = 5, gain = 3}) return itemstack elseif proportal_group_only and minetest.get_node_group(nname, "proportal") == 0 then minetest.sound_play("portalgun_error", {pos=pos,max_hear_distance = 5, gain = 3}) return itemstack end if minetest.registered_nodes[minetest.get_node({x=rnd(pos.x+(dir.x*i)), y=rnd(pos.y+(dir.y*i)+1), z=rnd(pos.z+(dir.z*i))}).name].walkable==false and rnd(user:get_pos().y)>rnd(pos.y+(dir.y*i)) then portalgun_setportal(pos,name,dir,i,mode,"y+") return itemstack elseif minetest.registered_nodes[minetest.get_node({x=rnd(pos.x+(dir.x*i)), y=rnd(pos.y+(dir.y*i)-1), z=rnd(pos.z+(dir.z*i))}).name].walkable==false and rnd(user:get_pos().y)rnd(pos.x+(dir.x*i)) then portalgun_setportal(pos,name,dir,i,mode,"x+") return itemstack elseif minetest.registered_nodes[minetest.get_node({x=rnd(pos.x+(dir.x*i)), y=rnd(pos.y+(dir.y*i)), z=rnd(pos.z+(dir.z*i)-1)}).name].walkable==false and rnd(user:get_pos().z)rnd(pos.z+(dir.z*i)) then portalgun_setportal(pos,name,dir,i,mode,"z+") return itemstack end minetest.sound_play("portalgun_error", {pos=pos,max_hear_distance = 20, gain = 3}) return itemstack end end return itemstack end function portalgun_setportal(pos,name,dir,i,mode,portal_dir) local lpos={x=pos.x+(dir.x*(i-1)), y=pos.y+(dir.y*(i-1)), z=pos.z+(dir.z*(i-1))} -- last pos local cpos={x=pos.x+(dir.x*i), y=pos.y+(dir.y*i), z=pos.z+(dir.z*i)} -- corrent poss if portal_dir=="y+" then cpos.y=(math.floor(cpos.y+ 0.5))+0.524 elseif portal_dir=="y-" then cpos.y=(math.floor(cpos.y+ 0.5))-0.524 elseif portal_dir=="z+" then cpos.z=(math.floor(cpos.z+ 0.5))+0.524 elseif portal_dir=="z-" then cpos.z=(math.floor(cpos.z+ 0.5))-0.524 elseif portal_dir=="x+" then cpos.x=(math.floor(cpos.x+ 0.5))+0.524 elseif portal_dir=="x-" then cpos.x=(math.floor(cpos.x+ 0.5))-0.524 end if portal_dir=="x+" or portal_dir=="x-" then -- auto correct (place in center) cpos.y=(math.floor(cpos.y+ 0.5)) cpos.z=(math.floor(cpos.z+ 0.5)) elseif portal_dir=="y+" or portal_dir=="y-" then cpos.x=(math.floor(cpos.x+ 0.5)) cpos.z=(math.floor(cpos.z+ 0.5)) elseif portal_dir=="z+" or portal_dir=="z-" then cpos.x=(math.floor(cpos.x+ 0.5)) cpos.y=(math.floor(cpos.y+ 0.5)) end if minetest.registered_nodes[minetest.get_node(cpos).name].walkable then minetest.sound_play("portalgun_error", {pos=pos,max_hear_distance = 5, gain = 3}) return false end if string.find(portal_dir,"x",1) or string.find(portal_dir,"z",1) then-- auto correct (move from bottom / top) local testpos1={x=cpos.x,y=cpos.y-1,z=cpos.z} local testpos2={x=cpos.x,y=cpos.y+1,z=cpos.z} if minetest.registered_nodes[minetest.get_node(testpos1).name].walkable and minetest.registered_nodes[minetest.get_node(testpos2).name].walkable==false then cpos.y=cpos.y+0.5 elseif minetest.registered_nodes[minetest.get_node(testpos2).name].walkable and minetest.registered_nodes[minetest.get_node(testpos1).name].walkable==false then cpos.y=cpos.y-0.5 end end portalgun_portal_tmp_user=name portalgun_portal[name].x=pos.x-lpos.x portalgun_portal[name].y=pos.y-lpos.y portalgun_portal[name].z=pos.z-lpos.z portalgun_portal[name].project=mode if portalgun_portal[name].x<0 then portalgun_portal[name].x=portalgun_portal[name].x*-1 end if portalgun_portal[name].z<0 then portalgun_portal[name].z=portalgun_portal[name].z*-1 end if mode==1 then portal_delete(name,1) portalgun_portal[name].portal1_use=portalgun_portal[name].portal1_use+1 portalgun_portal[name].portal1_dir=portal_dir portalgun_portal[name].portal1_pos=cpos portalgun_portal[name].portal1=minetest.add_entity(cpos, "portalgun:portal") portalgun_portal[name].portal1_active=true minetest.sound_play("portalgun_portalblue", {pos=cpos, max_hear_distance = 20, gain = 1}) else portal_delete(name,2) portalgun_portal[name].portal2_use=portalgun_portal[name].portal2_use+1 portalgun_portal[name].portal2_dir=portal_dir portalgun_portal[name].portal2_pos=cpos portalgun_portal[name].portal2=minetest.add_entity(cpos, "portalgun:portal") portalgun_portal[name].portal2_active=true minetest.sound_play("portalgun_portalorange", {pos=cpos,max_hear_distance = 20, gain = 1}) end end portalgun_front_of_field=function(ob,ob2) local pos2=ob2:get_pos() return vector.distance(ob:get_pos(),pos2)>vector.distance(portalgun_pointat(ob),pos2) end portalgun_pointat=function(ob) local pos=ob:get_pos() local yaw=ob:get_yaw() if yaw ~= yaw or type(yaw)~="number" then yaw=0 end local z =math.sin(yaw) * -0.1 local x =math.cos(yaw) * 0.1 return {x=pos.x+x,y=pos.y,z=pos.z+z} end