diff --git a/config.lua b/config.lua new file mode 100644 index 0000000..2ec9d62 --- /dev/null +++ b/config.lua @@ -0,0 +1,17 @@ +-- GUN CONFIGURATION -- + +gsettings = {} +-- gravity acceleration (metres/second^2) +gsettings.SPLASH_STREAM_GRAVITY = 9.8 + +-- speed of stream splash (metres/second) +gsettings.SPLASH_STREAM_SPEED = 50 + +-- lifetime of splash drop (seconds) +gsettings.SPLASH_DROP_LIFETIME = 2 + +-- splash stream collision box +gsettings.SPLASH_STREAM_COLLISION_BOX = {-0.1, -0.1, -0.1, 0.1, 0.1, 0.1} + +-- splash drop collision box +gsettings.SPLASH_DROP_COLLISION_BOX = {-0.05, -0.05, -0.05, 0.05, 0.05, 0.05} diff --git a/depends.txt b/depends.txt index 8d1c8b6..1810f69 100644 --- a/depends.txt +++ b/depends.txt @@ -1 +1 @@ - +default diff --git a/gun.lua b/gun.lua index d531c4c..60b9d86 100644 --- a/gun.lua +++ b/gun.lua @@ -1,17 +1,34 @@ -local gun = {} +-- PORTAL GUN -- -gun.SPLASH_STREAM_GRAVITY = 9.8 -gun.SPLASH_STREAM_SPEED = 50 -- metres/second -gun.SPLASH_DROP_LIFETIME = 2 -- seconds +gun = {} -gun.generate_splash_bounces = function(pos, normal, splash_color) +gun.generate_splash_particles = function(pos, normal, splash_color) local rand_amount = math.random(20, 25) - - local side = vector.rotate_around_axis({x=normal.x, y=0, z=normal.z}, {x=0, y=1, z=0}, math.pi/2) - - local signs = {-1, 1} - for i = 1, rand_amount do - local rand_pitch = math.rad(math.random(10, 45)) * signs[math.random(1, 2)] + + local min_vel_dir = vector.rotate(normal, {x=0, y=-math.pi/4, z=0}) + local max_vel_dir = vector.rotate(normal, {x=-math.pi/4, y=math.pi/4, z=0}) + + minetest.add_particlespawner({ + amount = rand_amount, + time = 0.1, + minpos = pos, + maxpos = pos, + minvel = vector.multiply(min_vel_dir, 5), + maxvel = vector.multiply(max_vel_dir, 5), + minacc = {x=0, y=-gsettings.SPLASH_STREAM_GRAVITY, z=0}, + maxacc = {x=0, y=-gsettings.SPLASH_STREAM_GRAVITY, z=0}, + minexptime = 1.5, + maxexptime = 2.5, + minsize = 3, + maxsize = 3.5, + collisiondetection = false, + collision_removal = false, + object_collision = false, + texture = "portaltest_splash_drop.png^[multiply:" .. splash_color, + glow = 7 + }) + --[[for i = 1, rand_amount do + local rand_pitch = -math.rad(math.random(10, 45)) local rand_yaw = math.rad(math.random(10, 45)) * signs[math.random(1, 2)] normal = vector.rotate_around_axis(normal, side, rand_pitch) @@ -21,8 +38,8 @@ gun.generate_splash_bounces = function(pos, normal, splash_color) local splash_drop = minetest.add_entity(pos, "portaltest:splash_drop") splash_drop:set_properties({textures={"portaltest_splash_drop.png^[multiply:" .. splash_color}}) - splash_drop:set_velocity(vector.multiply(res_dir, 10)) - end + splash_drop:set_velocity(vector.multiply(res_dir, 4)) + end]] end gun.bounce_splash_drop = function(drop, surface_normal) @@ -31,7 +48,7 @@ gun.bounce_splash_drop = function(drop, surface_normal) if not self then return end local new_vel = vector.multiply(self.last_velocity, -1) - local cross = vector.cross(new_vel, surface_normal) + local cross = vector.cross(surface_normal, new_vel) new_vel = vector.rotate_around_axis(new_vel, cross, vector.angle(surface_normal, new_vel)*2) drop:set_velocity(new_vel) @@ -40,7 +57,7 @@ end gun.global_step_through_players_with_guns = function() local players = minetest.get_connected_players() - for i, player in ipairs(players) do + for _, player in ipairs(players) do if player:get_wielded_item():get_name() == "portaltest:gun_empty" then local ctrls = player:get_player_control() local color = "" @@ -55,13 +72,19 @@ gun.global_step_through_players_with_guns = function() player:set_wielded_item(ItemStack("portaltest:gun_" .. color)) local pl_pos = player:get_pos() - local rel_offset_pos = vector.add(vector.new(0, 0, 1), vector.new(1, 0, 0)) + local rel_offset_pos = vector.new(0.5, 0, 0) + rel_offset_pos.y = 0.5 - rel_offset_pos = vector.rotate(rel_offset_pos, {x=player:get_look_vertical(), y=player:get_look_horizontal(), z=0}) + local dir = player:get_look_dir() + local dir_rot = vector.dir_to_rotation(dir) + rel_offset_pos = vector.rotate(rel_offset_pos, dir_rot) local pos = vector.add(pl_pos, rel_offset_pos) local splash_stream = minetest.add_entity(pos, "portaltest:splash_stream") splash_stream:set_properties({textures={"portaltest_splash_stream.png^[multiply:" .. color}}) - splash_stream:set_velocity(vector.multiply(player:get_look_dir(), gun.SPLASH_STREAM_SPEED)) + splash_stream:set_velocity(vector.multiply(dir, gsettings.SPLASH_STREAM_SPEED)) + + local self = splash_stream:get_luaentity() + self.stream_emitter = player:get_player_name() minetest.after(0.5, function() player:set_wielded_item(ItemStack("portaltest:gun_empty")) @@ -70,6 +93,100 @@ gun.global_step_through_players_with_guns = function() end end +gun.get_pointedthing_info = function(pos, dir, ray_length) + local pos2 = vector.add(pos, vector.multiply(dir, ray_length)) + local raycast = minetest.raycast(pos, pos2) + + local target_pt + for pt in raycast do + if pt.type == "object" then + local self = pt.ref:get_luaentity() + if self then + minetest.debug("ray has intersected an object with name: " .. self.name) + if self.name ~= "portaltest:splash_stream" then + target_pt = pt + break + else + --minetest.debug("raycast: " .. self.name) + end + end + elseif pt.type == "node" then + minetest.debug("raycast has intersected a node with name: " .. minetest.get_node(pt.under).name) + target_pt = pt + break + end + end + + return target_pt +end + +gun.update_player_portals_datas = function(player_meta) + local player_portals = minetest.deserialize(player_meta:get_string("portals")) + + if not player_portals or player_portals == {} then + return + end + + local new_datas = {} + + for color, pos in pairs(player_portals) do + local actual_node = minetest.get_node(player_portals[color]) + + if actual_node.name == "portaltest:portal_" .. color then + new_datas[color] = {x=pos.x, y=pos.y, z=pos.z} + end + end + + player_meta:set_string("portals", minetest.serialize(new_datas)) +end + +gun.place_portal = function(placer, pt, color, param2, dir_to_top) + local meta = placer:get_meta() + gun.update_player_portals_datas(meta) + local player_portals = minetest.deserialize(meta:get_string("portals")) + + if not player_portals or player_portals == {} then + player_portals = {} + end + + if portal.is_pos_busy_by_portal(pt.above) then + return + end + + if player_portals[color] then + minetest.remove_node(player_portals[color]) + end + + player_portals[color] = pt.above + + meta:set_string("portals", minetest.serialize(player_portals)) + + minetest.add_node(pt.above, {name = "portaltest:portal_" .. color, param2 = param2}) + + local setp_meta = minetest.get_meta(player_portals[color]) + + local cp_pos + + if color == "orange" then + if player_portals["blue"] then + cp_pos = player_portals["blue"] + end + elseif color == "blue" then + if player_portals["orange"] then + cp_pos = player_portals["orange"] + end + end + + if cp_pos then + setp_meta:set_string("connected_to", minetest.serialize(cp_pos)) + + local cp_meta = minetest.get_meta(cp_pos) + cp_meta:set_string("connected_to", minetest.serialize(player_portals[color])) + end + + setp_meta:set_string("dir_to_top", minetest.serialize(dir_to_top)) +end + minetest.register_node("portaltest:gun_empty", { drawtype = "mesh", visual_scale = 0.5, @@ -141,17 +258,108 @@ minetest.register_entity("portaltest:splash_stream", { visual_size = {x=1, y=1, z=1}, physical = true, collide_with_objects = true, - collisionbox = {-0.2, -0.2, -0.2, 0.2, 0.2, 0.2}, + collisionbox = gsettings.SPLASH_STREAM_COLLISION_BOX, selectionbox = {0, 0, 0, 0, 0, 0}, textures = {"portaltest_splash_stream.png"}, backface_culling = false, glow = 7, on_activate = function(self, staticdata, dtime_s) - self.object:set_acceleration({x=0, y=-gun.SPLASH_STREAM_GRAVITY, z=0}) + self.move_dir = vector.normalize(self.object:get_velocity()) end, on_step = function(self, dtime, moveresult) - if moveresult.collides then - local colls = moveresult.collisions + if not moveresult.collides then + self.move_dir = vector.normalize(self.object:get_velocity()) + else + local pos = self.object:get_pos() + local vel = self.object:get_velocity() + minetest.debug("cur_vel: " .. vector.length(vel)) + local texture = self.object:get_properties().textures[1] + + self.object:remove() + --minetest.debug("self.last_velocity: " .. minetest.pos_to_string(self.last_velocity)) + --minetest.debug("current velocity: " .. minetest.pos_to_string(vel)) + + local pt + if vector.length(self.move_dir) == 0 then + pt = gun.get_pointedthing_info(pos, vector.normalize(vel), 1) + else + pt = gun.get_pointedthing_info(pos, self.move_dir, 1) + end + + if pt then + minetest.debug("\'pt\' is not nil!") + --minetest.debug("pt.type: " .. pt.type) + --minetest.debug("pt.intersection_normal: " .. minetest.pos_to_string(pt.intersection_normal)) + --minetest.debug("pt.type: " .. pt.type) + local s, e = texture:find("%^%[multiply:", 1) + local color = texture:sub(e+1, texture:len()) + local player = minetest.get_player_by_name(self.stream_emitter) + if pt.type == "node" then + if pt.intersection_normal.y == 0 then + -- Portal is placed on the wall + local node = minetest.get_node_or_nil(pt.under) + local node2 = minetest.get_node_or_nil(vector.new(pt.under.x, pt.under.y+1, pt.under.z)) + + if (node and node.name == "portaltest:panel_mono") and + (node2 and node2.name == "portaltest:panel_mono") and + minetest.get_node({x=pt.above.x, y=pt.above.y+1, z=pt.above.z}).name == "air" then + + gun.place_portal(player, pt, color, minetest.dir_to_facedir(pt.intersection_normal), {x=0, y=1, z=0}) + end + else + -- Portal is placed on the floor/ceiling + local look_dir = player:get_look_dir() + local horiz_look_dir = vector.new(look_dir.x, 0, look_dir.z) + local x_horiz_dir = vector.new(look_dir.x, 0, 0) + local z_horiz_dir = vector.new(0, 0, look_dir.z) + local target_horiz_dir = vector.angle(x_horiz_dir, horiz_look_dir) < vector.angle(horiz_look_dir, z_horiz_dir) and x_horiz_dir or z_horiz_dir + + local node = minetest.get_node_or_nil(pt.under) + local node2 = minetest.get_node_or_nil(vector.add(pt.under, target_horiz_dir)) + local node3 = minetest.get_node_or_nil(vector.add(pt.under, vector.add(pt.intersection_normal, target_horiz_dir))) + + if (node and node.name == "portaltest:panel_mono") and + (node2 and node2.name == "portaltest:panel_mono") and + (node3 and node3.name == "air") then + + -- Keys are param2 values, values are corresponding directions + local y_up_rots = { + [6] = {x=0, y=0, z=1}, + [8] = {x=0, y=0, z=-1}, + [15] = {x=1, y=0, z=0}, + [17] = {x=-1, y=0, z=0} + } + + local y_down_rots = { + [4] = {x=0, y=0, z=-1}, + [10] = {x=0, y=0, z=1}, + [13] = {x=-1, y=0, z=0}, + [19] = {x=1, y=0, z=0} + } + + local target_param2 + local dir_to_top + + local nrmlzed_thd = vector.normalize(target_horiz_dir) + local target_y_rots = pt.intersection_normal.y == 1 and y_up_rots or y_down_rots + + for p2, dir in pairs(target_y_rots) do + if vector.equals(nrmlzed_thd, dir) then + target_param2 = p2 + dir_to_top = dir + break + end + end + + gun.place_portal(player, pt, color, target_param2, dir_to_top) + end + end + end + + gun.generate_splash_particles(pt.intersection_point, pt.intersection_normal, color) + + end + --[[local colls = moveresult.collisions minetest.debug("moveresult.collisions: " .. #moveresult.collisions) local sum_normal = vector.new() @@ -171,23 +379,23 @@ minetest.register_entity("portaltest:splash_stream", { local s, e = texture:find("%^%[multiply:", 1) gun.generate_splash_bounces(pos, sum_normal, texture:sub(e+1, texture:len())) - self.object:remove() + self.object:remove()]] end end }) -minetest.register_entity("portaltest:splash_drop", { +--[[minetest.register_entity("portaltest:splash_drop", { visual = "sprite", visual_size = {x=1, y=1, z=1}, physical = true, collide_with_objects = true, textures = {"portaltest_splash_drop.png"}, - collisionbox = {-0.05, -0.05, -0.05, 0.05, 0.05, 0.05}, + collisionbox = gsettings.SPLASH_DROP_COLLISION_BOX, selectionbox = {0, 0, 0, 0, 0, 0}, backface_culling = false, glow = 7, on_activate = function(self, staticdata, dtime_s) - self.object:set_acceleration({x=0, y=-gun.SPLASH_STREAM_GRAVITY, z=0}) + self.object:set_acceleration({x=0, y=-gsettings.SPLASH_STREAM_GRAVITY, z=0}) self.last_velocity = self.object:get_velocity() self.dtime = 0 end, @@ -197,22 +405,24 @@ minetest.register_entity("portaltest:splash_drop", { if not moveresult.collides then self.last_velocity = self.object:get_velocity() else - local pos = self.object:get_pos() - local vel = self.object:get_velocity() - local pos2 = vector.add(pos, vector.multiply(vel, dtime)) - local raycast = minetest.raycast(pos, pos2) - local pt = raycast:next() - - if pt then + local min_cb_pos = { + x = gsettings.SPLASH_DROP_COLLISION_BOX[1], + y = gsettings.SPLASH_DROP_COLLISION_BOX[2], + z = gsettings.SPLASH_DROP_COLLISION_BOX[3] + } + + local pt = gun.get_pointedthing_info(self.object:get_pos(), self.last_velocity, 1, dtime) + + if pt and pt.intersection_normal then gun.bounce_splash_drop(self.object, pt.intersection_normal) end end - if self.dtime >= gun.SPLASH_DROP_LIFETIME then + if self.dtime >= gsettings.SPLASH_DROP_LIFETIME then self.object:remove() end end -}) +})]] minetest.register_globalstep(function(dtime) diff --git a/init.lua b/init.lua index 3b9e1d7..6c26c6c 100644 --- a/init.lua +++ b/init.lua @@ -1,3 +1,6 @@ local modpath = minetest.get_modpath("portaltest") +dofile(modpath .. "/config.lua") dofile(modpath .. "/gun.lua") +dofile(modpath .. "/panels.lua") +dofile(modpath .. "/portal.lua") diff --git a/models/portaltest_gun.b3d b/models/portaltest_gun.b3d index 38c5531..4f0b87e 100644 Binary files a/models/portaltest_gun.b3d and b/models/portaltest_gun.b3d differ diff --git a/models/portaltest_gun.blend b/models/portaltest_gun.blend index f76b1b5..3daa9dd 100644 Binary files a/models/portaltest_gun.blend and b/models/portaltest_gun.blend differ diff --git a/models/portaltest_gun.blend1 b/models/portaltest_gun.blend1 index 92568a7..f76b1b5 100644 Binary files a/models/portaltest_gun.blend1 and b/models/portaltest_gun.blend1 differ diff --git a/models/portaltest_portal.b3d b/models/portaltest_portal.b3d new file mode 100644 index 0000000..b67a818 Binary files /dev/null and b/models/portaltest_portal.b3d differ diff --git a/models/portal.blend b/models/portaltest_portal.blend similarity index 60% rename from models/portal.blend rename to models/portaltest_portal.blend index e260ed8..da8c7c5 100644 Binary files a/models/portal.blend and b/models/portaltest_portal.blend differ diff --git a/models/portal.blend1 b/models/portaltest_portal.blend1 similarity index 60% rename from models/portal.blend1 rename to models/portaltest_portal.blend1 index 099d49a..eb95dab 100644 Binary files a/models/portal.blend1 and b/models/portaltest_portal.blend1 differ diff --git a/panels.lua b/panels.lua index 6d5bb33..a036e1b 100644 --- a/panels.lua +++ b/panels.lua @@ -1,10 +1,8 @@ +-- WHITE PANELS FROM MOON ROCK -- + minetest.register_node("portaltest:panel_mono", { description = "Mono Panel", - drawtype = "normal", - tiles = {"portaltest_while_panel.png"}, - paramtype = "light", - paramtype2 = "facedir", - sunlight_propagates = true, - groups = {cracky=1.5}, + tiles = {"portaltest_white_panel.png"}, + groups = {cracky=1.5, moonpanel = 1}, sounds = default.node_sound_stone_defaults() }) diff --git a/portal.lua b/portal.lua index 8d1c8b6..b784006 100644 --- a/portal.lua +++ b/portal.lua @@ -1 +1,239 @@ - +-- PORTALS -- + +portal = {} + +-- Return unit direction of node with position 'pos'. +portal.dir = function(pos) + local node = minetest.get_node(pos) + local back_dir = minetest.facedir_to_dir(node.param2) + + local dir = vector.multiply(back_dir, -1) + + return dir +end + +-- Rotates obj`s collision and selection boxes angles 'rot' (in radians). +-- Rotation occurs relatively to obj`s box rotation!!! +portal.rotate_entity_bounding_box = function(obj, rot) + if not obj:get_luaentity() then return end + + if not (math.deg(rot.x) % 90 == 0) or not (math.deg(rot.y) % 90 == 0) or not (math.deg(rot.z) % 90 == 0) then return end + + local def = obj:get_properties() + local colbox = def.collisionbox + local selbox = def.selectionbox + local new_colbox = {} + local new_selbox = {} + + new_colbox[1] = vector.rotate({x=colbox[1], y=colbox[2], z=colbox[3]}, rot) + new_colbox[2] = vector.rotate({x=colbox[4], y=colbox[5], z=colbox[6]}, rot) + + new_selbox[1] = vector.rotate({x=selbox[1], y=selbox[2], z=selbox[3]}, rot) + new_selbox[2] = vector.rotate({x=selbox[4], y=selbox[5], z=selbox[6]}, rot) + + local res_colbox = { + new_colbox[1].x, new_colbox[1].y, new_colbox[1].z, + new_colbox[2].x, new_colbox[2].y, new_colbox[2].z + } + + local res_selbox = { + new_selbox[1].x, new_selbox[1].y, new_selbox[1].z, + new_selbox[2].x, new_selbox[2].y, new_selbox[2].z + } + + return res_colbox, res_selbox +end + +-- Called each the node timer step. +--If there are objects within 'catch_box' box and their collision boxes are located at 0.1 distance to the portal surface, then teleport them saving their impulse. +portal.teleport_entity = function(pos) + local connected_to = minetest.deserialize(minetest.get_meta(pos):get_string("connected_to")) + --minetest.debug("connected_to: " .. (connected_to and minetest.pos_to_string(connected_to) or tostring(nil))) + + if not connected_to then + --minetest.debug("Nothing can be teleported at the moment as the portal at " .. minetest.pos_to_string(pos) .. " is unconnected!") + return + end + + local pdir = minetest.facedir_to_dir(minetest.get_node(pos).param2) + -- Catch_box coordinates are relative to the node`s origin (pos) + local catch_box = {vector.new(-0.4, -0.4, -0.5), vector.new(0.4, 1.4, -0.5)} + local pdir_rot = vector.dir_to_rotation(pdir) + + catch_box[1] = vector.rotate(catch_box[1], pdir_rot) + catch_box[2] = vector.add(vector.rotate(catch_box[2], pdir_rot), vector.multiply(pdir, 1.45)) + minetest.debug("catch_box: [1]=" .. minetest.pos_to_string(vector.add(pos, catch_box[1])) .. ", [2]=" .. minetest.pos_to_string(vector.add(pos, catch_box[2]))) + + local catched_objs = minetest.get_objects_in_area(vector.add(pos, catch_box[1]), vector.add(pos, catch_box[2])) + --minetest.debug("#catched_objs: " .. #catched_objs) + + local iter_func = function(obj) + local centre_point = vector.add(pos, vector.divide(vector.add(catch_box[1], vector.rotate(vector.new(0.4, 1.4, -0.5), pdir_rot)), 2)) + --minetest.debug("centre_point: " .. minetest.pos_to_string(centre_point)) + local epos_dir = vector.subtract(obj:get_pos(), centre_point) + + --[[local origin_epos_dir = vector.rotate(epos_dir, vector.multiply(vector.dir_to_rotation(epos_dir), -1)) + local epos_horiz_dir = vector.rotate(vector.new(origin_epos_dir.x, 0, origin_epos_dir.z), vector.dir_to_rotation(epos_dir)) + local abs_epos_horiz_dir = vector.add(centre_point, epos_horiz_dir)]] + + local dist_to_epos = vector.length(epos_dir)*math.cos(vector.angle(epos_dir, pdir)) + --minetest.debug("dist_to_epos: " .. dist_to_epos) + local rel_epos_horiz_dir = vector.subtract(epos_dir, vector.multiply(pdir, dist_to_epos)) + local abs_epos_horiz_dir = vector.add(centre_point, vector.multiply(rel_epos_horiz_dir, -1)) + + local raycast = minetest.raycast(abs_epos_horiz_dir, obj:get_pos()) + + for pt in raycast do + if pt.type == "object" and pt.ref == obj then + local dist_to_psurface = vector.distance(abs_epos_horiz_dir, pt.intersection_point) + minetest.debug("dist_to_psurface: " .. dist_to_psurface) + + if not (dist_to_psurface < 0.15) then + return + end + end + end + + local cportal_dir = minetest.facedir_to_dir(minetest.get_node(connected_to).param2) + minetest.debug("cportal_dir: " .. minetest.pos_to_string(cportal_dir)) + local box_rot = vector.subtract(vector.dir_to_rotation(cportal_dir), vector.dir_to_rotation(pdir_rot)) + + local new_colbox, new_selbox = portal.rotate_entity_bounding_box(obj, box_rot) + local target_pos = vector.add(connected_to, vector.multiply(vector.divide(cportal_dir, 2), dist_to_epos)) + minetest.debug("target_pos: " .. minetest.pos_to_string(target_pos)) + + if minetest.get_node(target_pos).name ~= "air" and not portal.is_pos_busy_by_portal(target_pos) then + return + end + + minetest.debug("set_pos()...") + obj:set_pos(target_pos) + obj:set_properties({collisionbox = new_colbox, selectionbox = new_selbox}) + + if obj:is_player() then + obj:set_look_vertical(obj:get_look_vertical()+box_rot.x) + obj:set_look_horizontal(obj:get_look_horizontal()+box_rot.y) + else + obj:set_rotation(vector.add(obj:get_rotation(), box_rot)) + end + + local cur_vel = obj:get_velocity() + local target_vel = vector.rotate(cur_vel, box_rot) + + obj:add_velocity(vector.subtract(target_vel, cur_vel)) + end + + for _, obj in ipairs(catched_objs) do + iter_func(obj) + end +end + +portal.is_pos_busy_by_portal = function(pos) + local portal_pos = minetest.find_node_near(pos, 1, {"portaltest:portal_orange", "portaltest:portal_blue"}, true) + + if not portal_pos then return end + + local dir_to_top = minetest.deserialize(minetest.get_meta(portal_pos):get_string("dir_to_top")) + local portal_pos2 = vector.add(portal_pos, dir_to_top) + + return vector.distance(pos, portal_pos) < 0.5 or + vector.distance(pos, portal_pos2) < 0.5 +end + +portal.check_for_portal_footing = function(pos) + local dir_to_top = minetest.deserialize(minetest.get_meta(pos):get_string("dir_to_top")) + local back_dir = vector.multiply(minetest.facedir_to_dir(minetest.get_node(pos).param2), -1) + + local node1 = minetest.get_node(vector.add(pos, back_dir)) + local node2 = minetest.get_node(vector.add(pos, vector.add(back_dir, dir_to_top))) + + if node1.name == "air" or node2.name == "air" then + minetest.remove_node(pos) + end +end + +portal.remove = function(pos) + local connected_to = minetest.deserialize(minetest.get_meta(pos):get_string("connected_to")) + + if not connected_to or connected_to == {} then + return + end + + minetest.get_meta(connected_to):set_string("connected_to", "") + + minetest.remove_node(pos) +end + +minetest.register_node("portaltest:portal_orange", { + description = "Portal", + drawtype = "mesh", + mesh = "portaltest_portal.b3d", + tiles = {"portaltest_orange_portal.png"}, + paramtype = "light", + paramtype2 = "facedir", + sunlight_propagates = true, + groups = {not_in_creative_inventory=1}, + light_source = 14, + collision_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, -0.5, 0.5, -0.4, -0.4}, -- Bottom Box + {-0.5, -0.4, -0.5, -0.4, 1.4, -0.4}, -- Left Box + {0.4, -0.4, -0.5, 0.5, 1.4, -0.4}, -- Right Box + {-0.5, 1.4, -0.5, 0.5, 1.5, -0.4} -- Top Box + } + }, + selection_box = { + type = "fixed", + fixed = {0, 0, 0, 0, 0, 0} + }, + on_construct = function(pos) + local timer = minetest.get_node_timer(pos) + timer:start(0.1) + end, + on_destruct = function(pos) + portal.remove(pos) + end, + on_timer = function(pos, elapsed) + portal.teleport_entity(pos) + portal.check_for_portal_footing(pos) + return true + end +}) + +minetest.register_node("portaltest:portal_blue", { + description = "Portal", + drawtype = "mesh", + mesh = "portaltest_portal.b3d", + tiles = {"portaltest_blue_portal.png"}, + paramtype = "light", + paramtype2 = "facedir", + sunlight_propagates = true, + groups = {not_in_creative_inventory=1}, + light_source = 14, + collision_box = { + type = "fixed", + fixed = { + {-0.5, -0.5, -0.5, 0.5, -0.4, -0.4}, -- Bottom Box + {-0.5, -0.4, -0.5, -0.4, 1.4, -0.4}, -- Left Box + {0.4, -0.4, -0.5, 0.5, 1.4, -0.4}, -- Right Box + {-0.5, 1.4, -0.5, 0.5, 1.5, -0.4} -- Top Box + } + }, + selection_box = { + type = "fixed", + fixed = {0, 0, 0, 0, 0, 0} + }, + on_construct = function(pos) + local timer = minetest.get_node_timer(pos) + timer:start(0.1) + end, + on_destruct = function(pos) + portal.remove(pos) + end, + on_timer = function(pos, elapsed) + portal.teleport_entity(pos) + portal.check_for_portal_footing(pos) + return true + end +}) diff --git a/textures/portaltest_anti_expropriation_field.png b/textures/portaltest_anti_expropriation_field.png new file mode 100644 index 0000000..051520c Binary files /dev/null and b/textures/portaltest_anti_expropriation_field.png differ diff --git a/textures/portaltest_splash_stream.png b/textures/portaltest_splash_stream.png index c0f76a4..7c8c66d 100644 Binary files a/textures/portaltest_splash_stream.png and b/textures/portaltest_splash_stream.png differ