Mod upload

master
Piezo_ 2018-09-08 22:56:22 -07:00
commit 61cf93befa
39 changed files with 5697 additions and 0 deletions

15
CHANGES.txt Normal file
View File

@ -0,0 +1,15 @@
Changes by Piezo_:
Improved portal response time by changing the teleport routine from a node update to a global step
Changed how portals update their world-node
Changed model scale and hitbox dimensions
Vertically offset model to be partially buried.
Non-player objects can now travel through portals
Reduced active portal brightness somewhat
Restructured portal network to prevent players causing trouble by naming themself "players" or "registered_players"
Visual style and sounds completely re-done to add originality
Public portals can now be used by anyone, but only the portal's owner can set the description and public/private state.
Server operators can disable "ownership" of portals by setting meseportals.allowPrivatePortals (in init.lua) to false
A maximum number of allowed portals per player can be set via meseportals.maxPlayerPortals
Added permissions "msp_admin", which allows full control and access to all portals, and "msp_unlimited", which bypasses the portal cap.
Reorganized/Split up files
Position and rotation relative to the portal are now maintained, making travel feel smoother.

27
LICENSE.txt Normal file
View File

@ -0,0 +1,27 @@
Copyright (C) 2018 "Piezo_"
Copyright (C) 2015-2016 - Maciej "RealBadAngel" Kasatkin
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject
to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of the authors shall
not be used in advertising or otherwise to promote the sale, use or
other dealings in this Software without prior written authorization
from the authors.

2
depends.txt Normal file
View File

@ -0,0 +1,2 @@
default
bucket

1
description.txt Normal file
View File

@ -0,0 +1 @@
A futuristic multiplayer transportation system built on RealBadAngel's mod for Minetest.

31
init.lua Normal file
View File

@ -0,0 +1,31 @@
-- Minetest 0.4.5 : meseportals
--data tables definitions
meseportals={}
meseportals_network = {}
meseportals_gui = {}
meseportals.allowPrivatePortals = true
meseportals.maxPlayerPortals = 14 --Set to 0 or lower to restrict portal placement to those with msp_unlimited privilege
meseportals.default_page = "main"
meseportals_gui["players"]={}
meseportals["registered_players"] = {}
meseportals.current_page={}
minetest.register_privilege("msp_admin", {
description = "Allows full control of all mese portals.",
give_to_singleplayer = false,
})
minetest.register_privilege("msp_unlimited", {
description = "Allows player to place an unlimited number of mese portals.",
give_to_singleplayer = true,
})
modpath=minetest.get_modpath("meseportals")
dofile(modpath.."/meseportal_network.lua")
dofile(modpath.."/meseportal_gui.lua")
dofile(modpath.."/portal_defs.lua")
dofile(modpath.."/recipes.lua")
dofile(modpath.."/node_behaviors.lua")

438
meseportal_gui.lua Normal file
View File

@ -0,0 +1,438 @@
local reportFormspecViolation = function(submitter_name, violation)
local path = minetest.get_worldpath().."/meseportals_incidents.log"
local file = io.open( path, "r" )
local data = ""
if( file ) then
data = file:read("*all")
file:close()
end
data = data.."<"..os.date().."> "..submitter_name.." "..violation.."\n"
file = io.open( path, "w" )
if( file ) then
file:write( data )
file:close()
end
end
local getCleanText = function(submitter_name, scan_text)
if scan_text ~= nil then
if string.find(scan_text, ";") or
string.find(scan_text, "%[") or
string.find(scan_text, "%]") or
string.find(scan_text, "\\") then
reportFormspecViolation(submitter_name, "sent dirty string of length "..string.len(scan_text)..": "..scan_text)
--Call me paranoid. The length bit is so that someone can't get away with causing their report to line-break, and fabricating a fake report on the next line, essentially framing another player as well as themself.
return ""
else
return scan_text
end
else
return nil
end
end
meseportals.searchportals = function(pos, player_name, isAdmin)
meseportals_gui["players"][player_name]["own_portals"]={}
meseportals_gui["players"][player_name]["public_portals"]={}
local own_portals_count=0
local public_portals_count=0
for __,portals in ipairs(meseportals_network[player_name]) do
if portals["pos"].x==pos.x and portals["pos"].y==pos.y and portals["pos"].z==pos.z then
--current_portal=portals
else
own_portals_count=own_portals_count+1
if string.find(portals["description"], meseportals_gui["players"][player_name]["query"]) then
table.insert(meseportals_gui["players"][player_name]["own_portals"],portals)
end
end
end
-- get all public portals
for __,tab in ipairs(meseportals["registered_players"]) do
local temp=tab["player_name"]
for __,portals in ipairs(meseportals_network[temp]) do
if string.find(portals["description"], meseportals_gui["players"][player_name]["query"]) then
if portals["type"]=="public" or isAdmin or not meseportals.allowPrivatePortals then
if portals["pos"].x==pos.x and portals["pos"].y==pos.y and portals["pos"].z==pos.z then
--current_portal=portals
else
public_portals_count=public_portals_count+1
table.insert(meseportals_gui["players"][player_name]["public_portals"],portals)
end
end
end
end
end
meseportals_gui["players"][player_name]["own_portals_count"]=own_portals_count
meseportals_gui["players"][player_name]["public_portals_count"]=public_portals_count
end
--show formspec to player
meseportals.portalFormspecHandler = function(pos, _, clicker, _)
if (meseportals.findPortal(pos) ~= nil) then
local player_name = clicker:get_player_name()
local isAdmin = minetest.check_player_privs(clicker, {msp_admin=true})
local owner=meseportals.findPortal(pos)["owner"]
if meseportals.findPortal(pos)["type"] == "private" and player_name ~= owner and meseportals.allowPrivatePortals and not isAdmin then
minetest.chat_send_player(clicker:get_player_name(), meseportals.findPortal(pos)["owner"] .." has set this portal to private.")
return
else
local current_portal=meseportals.findPortal(pos)
meseportals_gui["players"][player_name]["query"]=""
meseportals.searchportals(pos, player_name, isAdmin)
-- print(dump(meseportals_gui["players"][player_name]["public_portals"]))
if current_portal == nil then
print ("Portal not registered in network! Please remove it and place once again.")
return nil
end
meseportals_gui["players"][player_name]["current_index"]=0
meseportals_gui["players"][player_name]["temp_portal"]["owner"]=current_portal.owner
meseportals_gui["players"][player_name]["temp_portal"]["type"]=current_portal["type"]
meseportals_gui["players"][player_name]["temp_portal"]["description"]=current_portal["description"]
meseportals_gui["players"][player_name]["temp_portal"]["pos"]={}
meseportals_gui["players"][player_name]["temp_portal"]["pos"] = vector.new(pos)
if current_portal["destination"] then
meseportals_gui["players"][player_name]["temp_portal"]["destination_description"]=current_portal["destination_description"]
meseportals_gui["players"][player_name]["temp_portal"]["destination_dir"]=current_portal["destination_dir"]
meseportals_gui["players"][player_name]["temp_portal"]["destination"]={}
meseportals_gui["players"][player_name]["temp_portal"]["destination"].x=current_portal["destination"].x
meseportals_gui["players"][player_name]["temp_portal"]["destination"].y=current_portal["destination"].y
meseportals_gui["players"][player_name]["temp_portal"]["destination"].z=current_portal["destination"].z
else
meseportals_gui["players"][player_name]["temp_portal"]["destination"]=nil
end
meseportals_gui["players"][player_name]["dest_type"]="all"
local formspec=meseportals.get_formspec(player_name,"main")
meseportals_gui["players"][player_name]["formspec"]=formspec
if formspec ~=nil then minetest.show_formspec(player_name, "meseportals_main", formspec) end
end
else
minetest.chat_send_player(clicker:get_player_name(), "This portal is broken.")
end
end
-- get_formspec
meseportals.get_formspec = function(player_name,page)
if player_name==nil then return nil end
meseportals_gui["players"][player_name]["current_page"]=page
local temp_portal=meseportals_gui["players"][player_name]["temp_portal"]
local isAdmin = minetest.check_player_privs(player_name, {msp_admin=true})
local formspec = "size[14,9.8]"
--background
formspec = formspec .."background[-0.19,-0.25;14.38,10.6;meseportal_ui_form_bg.png]"
formspec = formspec.."label[0,0.0;Mese Portal ("
if meseportals.allowPrivatePortals then
formspec=formspec..temp_portal["owner"]
end
formspec = formspec..")]"
formspec = formspec.."label[0,.5;Position: ("..temp_portal["pos"].x..","..temp_portal["pos"].y..","..temp_portal["pos"].z..")]"
if player_name == temp_portal["owner"] or isAdmin or not meseportals.allowPrivatePortals then
if meseportals.allowPrivatePortals then
formspec = formspec.."image_button[3.5,.6;.6,.6;meseportal_toggle_icon.png;toggle_type;]"
formspec = formspec.."label[4,.5;Type: "..temp_portal["type"].."]"
end
formspec = formspec.."image_button[6.5,.6;.6,.6;meseportal_pencil_icon.png;edit_desc;]"
end
formspec = formspec.."label[0,1.1;Destination: ]"
if temp_portal["destination"] then
if meseportals.findPortal(temp_portal["destination"]) then
if isAdmin or meseportals.findPortal(temp_portal["destination"])["type"] ~= "private" or player_name == meseportals.findPortal(temp_portal["destination"])["owner"] or not meseportals.allowPrivatePortals then
formspec = formspec.."label[2.5,1.1;"..temp_portal["destination_description"].." ("..temp_portal["destination"].x..","..temp_portal["destination"].y..","..temp_portal["destination"].z..") "
if isAdmin then
formspec = formspec.."("..meseportals.findPortal(temp_portal["destination"])["type"]..")"
end
formspec = formspec.."]"
else
formspec = formspec.."label[2.5,1.1;Private Portal]"
end
else
formspec = formspec.."label[2.5,1.1;Invalid Destination]"
end
formspec = formspec.."image_button[2,1.2;.6,.6;meseportal_cancel_icon.png;remove_dest;]"
else
formspec = formspec.."label[2,1.1;Not connected]"
end
formspec = formspec.."label[0,1.7;Aviable destinations:]"
formspec = formspec.."image_button[3.5,1.8;.6,.6;meseportal_toggle_icon.png;toggle_dest_type;]"
formspec = formspec.."label[4,1.7;Filter: "..meseportals_gui["players"][player_name]["dest_type"].."]"
formspec = formspec.."image_button[12.6,1.375;.8,.8;meseportal_ui_search_icon.png;update_search_query;]"
formspec = formspec.."field[9.5,1.6;3.5,1;search_box;Search...;"..meseportals_gui["players"][player_name]["query"].."]"
if page=="main" then
if player_name == temp_portal["owner"]or isAdmin or not meseportals.allowPrivatePortals then
formspec = formspec.."image_button[6.5,.6;.6,.6;meseportal_pencil_icon.png;edit_desc;]"
end
formspec = formspec.."label[7,.5;Description: "..temp_portal["description"].."]"
end
if page=="edit_desc" then
if player_name == temp_portal["owner"]or isAdmin or not meseportals.allowPrivatePortals then
formspec = formspec.."image_button[6.5,.6;.6,.6;meseportal_ok_icon.png;save_desc;]"
end
formspec = formspec.."field[7.3,.7;5,1;desc_box;Edit portal description:;"..temp_portal["description"].."]"
end
local list_index=meseportals_gui["players"][player_name]["current_index"]
local page=math.floor(list_index / 24 + 1)
local pagemax
if meseportals_gui["players"][player_name]["dest_type"] == "own" then
pagemax = math.floor((meseportals_gui["players"][player_name]["own_portals_count"] / 24) + 1)
local x,y
for y=0,7,1 do
for x=0,2,1 do
local portal_temp=meseportals_gui["players"][player_name]["own_portals"][list_index+1]
if portal_temp then
formspec = formspec.."image_button["..(x*4.5)..","..(2.5+y*.87)..";.6,.6;meseportal.png;list_button"..list_index..";]"
formspec = formspec.."label["..(x*4.5+.5)..","..(2.3+y*.87)..";"
if portal_temp["destination"] ~= nil then
formspec = formspec.."<A> "
end
formspec = formspec.."("..portal_temp["pos"].x..","..portal_temp["pos"].y..","..portal_temp["pos"].z..") "..portal_temp["type"].."]"
formspec = formspec.."label["..(x*4.5+.5)..","..(2.7+y*.87)..";"..portal_temp["description"].."]"
end
list_index=list_index+1
end
end
else
pagemax = math.floor(meseportals_gui["players"][player_name]["public_portals_count"] / 24 + 1)
local x,y
for y=0,7,1 do
for x=0,2,1 do
local portal_temp=meseportals_gui["players"][player_name]["public_portals"][list_index+1]
if portal_temp then
formspec = formspec.."image_button["..(x*4.5)..","..(2.5+y*.87)..";.6,.6;meseportal.png;list_button"..list_index..";]"
formspec = formspec.."label["..(x*4.5+.5)..","..(2.3+y*.87)..";"
if portal_temp["destination"] ~= nil then
formspec = formspec.."<A> "
end
formspec=formspec.."("..portal_temp["pos"].x..","..portal_temp["pos"].y..","..portal_temp["pos"].z..") "..portal_temp["owner"].."]"
formspec = formspec.."label["..(x*4.5+.5)..","..(2.7+y*.87)..";"..portal_temp["description"]
if isAdmin then
formspec = formspec.." ("..portal_temp["type"]..")"
end
formspec = formspec.."]"
end
list_index=list_index+1
end
end
end
formspec=formspec.."label[7.5,1.7;Page: "..page.." of "..pagemax.."]"
formspec = formspec.."image_button[6.5,1.8;.6,.6;meseportal_left_icon.png;page_left;]"
formspec = formspec.."image_button[6.9,1.8;.6,.6;meseportal_right_icon.png;page_right;]"
formspec = formspec.."image_button_exit[6.1,9.3;.8,.8;meseportal_ok_icon.png;save_changes;]"
formspec = formspec.."image_button_exit[7.1,9.3;.8,.8;meseportal_cancel_icon.png;discard_changes;]"
return formspec
end
-- register_on_player_receive_fields
minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "meseportals_main" then return end
local player_name = player:get_player_name()
local isAdmin = minetest.check_player_privs(player, {msp_admin=true})
local temp_portal=meseportals_gui["players"][player_name]["temp_portal"]
local current_portal=meseportals.findPortal(meseportals_gui["players"][player_name]["temp_portal"]["pos"])
local formspec
if current_portal then
if player_name == current_portal["owner"] or isAdmin or not meseportals.allowPrivatePortals then
if fields.toggle_type then
if temp_portal["type"] == "private" then
temp_portal["type"] = "public"
else
temp_portal["type"] = "private"
end
meseportals_gui["players"][player_name]["current_index"]=0
formspec= meseportals.get_formspec(player_name,"main")
meseportals_gui["players"][player_name]["formspec"] = formspec
minetest.show_formspec(player_name, "meseportals_main", formspec)
minetest.sound_play("click", {to_player=player_name, gain = 0.5})
return
end
if fields.edit_desc then
formspec= meseportals.get_formspec(player_name,"edit_desc")
meseportals_gui["players"][player_name]["formspec"]=formspec
minetest.show_formspec(player_name, "meseportals_main", formspec)
minetest.sound_play("click", {to_player=player_name, gain = 0.5})
return
end
if fields.save_desc then
temp_portal["description"]=getCleanText(player_name, fields.desc_box)
formspec= meseportals.get_formspec(player_name,"main")
meseportals_gui["players"][player_name]["formspec"]=formspec
minetest.show_formspec(player_name, "meseportals_main", formspec)
minetest.sound_play("click", {to_player=player_name, gain = 0.5})
return
end
else
if fields.toggle_type then
reportFormspecViolation(player_name, "attempted to change type of someone else's portal!")
end
if fields.edit_desc then
reportFormspecViolation(player_name, "attempted to edit description of someone else's portal!")
end
if fields.save_desc then
reportFormspecViolation(player_name, "attempted to change description of someone else's portal!")
end
end
if fields.toggle_dest_type then
if meseportals_gui["players"][player_name]["dest_type"] == "own" then
meseportals_gui["players"][player_name]["dest_type"] = "all"
else meseportals_gui["players"][player_name]["dest_type"] = "own" end
meseportals_gui["players"][player_name]["current_index"] = 0
formspec = meseportals.get_formspec(player_name,"main")
meseportals_gui["players"][player_name]["formspec"] = formspec
minetest.show_formspec(player_name, "meseportals_main", formspec)
minetest.sound_play("click", {to_player=player_name, gain = 0.5})
return
end
if fields.update_search_query then
meseportals_gui["players"][player_name]["query"] = getCleanText(player_name, fields.search_box)
meseportals.searchportals(current_portal["pos"], player_name, isAdmin)
formspec = meseportals.get_formspec(player_name,"main")
meseportals_gui["players"][player_name]["formspec"] = formspec
minetest.show_formspec(player_name, "meseportals_main", formspec)
minetest.sound_play("click", {to_player=player_name, gain = 0.5})
end
-- page controls
local start=math.floor(meseportals_gui["players"][player_name]["current_index"]/24 +1 )
local start_i=start
local pagemax
if meseportals_gui["players"][player_name]["dest_type"] == "own" then
pagemax = math.floor(((meseportals_gui["players"][player_name]["own_portals_count"]) / 24) + 1)
else
pagemax = math.floor(((meseportals_gui["players"][player_name]["public_portals_count"]) / 24) + 1)
end
if fields.page_left then
minetest.sound_play("paperflip2", {to_player=player_name, gain = 1.0})
start_i = start_i - 1
if start_i < 1 then start_i = 1 end
if not (start_i == start) then
meseportals_gui["players"][player_name]["current_index"] = (start_i-1)*24
formspec = meseportals.get_formspec(player_name,"main")
meseportals_gui["players"][player_name]["formspec"] = formspec
minetest.show_formspec(player_name, "meseportals_main", formspec)
end
end
if fields.page_right then
minetest.sound_play("paperflip2", {to_player=player_name, gain = 1.0})
start_i = start_i + 1
if start_i > pagemax then start_i = pagemax end
if not (start_i == start) then
meseportals_gui["players"][player_name]["current_index"] = (start_i-1)*24
formspec = meseportals.get_formspec(player_name,"main")
meseportals_gui["players"][player_name]["formspec"] = formspec
minetest.show_formspec(player_name, "meseportals_main", formspec)
end
end
if fields.remove_dest then
minetest.sound_play("click", {to_player=player_name, gain = 0.5})
temp_portal["destination"]=nil
temp_portal["destination_description"]=nil
formspec = meseportals.get_formspec(player_name,"main")
meseportals_gui["players"][player_name]["formspec"] = formspec
minetest.show_formspec(player_name, "meseportals_main", formspec)
end
if fields.save_changes then
minetest.sound_play("click", {to_player=player_name, gain = 0.5})
local meta = minetest.get_meta(temp_portal["pos"])
local infotext=""
if player_name == current_portal["owner"] or isAdmin or not meseportals.allowPrivatePortals then
if fields.desc_box ~= nil then
temp_portal["description"]=getCleanText(player_name, fields.desc_box)
end
current_portal["type"]=temp_portal["type"]
current_portal["description"]=temp_portal["description"]
end
current_portal["dest"]=temp_portal["dest"]
if temp_portal["destination"] then
local dest_portal = meseportals.findPortal(temp_portal["destination"])
if dest_portal then
if dest_portal["type"] ~= "private" or dest_portal["owner"] == player_name or isAdmin then
if current_portal["destination"] ~= nil then
current_portal["destination_deactivate"] = vector.new(current_portal["destination"])
end
current_portal["destination"]={}
current_portal["destination"]=vector.new(temp_portal["destination"])
current_portal["destination_description"]=temp_portal["destination_description"]
current_portal["destination_dir"]=temp_portal["destination_dir"]
else
reportFormspecViolation(player_name, "attempted to connect to private portal at "..minetest.pos_to_string(dest_portal.pos).." from "..minetest.pos_to_string(current_portal.pos))
end
else
minetest.chat_send_player(player_name, "The portal seems to have vanished while you were still in the menu...")
end
else
if current_portal["destination"] ~= nil then
current_portal["destination_deactivate"] = vector.new(current_portal["destination"])
meseportals.deactivatePortal(current_portal.pos)
end
end
if current_portal["destination_deactivate"] ~= nil then
if meseportals.findPortal(current_portal["destination_deactivate"]) then
meseportals.deactivatePortal (current_portal["destination_deactivate"])
current_portal["destination_deactivate"] = nil
end
end
if meseportals.findPortal(current_portal["destination"]) then
local dest_portal = meseportals.findPortal(current_portal["destination"])
if dest_portal["destination"] == nil or isAdmin then
if dest_portal["destination"] then --Admin can interrupt an existing connection
meseportals.deactivatePortal(dest_portal["destination"])
end
meseportals.activatePortal (current_portal.pos)
dest_portal["destination"] = current_portal["pos"]
dest_portal["destination_description"] = current_portal["description"]
dest_portal["destination_dir"] = current_portal["dir"]
meseportals.activatePortal (dest_portal.pos)
else
minetest.chat_send_player(player_name, "Connection failed: Portal is busy.")
meseportals.deactivatePortal (current_portal["pos"])
end
else
meseportals.deactivatePortal (current_portal["pos"])
end
if meseportals.save_data(current_portal["owner"])==nil then
print ("[meseportals] Couldnt update network file!")
end
end
if fields.discard_changes then
minetest.sound_play("click", {to_player=player_name, gain = 0.5})
end
local list_index=meseportals_gui["players"][player_name]["current_index"]
local i
for i=0,23,1 do
local button="list_button"..i+list_index
if fields[button] then
minetest.sound_play("click", {to_player=player_name, gain = 1.0})
local portal=meseportals_gui["players"][player_name]["temp_portal"]
local dest_portal
if meseportals_gui["players"][player_name]["dest_type"] == "own" then
dest_portal=meseportals_gui["players"][player_name]["own_portals"][list_index+i+1]
else
dest_portal=meseportals_gui["players"][player_name]["public_portals"][list_index+i+1]
end
portal["destination"]={}
portal["destination"].x=dest_portal["pos"].x
portal["destination"].y=dest_portal["pos"].y
portal["destination"].z=dest_portal["pos"].z
portal["destination_description"]=dest_portal["description"]
portal["destination_dir"]=dest_portal["dir"]
formspec = meseportals.get_formspec(player_name,"main")
meseportals_gui["players"][player_name]["formspec"] = formspec
minetest.show_formspec(player_name, "meseportals_main", formspec)
end
end
end
end)

148
meseportal_network.lua Normal file
View File

@ -0,0 +1,148 @@
local function table_empty(tab)
for key in pairs(tab) do return false end
return true
end
meseportals.save_data = function(table_pointer)
local data = minetest.serialize( meseportals_network[table_pointer] )
local path = minetest.get_worldpath().."/meseportals_"..table_pointer..".data"
local file = io.open( path, "w" )
if( file ) then
file:write( data )
file:close()
return true
else return nil
end
end
meseportals.restore_data = function(table_pointer)
local path = minetest.get_worldpath().."/meseportals_"..table_pointer..".data"
local file = io.open( path, "r" )
if( file ) then
local data = file:read("*all")
meseportals_network[table_pointer] = minetest.deserialize( data )
file:close()
if table_empty(meseportals_network[table_pointer]) then os.remove(path) end
return true
else return nil
end
end
meseportals.load_players = function()
local path = minetest.get_worldpath().."/meseportals.players"
local file = io.open( path, "r" )
if( file ) then
local data = file:read("*all")
meseportals["registered_players"] = minetest.deserialize( data )
file:close()
if table_empty(meseportals["registered_players"]) then os.remove(path) end
return true
else return nil
end
end
meseportals.save_players = function()
if table_empty(meseportals["registered_players"]) then return end
local data = minetest.serialize( meseportals["registered_players"] )
local path = minetest.get_worldpath().."/meseportals.players"
local file = io.open( path, "w" )
if( file ) then
file:write( data )
file:close()
return true
else return nil
end
end
-- load meseportalss network data
if meseportals.load_players() ~= nil then
for __,tab in ipairs(meseportals["registered_players"]) do
if meseportals.restore_data(tab["player_name"]) == nil then
--print ("[meseportals] Error loading data!")
meseportals_network[tab["player_name"]] = {}
end
end
else
print ("[meseportals] Error loading data! Creating new file.")
meseportals["registered_players"]={}
meseportals.save_players()
end
-- register_on_joinplayer
minetest.register_on_joinplayer(function(player)
local player_name = player:get_player_name()
local registered=nil
for __,tab in ipairs(meseportals["registered_players"]) do
if tab["player_name"] == player_name then registered = true break end
end
if registered == nil then
local new={}
new["player_name"]=player_name
table.insert(meseportals["registered_players"],new)
meseportals_network[player_name]={}
meseportals.save_players()
meseportals.save_data(player_name)
end
meseportals_gui["players"][player_name]={
formspec = "",
current_page = meseportals.default_page,
own_portals ={},
own_portals_count =0,
public_portals ={},
public_portals_count =0,
current_index =0,
temp_portal ={},
}
end)
meseportals.unregisterPortal = function(pos)
for _,tab in pairs(meseportals.registered_players) do
local player_name=tab.player_name
for __,portal in ipairs(meseportals_network[player_name]) do
if portal["pos"].x==pos.x and portal["pos"].y==pos.y and portal["pos"].z==pos.z then
table.remove(meseportals_network[player_name], __)
if meseportals.save_data(player_name)==nil then
print ("[meseportals] Couldnt update network file!")
end
end
end
end
end
meseportals.registerPortal = function(player_name,pos,dir)
if meseportals.findPortal(pos) then
--An annoying glitch
meseportals.unregisterPortal(pos)
end
if meseportals_network[player_name]==nil then
meseportals_network[player_name]={}
end
local new_portal ={}
new_portal["pos"]=pos
new_portal["type"]="public"
new_portal["description"]="Portal at (" ..new_portal["pos"].x .."," ..new_portal["pos"].y .."," ..new_portal["pos"].z ..")"
new_portal["dir"]=dir
new_portal["owner"]=player_name
table.insert(meseportals_network[player_name],new_portal)
if meseportals.save_data(player_name)==nil then
print ("[meseportals] Couldnt update network file!")
end
end
meseportals.findPortal = function(pos)
if pos ~= nil then
for _,tab in pairs(meseportals.registered_players) do
local player_name=tab.player_name
for _,portals in pairs(meseportals_network[player_name]) do
if portals
and vector.equals(portals.pos, pos) then
return portals
end
end
end
end
return nil
end

1
mod.conf Normal file
View File

@ -0,0 +1 @@
name = meseportals

4280
models/meseportal.obj Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,164 @@
# Blender v2.79 (sub 0) OBJ File: 'controller.blend'
# www.blender.org
o control_panel_Plane.002
v -0.351000 0.270000 0.476056
v -0.351000 -0.270000 0.476056
v -0.388572 0.298902 0.496045
v 0.388572 0.298902 0.496045
v -0.388572 -0.298902 0.496045
v 0.388572 -0.298902 0.496045
v -0.419801 0.322924 0.486703
v 0.419801 0.322924 0.486703
v -0.419801 -0.322924 0.486703
v 0.419801 -0.322924 0.486703
v -0.427885 0.329142 0.478620
v 0.427885 0.329142 0.478620
v -0.427885 -0.329143 0.478620
v 0.427885 -0.329143 0.478620
v -0.351000 0.270000 0.466722
v 0.351000 0.270000 0.466722
v -0.351000 -0.270000 0.466722
v 0.351000 -0.270000 0.466722
v -0.360401 0.277231 0.459573
v 0.360401 0.277231 0.459573
v -0.360401 -0.277231 0.459573
v 0.360401 -0.277232 0.459573
v -0.388572 0.298902 0.450244
v 0.388572 0.298902 0.450244
v -0.388572 -0.298902 0.450244
v 0.388572 -0.298902 0.450244
v -0.419801 0.322924 0.456074
v 0.419801 0.322924 0.456074
v -0.419801 -0.322924 0.456074
v 0.419801 -0.322924 0.456074
v -0.427885 0.329142 0.464158
v 0.427885 0.329142 0.464158
v -0.427885 -0.329143 0.464157
v 0.427885 -0.329143 0.464157
vt 0.892354 0.497145
vt 0.892324 0.102503
vt 0.379290 0.102541
vt 0.379319 0.497183
vt 0.357770 0.086684
vt 0.357802 0.513043
vt 0.913874 0.513002
vt 0.913842 0.086643
vt 0.358706 0.514199
vt 0.912971 0.514158
vt 0.912938 0.085487
vt 0.358673 0.085527
vt 0.353414 0.523967
vt 0.920746 0.523967
vt 0.918229 0.075719
vt 0.350898 0.075719
vt 0.350220 0.082578
vt 0.350255 0.517149
vt 0.921424 0.517108
vt 0.921389 0.082537
vt 0.504874 0.999888
vt 0.504874 0.611610
vt 0.000112 0.611610
vt 0.000112 0.999888
vt 0.871302 0.024079
vt 0.395517 0.024114
vt 0.376922 0.039689
vt 0.889899 0.039651
vt 0.407894 0.583827
vt 0.869900 0.583768
vt 0.876127 0.575572
vt 0.400342 0.575607
vt 0.863750 0.015859
vt 0.401744 0.015917
vt 0.284769 0.121626
vt 0.284796 0.478109
vt 0.292593 0.482882
vt 0.292565 0.116852
vt 0.986876 0.478060
vt 0.986849 0.121577
vt 0.979052 0.116803
vt 0.979080 0.482834
vt 0.312184 0.497187
vt 0.312155 0.102545
vt 0.959460 0.102499
vt 0.959490 0.497141
vt 0.894722 0.559997
vt 0.381745 0.560035
vt 0.333158 0.513043
vt 0.333125 0.086685
vt 0.938486 0.086642
vt 0.938519 0.513001
vt 0.915334 0.543678
vt 0.361131 0.543720
vt 0.356310 0.056008
vt 0.910513 0.055966
vt 0.920740 0.533870
vt 0.353409 0.533869
vt 0.350903 0.065816
vt 0.918235 0.065816
vt 0.340708 0.517150
vt 0.340672 0.082579
vt 0.930936 0.082536
vt 0.930972 0.517107
vn 0.0000 0.0000 -1.0000
vn -0.2866 0.0000 -0.9581
vn 0.2866 0.0000 -0.9581
vn 0.0000 0.3624 -0.9320
vn -0.0000 -0.3624 -0.9320
vn 0.0000 0.7926 -0.6097
vn -0.0000 -0.7926 -0.6097
vn -0.7071 0.0000 -0.7071
vn 0.7071 0.0000 -0.7071
vn 0.0000 0.0000 1.0000
vn 0.0000 0.3954 0.9185
vn -0.0000 -0.7030 0.7112
vn 0.0000 0.7030 0.7112
vn 0.6053 -0.0000 0.7960
vn -0.6053 0.0000 0.7960
vn 0.3144 -0.0000 0.9493
vn -0.3144 -0.0000 0.9493
vn -0.0000 -0.3954 0.9185
vn -0.1835 -0.0000 0.9830
vn 0.1835 -0.0000 0.9830
vn 0.0000 0.2358 0.9718
vn -0.0000 -0.2358 0.9718
vn 0.0000 0.7926 0.6097
vn -0.0000 -0.7926 0.6097
vn -0.7071 -0.0000 0.7071
vn 0.7071 -0.0000 0.7071
vn 0.0000 1.0000 0.0000
vn -1.0000 0.0000 0.0000
vn 1.0000 0.0000 0.0000
vn -0.0000 -1.0000 0.0000
g control_panel_Plane.002_0001
s off
f 5/1/1 3/2/1 4/3/1 6/4/1
f 4/3/2 8/5/2 10/6/2 6/4/2
f 5/1/3 9/7/3 7/8/3 3/2/3
f 6/4/4 10/9/4 9/10/4 5/1/4
f 3/2/5 7/11/5 8/12/5 4/3/5
f 10/9/6 14/13/6 13/14/6 9/10/6
f 7/11/7 11/15/7 12/16/7 8/12/7
f 8/5/8 12/17/8 14/18/8 10/6/8
f 9/7/9 13/19/9 11/20/9 7/8/9
f 15/21/10 17/22/10 18/23/10 16/24/10
f 19/25/11 20/26/11 24/27/11 23/28/11
f 18/29/12 17/30/12 21/31/12 22/32/12
f 15/33/13 16/34/13 20/26/13 19/25/13
f 16/35/14 18/36/14 22/37/14 20/38/14
f 17/39/15 15/40/15 19/41/15 21/42/15
f 20/38/16 22/37/16 26/43/16 24/44/16
f 21/42/17 19/41/17 23/45/17 25/46/17
f 22/32/18 21/31/18 25/47/18 26/48/18
f 24/44/19 26/43/19 30/49/19 28/50/19
f 25/46/20 23/45/20 27/51/20 29/52/20
f 26/48/21 25/47/21 29/53/21 30/54/21
f 23/28/22 24/27/22 28/55/22 27/56/22
f 30/54/23 29/53/23 33/57/23 34/58/23
f 27/56/24 28/55/24 32/59/24 31/60/24
f 28/50/25 30/49/25 34/61/25 32/62/25
f 29/52/26 27/51/26 31/63/26 33/64/26
f 13/14/27 14/13/27 34/58/27 33/57/27
f 14/18/28 12/17/28 32/62/28 34/61/28
f 11/20/29 13/19/29 33/64/29 31/63/29
f 12/16/30 11/15/30 31/60/30 32/59/30
l 2 1

130
node_behaviors.lua Normal file
View File

@ -0,0 +1,130 @@
minetest.register_abm({
nodenames = {"meseportals:portal_collider"},
interval = 1,
chance = 1,
action = function(pos)
local portalpos = minetest.string_to_pos(minetest.get_meta(pos):get_string("portal"))
if portalpos then
local nodeName = minetest.get_node(portalpos).name
if nodeName ~= "ignore" then --If the portal is on the edge of the loaded world, wait to update
if nodeName ~= "meseportals:portalnode_on" and nodeName ~= "meseportals:portalnode_off" then
minetest.remove_node(pos)
end
end
end
end
})
minetest.register_abm({
nodenames = {"meseportals:portalnode_on", "meseportals:portalnode_off"},
interval = 1,
chance = 1,
action = function(pos)
local current_portal = meseportals.findPortal(pos)
if current_portal then
if current_portal["updateme"] then
if current_portal["destination"] == nil then
if minetest.get_node(pos).name ~= "meseportals:portalnode_off" then
minetest.sound_play("meseportal_close", {pos = pos, max_hear_distance = 72,})
end
meseportals.swap_portal_node(pos,"meseportals:portalnode_off",current_portal["dir"])
else
meseportals.swap_portal_node(pos,"meseportals:portalnode_on",current_portal["dir"])
minetest.sound_play("meseportal_open", {pos = pos, max_hear_distance = 72,})
end
current_portal["updateme"] = false
end
local meta = minetest.get_meta(pos)
if current_portal["type"]=="private" and meseportals.allowPrivatePortals then
infotext="Private Portal"
else
infotext=(current_portal["description"])
if meseportals.allowPrivatePortals then
infotext=infotext.." (Public Portal)\n".."Owned by "..current_portal["owner"]
end
local dest_portal = meseportals.findPortal(current_portal["destination"])
if dest_portal then
if dest_portal["type"] == "public" or not meseportals.allowPrivatePortals then
infotext=infotext.."\nDestination: " ..current_portal["destination_description"] .." ("..current_portal["destination"].x..","..current_portal["destination"].y..","..current_portal["destination"].z..") "
else
infotext=infotext.."\nDestination: Private Portal"
end
end
end
meta:set_string("infotext",infotext)
end
end
})
minetest.register_globalstep(function(dtime)
for _, skip in pairs(meseportals_network) do
for __, portal in pairs(skip) do
if portal ~= nil then
local pos = portal["pos"]
local dest_portal=meseportals.findPortal(portal["destination"])
if dest_portal then
local pos1 = vector.new(dest_portal["pos"])
if dest_portal["destination"] then
for _,object in pairs(core.get_objects_inside_radius({x = pos.x, y = pos.y, z = pos.z}, 2)) do
local dir = portal.dir
local dir1 = portal.destination_dir
local hdiff = nil
if dir == 1
or dir == 3 then
if math.floor(object:get_pos().x + 0.5) == pos.x then
hdiff = (object:get_pos().z - pos.z)
end
else
if math.floor(object:get_pos().z + 0.5) == pos.z then
hdiff = (object:get_pos().x - pos.x)
end
end
if hdiff then
pos1.y = pos1.y + (object:get_pos().y - pos.y) + 0.2
local dest_angle = ((dir1 - 2) * -90)
if object:get_look_horizontal() then
dest_angle = (math.deg(object:get_look_yaw()) + 90) + ((dir1 - dir) * -90)
end
if dir == 1 or dir == 2 then
hdiff = -hdiff
end
--hdiff = -1
if dir1 == 0 then --ALL CORRECT
pos1.z = pos1.z-1.25
pos1.x = pos1.x - hdiff
elseif dir1 == 1 then
pos1.x = pos1.x-1.25
pos1.z = pos1.z + hdiff
elseif dir1 == 2 then
pos1.z=pos1.z+1.25
pos1.x = pos1.x + hdiff
elseif dir1 == 3 then
pos1.x = pos1.x+1.25
pos1.z = pos1.z - hdiff
end
object:moveto(pos1,false)
object:set_look_horizontal(math.rad(dest_angle))
if object:is_player() then
minetest.sound_play("meseportal_warp", {to_player=object:get_player_name(), gain=1.0, max_hear_distance=15})
end
minetest.sound_play("meseportal_warp", {pos = pos, gain=1.0, max_hear_distance=15})
minetest.sound_play("meseportal_warp", {pos = pos1, gain=1.0, max_hear_distance=15})
end
end
end
else
if portal["destination"] then --Destination portal broke/vanished
meseportals.deactivatePortal(pos)
end
end
end
end
end
end)

416
portal_defs.lua Normal file
View File

@ -0,0 +1,416 @@
function meseportals.swap_portal_node(pos,name,dir)
local node = core.get_node(pos)
local meta = core.get_meta(pos)
meta:set_string("dont_destroy","true")
local meta0 = meta:to_table()
node.name = name
node.param2=dir
core.set_node(pos,{name=name, param2=dir})
meta:from_table(meta0)
meta:set_string("dont_destroy","false")
end
minetest.register_node("meseportals:portal_collider",{
drawtype = "airlike",
groups = {not_in_creative_inventory=1},
sunlight_propagates = true,
can_dig = false,
selection_box = {
type = "fixed",
fixed={0.0,0.0,0.0,0.0,0.0,0.0}},
})
function placeportalCollider(pos, pos1)
if minetest.get_node(pos).name == "air" or minetest.registered_nodes[minetest.get_node(pos).name].buildable_to then
core.set_node(pos,{name="meseportals:portal_collider"})
local meta = minetest.get_meta(pos)
meta:set_string("portal", minetest.pos_to_string(pos1))
return true
else
return false
end
end
local function placeportal(player,pos)
if minetest.check_player_privs(player, {msp_unlimited=true}) or meseportals.maxPlayerPortals > #meseportals_network[player:get_player_name()] then
local dir = minetest.dir_to_facedir(player:get_look_dir())
local pos1 = vector.new(pos)
local hadRoom = true
if dir == 1
or dir == 3 then
pos1.z=pos1.z+2
hadRoom = hadRoom and placeportalCollider(pos1, pos)
pos1.y=pos1.y+1
hadRoom = hadRoom and placeportalCollider(pos1, pos)
pos1.y=pos1.y+1
hadRoom = hadRoom and placeportalCollider(pos1, pos)
pos1.y=pos1.y+1
hadRoom = hadRoom and placeportalCollider(pos1, pos)
pos1.z=pos1.z-1
hadRoom = hadRoom and placeportalCollider(pos1, pos)
pos1.z=pos1.z-1
hadRoom = hadRoom and placeportalCollider(pos1, pos)
pos1.z=pos1.z-1
hadRoom = hadRoom and placeportalCollider(pos1, pos)
pos1.z=pos1.z-1
hadRoom = hadRoom and placeportalCollider(pos1, pos)
pos1.y=pos1.y-1
hadRoom = hadRoom and placeportalCollider(pos1, pos)
pos1.y=pos1.y-1
hadRoom = hadRoom and placeportalCollider(pos1, pos)
pos1.y=pos1.y-1
hadRoom = hadRoom and placeportalCollider(pos1, pos)
pos1.y=pos1.y-1
placeportalCollider(pos1, pos)
pos1.z=pos1.z+1
placeportalCollider(pos1, pos)
pos1.z=pos1.z+1
placeportalCollider(pos1, pos)
pos1.z=pos1.z+1
placeportalCollider(pos1, pos)
pos1.z=pos1.z+1
placeportalCollider(pos1, pos)
else
pos1.x=pos1.x+2
hadRoom = hadRoom and placeportalCollider(pos1, pos)
pos1.y=pos1.y+1
hadRoom = hadRoom and placeportalCollider(pos1, pos)
pos1.y=pos1.y+1
hadRoom = hadRoom and placeportalCollider(pos1, pos)
pos1.y=pos1.y+1
hadRoom = hadRoom and placeportalCollider(pos1, pos)
pos1.x=pos1.x-1
hadRoom = hadRoom and placeportalCollider(pos1, pos)
pos1.x=pos1.x-1
hadRoom = hadRoom and placeportalCollider(pos1, pos)
pos1.x=pos1.x-1
hadRoom = hadRoom and placeportalCollider(pos1, pos)
pos1.x=pos1.x-1
hadRoom = hadRoom and placeportalCollider(pos1, pos)
pos1.y=pos1.y-1
hadRoom = hadRoom and placeportalCollider(pos1, pos)
pos1.y=pos1.y-1
hadRoom = hadRoom and placeportalCollider(pos1, pos)
pos1.y=pos1.y-1
hadRoom = hadRoom and placeportalCollider(pos1, pos)
pos1.y=pos1.y-1
placeportalCollider(pos1, pos)
pos1.x=pos1.x+1
placeportalCollider(pos1, pos)
pos1.x=pos1.x+1
placeportalCollider(pos1, pos)
pos1.x=pos1.x+1
placeportalCollider(pos1, pos)
pos1.x=pos1.x+1
placeportalCollider(pos1, pos)
end
if hadRoom then
meseportals.swap_portal_node(pos,"meseportals:portalnode_off",dir)
local player_name = player:get_player_name()
meseportals.registerPortal(player_name, pos, dir)
return true
else
minetest.remove_node(pos)
minetest.chat_send_player(player:get_player_name(), "Not enough room!")
end
else
minetest.chat_send_player(player:get_player_name(), "You have reached the maximum allowed number of portals!")
core.remove_node(pos)
end
end
function meseportals.activatePortal(pos)
local portal = meseportals.findPortal(pos)
if meseportals.findPortal(pos) then
portal["updateme"] = true
meseportals.save_data(portal["owner"])
end
end
function meseportals.deactivatePortal(pos)
local portal = meseportals.findPortal(pos)
if portal then
portal["destination"] = nil
portal["destination_description"] = nil
portal["destination_dir"] = nil
portal["updateme"] = true
meseportals.save_data(portal["owner"])
end
end
local function removeportal(pos)
if (meseportals.findPortal(pos) ~= nil) then
local meta = core.get_meta(pos)
if meta:get_string("dont_destroy") == "true" then
-- when swapping it
return
end
if meseportals.findPortal(pos)["destination"] then
meseportals.deactivatePortal(meseportals.findPortal(pos)["destination"])
end
meseportals.unregisterPortal(pos)
minetest.add_item(pos, {name="meseportals:portalnode_off", count=1, wear=0, metadata=""})
end
end
local function portalCanDig(pos, player)
local isAdmin = minetest.check_player_privs(player, {msp_admin=true})
if meseportals.allowPrivatePortals and meseportals.findPortal(pos) ~= nil and not isAdmin then --Anyone can clean up a busted portal
if player:get_player_name() ~= meseportals.findPortal(pos)["owner"] then
minetest.chat_send_player(player:get_player_name(), "This portal belongs to " ..meseportals.findPortal(pos)["owner"] .."!")
end
return player:get_player_name() == meseportals.findPortal(pos)["owner"]
else
return true
end
end
local msp_selection_box = {
type = "fixed",
fixed={{-2.5,-1.5,-0.2,2.5,3.5,0.2},},
}
local msp_groups = {dig_immediate=3,oddly_breakable_by_hand=1,not_in_creative_inventory=1}
local msp_groups1 = {dig_immediate=3,oddly_breakable_by_hand=1}
minetest.register_node("meseportals:portalnode_on",{
tiles = {
--{name = "gray.png"},
--{
--name = "puddle_animated.png",
--animation = {
-- type = "vertical_frames",
-- aspect_w = 16,
-- aspect_h = 16,
-- length = 2.0,
-- },
--},
{name = "meseportal_0004.png",--Portal
animation = {
type = "vertical_frames",
length = 1.0,
},
},
{name = "meseportal_0003.png", --Buttons
animation = {
type = "vertical_frames",
},
},
{name = "meseportal_0003.png", --Cables
animation = {
type = "vertical_frames",
},
},
{name = "meseportal_0003.png", --Coil
animation = {
type = "vertical_frames",
},
},
{name = "meseportal_0001.png"}, --Frame
},
drawtype = "mesh",
mesh = "meseportal.obj",
visual_scale = 5.0,
groups = msp_groups,
drop = {name="meseportals:portalnode_off", count=1, wear=0, metadata=""},
paramtype2 = "facedir",
paramtype = "light",
light_source = 5,
selection_box = msp_selection_box,
walkable = false,
can_dig = portalCanDig,
on_destruct = removeportal,
on_rightclick=meseportals.portalFormspecHandler,
})
minetest.register_node("meseportals:portalnode_off",{
description = "Mese Portal",
inventory_image = "meseportal.png",
wield_image = "meseportal.png",
tiles = {
{name = "meseportal_null.png"},
{name = "meseportal_0002.png"},
{name = "meseportal_0002.png"},
{name = "meseportal_0002.png"},
{name = "meseportal_0001.png"},
},
groups = msp_groups1,
paramtype2 = "facedir",
paramtype = "light",
drawtype = "mesh",
drop = {name="meseportals:portalnode_off", count=1, wear=0, metadata=""},
mesh = "meseportal.obj",
visual_scale = 5.0,
selection_box = msp_selection_box,
walkable = false,
can_dig = portalCanDig,
on_destruct = removeportal,
on_place = function(itemstack, placer, pointed_thing)
if not minetest.is_protected(pos, placer:get_player_name()) then
local pos = pointed_thing.above
local meta = minetest.get_meta(pos)
minetest.rotate_node(itemstack, placer, pointed_thing) --This handles creative inventory correctly. Aside from that, it's basically useless.
local node = minetest.get_node(pos)
node.param2 = minetest.dir_to_facedir(placer:get_look_dir())
meta:set_string("dont_destroy","true")
minetest.set_node(pos, node)
meta:set_string("dont_destroy","false")
placeportal(placer,pos)
return itemstack
end
end,
on_rightclick=meseportals.portalFormspecHandler,
})
local usePortalController = function(pos, clicker)
if meseportals.findPortal(pos) then
meseportals.portalFormspecHandler(pos, nil, clicker, nil)
else
minetest.chat_send_player(clicker:get_player_name(), "The linked portal was moved or destroyed. Link this controller to a new portal.")
end
end
minetest.register_node("meseportals:linked_portal_controller", {
description = "Linked Portal Controller",
inventory_image = "meseportal_controller_inventory.png",
wield_image = "meseportal_controller_inventory.png",
tiles = {{name = "meseportal_controller.png"}},
drawtype = "mesh",
paramtype = "light",
paramtype2 = "facedir",
mesh = "meseportal_controller.obj",
groups = msp_groups,
stack_max = 1,
walkable = true,
light_source = 5,
selection_box = {
type = "fixed",
fixed={{-0.425,-0.325,0.5,0.45,0.325,0.425},},
},
collision_box = {
type = "fixed",
fixed={{-0.425,-0.325,0.5,0.45,0.325,0.425},},
},
on_place = function(itemstack, placer, pointed_thing)
local rightClicked = minetest.get_node(pointed_thing.under).name
if rightClicked == "meseportals:portalnode_on" or rightClicked == "meseportals:portalnode_off" then
local portal = meseportals.findPortal(pointed_thing.under)
if portal then
if portal["type"] == "public" or placer:get_player_name() == portal["owner"] or minetest.check_player_privs(placer, {msp_admin=true}) or not meseportals.allowPrivatePortals then
minetest.chat_send_player(placer:get_player_name(), "Controller linked to "..portal["description"])
itemstack:get_meta():set_string("portal", minetest.pos_to_string(pointed_thing.under))
itemstack:get_meta():set_string("description", "Linked Portal Controller ["..portal["description"].."]")
return itemstack
else
minetest.chat_send_player(placer:get_player_name(), portal["owner"] .." has set this portal to private.")
end
else
minetest.chat_send_player(placer:get_player_name(), "This portal is broken.")
end
else
minetest.rotate_node(itemstack, placer, pointed_thing)
core.set_node(pointed_thing.above, {name=minetest.get_node(pointed_thing.above).name, param2=minetest.dir_to_facedir(placer:get_look_dir())})
local meta = minetest.get_meta(pointed_thing.above)
meta:set_string("portal", itemstack:get_meta():get_string("portal"))
return itemstack
end
end,
on_dig = function(pos, node, player)
minetest.add_item(pos, {name="meseportals:unlinked_portal_controller", count=1, wear=0, metadata=""})
minetest.remove_node(pos)
end,
on_use = function(itemstack, user)
local pos1 = minetest.string_to_pos(itemstack:get_meta():get_string("portal"))
usePortalController(pos1, user)
end,
on_rightclick = function(pos, node, clicker)
local pos1 = minetest.string_to_pos(minetest.get_meta(pos):get_string("portal"))
usePortalController(pos1, clicker)
end
})
minetest.register_node("meseportals:unlinked_portal_controller", {
description = "Unlinked Portal Controller",
inventory_image = "meseportal_controller_inventory_unlinked.png",
wield_image = "meseportal_controller_inventory_unlinked.png",
tiles = {{name = "meseportal_controller_unlinked.png"}},
drawtype = "mesh",
paramtype = "light",
paramtype2 = "facedir",
mesh = "meseportal_controller.obj",
groups = msp_groups1,
walkable = true,
selection_box = {
type = "fixed",
fixed={{-0.425,-0.325,0.5,0.45,0.325,0.425},},
},
collision_box = {
type = "fixed",
fixed={{-0.425,-0.325,0.5,0.45,0.325,0.425},},
},
on_place = function(itemstack, placer, pointed_thing)
local rightClicked = minetest.get_node(pointed_thing.under).name
if rightClicked == "meseportals:portalnode_on" or rightClicked == "meseportals:portalnode_off" then
local portal = meseportals.findPortal(pointed_thing.under)
if portal then
if portal["type"] == "public" or placer:get_player_name() == portal["owner"] or minetest.check_player_privs(placer, {msp_admin=true}) then
minetest.chat_send_player(placer:get_player_name(), "Controller linked to "..portal["description"])
local newItem = itemstack:take_item()
local inv = placer:get_inventory()
newItem:set_name("meseportals:linked_portal_controller")
newItem:get_meta():set_string("portal", minetest.pos_to_string(pointed_thing.under))
newItem:get_meta():set_string("description", "Linked Portal Controller ["..portal["description"].."]")
if inv:add_item("main", newItem):get_count() > 0 then --Not enough inventory space, drop on the ground
minetest.add_item(placer:get_pos(), newItem)
end
return itemstack
else
minetest.chat_send_player(placer:get_player_name(), portal["owner"] .." has set this portal to private.")
end
else
minetest.chat_send_player(placer:get_player_name(), "This portal is broken.")
end
else
minetest.rotate_node(itemstack, placer, pointed_thing)
core.set_node(pointed_thing.above, {name=minetest.get_node(pointed_thing.above).name, param2=minetest.dir_to_facedir(placer:get_look_dir())})
local meta = minetest.get_meta(pointed_thing.above)
meta:set_string("portal", itemstack:get_meta():get_string("portal"))
return itemstack
end
end,
on_dig = function(pos, node, player)
local meta = minetest.get_meta(pos)
local item = {name="meseportals:unlinked_portal_controller", count=1, wear=0, metadata=""}
minetest.add_item(pos, item)
minetest.remove_node(pos)
end,
on_use = function(_, user)
minetest.chat_send_player(user:get_player_name(), "This controller is not linked. Link this controller to a portal by right-clicking the portal.")
end,
on_rightclick = function(_, __, user)
minetest.chat_send_player(user:get_player_name(), "This controller is not linked. Link this controller to a portal by right-clicking the portal.")
end,
})
minetest.register_craftitem("meseportals:portal_segment", {
description = "Encased Mesenetic Field Coil",
inventory_image = "meseportal_portal_part.png",
wield_image = "meseportal_portal_part.png",
})
minetest.register_craftitem("meseportals:tesseract_crystal", {
description = "Tesseract Crystal",
inventory_image = "meseportal_tesseract.png",
wield_image = "meseportal_tesseract.png",
})

44
recipes.lua Normal file
View File

@ -0,0 +1,44 @@
local OB = "default:obsidian"
local MB = "default:mese_block"
local DI = "default:diamond"
local MC = "default:mese_crystal"
local GL = "default:obsidian_glass"
local LV = "bucket:bucket_lava"
local TC = "meseportals:tesseract_crystal"
local PS = "meseportals:portal_segment"
minetest.register_craft({
output = "meseportals:tesseract_crystal",
recipe = {
{DI, MB, DI},
{MB, OB, MB},
{DI, MB, DI},
}
})
minetest.register_craft({
output = "meseportals:portal_segment",
recipe = {
{OB, OB, OB},
{MB, LV, MB},
{OB, OB, OB},
}
})
minetest.register_craft({
output = "meseportals:portalnode_off",
recipe = {
{PS, TC, PS},
{TC, "", TC},
{PS, TC, PS},
}
})
minetest.register_craft({
output = "meseportals:unlinked_portal_controller",
recipe = {
{GL, GL, GL},
{GL, TC, GL},
{GL, GL, GL},
}
})

BIN
screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 647 KiB

BIN
sounds/click.ogg Normal file

Binary file not shown.

BIN
sounds/meseportal_close.ogg Normal file

Binary file not shown.

BIN
sounds/meseportal_open.ogg Normal file

Binary file not shown.

BIN
sounds/meseportal_warp.ogg Normal file

Binary file not shown.

BIN
sounds/paperflip2.ogg Normal file

Binary file not shown.

BIN
textures/meseportal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 937 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 521 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB