diff --git a/init.lua b/init.lua index 3e72454..09a9058 100644 --- a/init.lua +++ b/init.lua @@ -1,4 +1,110 @@ teleports = {} +teleports.teleports = {} +teleports.lastplayername ="" +teleports.filename = minetest.get_worldpath() .. "/teleports.txt" + +function teleports:save() + local datastring = minetest.serialize(self.teleports) + if not datastring then + return + end + local file, err = io.open(self.filename, "w") + if err then + return + end + file:write(datastring) + file:close() +end +function teleports:load() + local file, err = io.open(self.filename, "r") + if err then + self.teleports = {} + return + end + self.teleports = minetest.deserialize(file:read("*all")) + if type(self.teleports) ~= "table" then + self.teleports = {} + end + file:close() +end +function teleports:find_nearby(pos, count) + local nearby = {} + for i = #teleports.teleports, 1, -1 do + local EachTeleport = teleports.teleports[i] + if not vector.equals(EachTeleport.pos, pos) and vector.distance(EachTeleport.pos, pos) < 260 then + table.insert(nearby, EachTeleport) + if #nearby>count then + break + end + end + end + return nearby +end +teleports.set_formspec = function(pos) + local meta = minetest.get_meta(pos) + local node = minetest.get_node(pos) + + local buttons = ""; + for i, EachTeleport in ipairs( teleports:find_nearby(pos, 5) ) do + buttons = buttons.."button_exit[3,"..(i)..";2,0.5;tp"..i..";GO>"..EachTeleport.pos.x..","..EachTeleport.pos.y..","..EachTeleport.pos.z.."]"; + end + + meta:set_string("formspec", "size[8,10;]" + .."label[0,0;" .. 'Go to available teleports! Use mossy cobble as fuel!' .. "]" + .."list[current_name;price;0,1;1,1;]" + + ..buttons + + .."button_exit[1,5;2,0.5;cancel;Cancel]" + .."list[current_player;main;0,6;8,4;]") +end +teleports.on_receive_fields = function(pos, formname, fields, player) + local meta = minetest.env:get_meta(pos); + local inv = meta:get_inventory(); + local price = {name="default:mossycobble", count=1, wear=0, metadata=""} + if fields.tp1 or fields.tp2 or fields.tp3 or fields.tp4 or fields.tp5 or fields.tp6 then + if inv:contains_item("price", price) then + inv:remove_item("price", price); + local available = teleports:find_nearby(pos, 5) + if player ~= nil and player:is_player() then + if fields.tp1 and #available>0 then + player:setpos({x=available[1].pos.x,y=available[1].pos.y+0.5,z=available[1].pos.z}) + teleports.lastplayername = player:get_player_name() + elseif fields.tp2 and #available>1 then + player:setpos({x=available[2].pos.x,y=available[2].pos.y+0.5,z=available[2].pos.z}) + teleports.lastplayername = player:get_player_name() + elseif fields.tp3 and #available>2 then + player:setpos({x=available[3].pos.x,y=available[3].pos.y+0.5,z=available[3].pos.z}) + teleports.lastplayername = player:get_player_name() + elseif fields.tp4 and #available>3 then + player:setpos({x=available[3].pos.x,y=available[3].pos.y+0.5,z=available[3].pos.z}) + teleports.lastplayername = player:get_player_name() + elseif fields.tp5 and #available>4 then + player:setpos({x=available[5].pos.x,y=available[5].pos.y+0.5,z=available[5].pos.z}) + teleports.lastplayername = player:get_player_name() + elseif fields.tp6 and #available>5 then + player:setpos({x=available[6].pos.x,y=available[6].pos.y+0.5,z=available[6].pos.z}) + teleports.lastplayername = player:get_player_name() + end + end + + teleports.set_formspec(pos) + end + end +end +teleports.allow_metadata_inventory_put = function(pos, listname, index, stack, player) + if listname=="price" and stack:get_name()=="default:mossycobble" then + return 99 + else + return 0 + end +end +teleports.allow_metadata_inventory_take = function(pos, listname, index, stack, player) + return 0 +end + +teleports:load() + minetest.register_node("teleports:teleport", { description = "Teleport", @@ -9,7 +115,32 @@ minetest.register_node("teleports:teleport", { groups = {cracky=1, level=3}, drop = 'default:diamond', sounds = default.node_sound_stone_defaults(), + after_place_node = function(pos, placer) + if placer and placer:is_player() then + local meta = minetest.env:get_meta(pos) + local inv = meta:get_inventory() + inv:set_size("price", 1) + local initialcharge = {name="default:mossycobble", count=30, wear=0, metadata=""} + inv:add_item("price", initialcharge) + teleports.set_formspec(pos) + table.insert(teleports.teleports, {pos=vector.round(pos)} ) + teleports:save() + end + end, + on_destruct = function(pos) + for i, EachTeleport in ipairs(teleports.teleports) do + if vector.equals(EachTeleport.pos, pos) then + table.remove(teleports.teleports, i) + teleports:save() + end + end + end, + on_receive_fields = teleports.on_receive_fields, + allow_metadata_inventory_put = teleports.allow_metadata_inventory_put, + allow_metadata_inventory_take = teleports.allow_metadata_inventory_take, }) + + --redefine diamond minetest.register_node(":default:diamondblock", { description = "Diamond Block", @@ -46,38 +177,23 @@ minetest.register_abm({ interval = 10, chance = 1, action = function(pos) - local objectsnear=minetest.get_objects_inside_radius({x=pos.x,y=pos.y+0.5,z=pos.z}, 0.52) - local r=80 + local objectsnear=minetest.get_objects_inside_radius({x=pos.x,y=pos.y+0.5,z=pos.z}, 0.52); if #objectsnear>0 then - local player = objectsnear[1] - if player:is_player() then - local power = minetest.find_nodes_in_area( - {x=pos.x-1, y=pos.y, z=pos.z-1}, - {x=pos.x+1, y=pos.y, z=pos.z+1}, - {"default:diamondblock"}) - r=r+#power*20 --diamond blocks around teleport increase its range - local positions = minetest.find_nodes_in_area( - {x=pos.x-r, y=pos.y-r, z=pos.z-r}, - {x=pos.x+r, y=pos.y+r, z=pos.z+r}, - {"teleports:teleport"}) - while #positions>1 do + local player = objectsnear[1]; + if player:is_player() and player:get_player_name()~=teleports.lastplayername then + local positions = teleports:find_nearby(pos, 10) + if #positions>0 then local key = math.random(1, #positions) - local pos2 = positions[key] --choose teleport randomly - if (pos.x == pos2.x and pos.y == pos2.y and pos.z == pos2.z) or -- any better way to compare? - minetest.get_node({x=pos2.x,y=pos2.y+1,z=pos2.z}).name~="air" or - minetest.get_node({x=pos2.x,y=pos2.y+2,z=pos2.z}).name~="air" - then - table.remove(positions, key) - else - minetest.after(0.2, function() - if player ~= nil and player:is_player() then --still is player, just in case - player:setpos({x=pos2.x,y=pos2.y+0.5,z=pos2.z}) - minetest.log("info", "Player teleported from "..pos.x..","..pos.y..","..pos.z.." to "..pos2.x..","..pos2.y..","..pos2.z) - end - end) - break - end + local pos2 = positions[key].pos + teleports.lastplayername = player:get_player_name() + if math.random(1, 100) > 5 then + player:setpos({x=pos2.x,y=pos2.y+0.5,z=pos2.z}) + else + player:setpos({x=pos2.x-5+math.random(1, 10),y=pos2.y+3,z=pos2.z-5+math.random(1, 10)}) + end end + else + teleports.lastplayername = "" end end end,