add void_chest particle switch, tweaks to void_chest: add misteres original animation, net-performance tweaks, staging meseportals, update git notes.
|
@ -1,19 +1,19 @@
|
|||
## Just some notes on how to properly use git.
|
||||
|
||||
add changes
|
||||
# add changes
|
||||
git add .
|
||||
|
||||
commit changes to branch
|
||||
# commit changes to branch
|
||||
git commit
|
||||
|
||||
push changes to repo
|
||||
# push changes to repo
|
||||
git push
|
||||
|
||||
Switch working branch in git:
|
||||
# Switch working branch in git:
|
||||
git checkout <branch-name>
|
||||
|
||||
merges changes from master into current working branch.
|
||||
git merge master
|
||||
# merge changes from "testing" branch into current working branch.
|
||||
git merge testing
|
||||
|
||||
updates local files from git
|
||||
# updates local files from git
|
||||
git pull
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
void_chest = {
|
||||
show_particles = (minetest.settings:get("void_chest.show_particles") ~= "false")
|
||||
}
|
||||
|
||||
-- Register the void chest.
|
||||
minetest.register_node("void_chest:void_chest", {
|
||||
description = "" ..core.colorize("#660099","Void Chest\n") ..core.colorize("#FFFFFF", "Use the power of the void to store your items."),
|
||||
|
@ -8,8 +12,10 @@ minetest.register_node("void_chest:void_chest", {
|
|||
legacy_facedir_simple = true,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
on_construct = function(pos)
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:start(.1) -- in seconds
|
||||
if void_chest.show_particles then
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:start(.1) -- in seconds
|
||||
end
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("formspec",
|
||||
"size[8,9]"..
|
||||
|
@ -38,32 +44,39 @@ minetest.register_node("void_chest:void_chest", {
|
|||
" takes stuff from void chest at "..minetest.pos_to_string(pos))
|
||||
end,
|
||||
on_timer = function(pos)
|
||||
-- Particles for the void effect, implemented by MisterE, thanks!
|
||||
for i=1,10 do -- number of particles spawned every on_timer
|
||||
local vel_scalar = math.random(0,5)/10 -- multiplied by the particle's velocity vector of 1
|
||||
local accel_scalar = math.random(1,5)/10 -- multiplied by the particle's accel vector of 1
|
||||
local expir = math.random(1,10) -- number of sec particle will last, if it doesn't hit a node
|
||||
local particle_pos = {x=pos.x + ((math.random(-10,10)/10)*(math.random(6,15)/10)), y=pos.y + ((math.random(-10,10)/10)*(math.random(6,15)/10)), z=pos.z+ ((math.random(-10,10)/10)*(math.random(6,15)/10))}
|
||||
local part_vel = vector.direction(particle_pos, pos)
|
||||
part_vel = {x= vel_scalar*part_vel.x, y= vel_scalar*part_vel.y, z= vel_scalar*part_vel.z}
|
||||
local part_accel = vector.direction(particle_pos, pos)
|
||||
part_accel = {x= accel_scalar*part_accel.x, y= accel_scalar*part_accel.y, z= accel_scalar*part_accel.z}
|
||||
minetest.add_particle({
|
||||
pos = particle_pos,
|
||||
velocity = part_vel,
|
||||
acceleration = part_accel,
|
||||
expirationtime = expir,
|
||||
size = math.random(7,10)/10,
|
||||
collisiondetection = true,
|
||||
collision_removal = true,
|
||||
vertical = false,
|
||||
texture = "void_chest_void_particle.png",
|
||||
glow = 5,
|
||||
})
|
||||
if void_chest.show_particles then
|
||||
-- Particles for the void effect, implemented by MisterE, thanks!
|
||||
for i=1,2 do -- number of particles spawned every on_timer
|
||||
local spin_speed = math.random(80,175)/1000 --controls how fast a particular particle spins
|
||||
local vel_scalar = math.random(0,5)/10 -- multiplied by the particle's velocity vector of 1
|
||||
local accel_scalar = math.random(1,5)/10 -- multiplied by the particle's accel vector of 1
|
||||
local expir = math.random(1,5) -- number of sec particle will last, if it doesn't hit a node
|
||||
local particle_pos = {x=pos.x + ((math.random(-15,15)/10)*(math.random(6,15)/10)), y=pos.y + ((math.random(-15,15)/10)*(math.random(6,15)/10)), z=pos.z+ ((math.random(-15,15)/10)*(math.random(6,15)/10))}
|
||||
local part_vel = vector.direction(particle_pos, pos)
|
||||
part_vel = {x= vel_scalar*part_vel.x, y= vel_scalar*part_vel.y, z= vel_scalar*part_vel.z}
|
||||
local part_accel = vector.direction(particle_pos, pos)
|
||||
part_accel = {x= accel_scalar*part_accel.x, y= accel_scalar*part_accel.y, z= accel_scalar*part_accel.z}
|
||||
minetest.add_particle({
|
||||
pos = particle_pos,
|
||||
velocity = part_vel,
|
||||
acceleration = part_accel,
|
||||
expirationtime = expir,
|
||||
size = math.random(5,15)/10,
|
||||
collisiondetection = true,
|
||||
collision_removal = true,
|
||||
vertical = false,
|
||||
texture = "void_chest_void_particle.png",
|
||||
animation = {
|
||||
type = "vertical_frames",
|
||||
aspect_w = 16,
|
||||
aspect_h = 16,
|
||||
length = spin_speed,
|
||||
},
|
||||
glow = 5,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return true
|
||||
return true
|
||||
end,
|
||||
|
||||
})
|
||||
|
@ -80,7 +93,7 @@ if minetest.get_modpath("magic_materials") then
|
|||
}
|
||||
})
|
||||
else -- Else we use a recipe using "default" to avoid a hard dependency.
|
||||
minetest.register_craft({
|
||||
minetest.register_craft({
|
||||
output = 'void_chest:void_chest',
|
||||
recipe = {
|
||||
{'default:steelblock','default:obsidian_block','default:steelblock'},
|
||||
|
@ -94,3 +107,4 @@ minetest.register_on_joinplayer(function(player)
|
|||
local inv = player:get_inventory()
|
||||
inv:set_size("void_chest:void_chest", 8*4)
|
||||
end)
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
# VOID CHEST SETTINGS
|
||||
|
||||
# VOID CHEST:
|
||||
# on low performance servers the particles can cause a drop in performance.
|
||||
|
||||
# Default: true
|
||||
void_chest.show_particles (Show Particles) bool true
|
||||
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 4.2 KiB |
|
@ -0,0 +1,20 @@
|
|||
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
|
||||
Added search bar, and formspec security measures.
|
||||
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.
|
||||
Portals and all associated nodes are now fully protection-aware.
|
||||
Reorganized/Split up files
|
||||
Position and rotation relative to the portal are now maintained, making travel feel smoother.
|
||||
|
||||
Changes by SpaghettiToastBook:
|
||||
Added meseportals.can_connect
|
|
@ -0,0 +1,39 @@
|
|||
Media:
|
||||
Portal, item, and controller textures: CC BY-SA (4.0) by Piezo_
|
||||
textures/meseportal_adminlock.png: CC BY-SA (4.0) by Piezo_
|
||||
Other GUI Elements: See <https://github.com/minetest-mods/unified_inventory/blob/master/README.md>
|
||||
Models: CC BY-SA (4.0) by Piezo_
|
||||
Sounds:
|
||||
Portal noises (meseportal_open, meseportal_close): CC BY-SA (4.0) by Piezo_
|
||||
Portal noise (meseportal_warp) is a distorted versin of default_water_footstep.2.ogg from minetest_game
|
||||
GUI sounds: (click and paperflip2.ogg) See <https://github.com/minetest-mods/unified_inventory/blob/master/README.md>
|
||||
|
||||
Source code:
|
||||
|
||||
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.
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
default
|
||||
bucket
|
|
@ -0,0 +1 @@
|
|||
A futuristic multiplayer transportation system built on RealBadAngel's mod for Minetest.
|
|
@ -0,0 +1,30 @@
|
|||
--data tables definitions
|
||||
meseportals={}
|
||||
meseportals_network = {}
|
||||
meseportals_gui = {}
|
||||
|
||||
meseportals.allowPrivatePortals = true
|
||||
meseportals.maxPlayerPortals = 14 -- Set to 0 or lower to restrict portal placement to only players with msp_unlimited privilege
|
||||
meseportals.close_after = 240 -- Automatically close portals after a while (default: 4 min)
|
||||
|
||||
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")
|
|
@ -0,0 +1,474 @@
|
|||
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 __,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
|
||||
--current_portal=portals
|
||||
else
|
||||
own_portals_count=own_portals_count+1
|
||||
if string.find(portal["description"], meseportals_gui["players"][player_name]["query"]) then
|
||||
table.insert(meseportals_gui["players"][player_name]["own_portals"],portal)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- get all public portals
|
||||
for __,tab in ipairs(meseportals["registered_players"]) do
|
||||
local temp=tab["player_name"]
|
||||
for __,portal in ipairs(meseportals_network[temp]) do
|
||||
if string.find(portal["description"], meseportals_gui["players"][player_name]["query"]) then
|
||||
if portal["type"]=="public" or portal["owner"] == player_name or isAdmin or not meseportals.allowPrivatePortals then
|
||||
if portal["pos"].x==pos.x and portal["pos"].y==pos.y and portal["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"],portal)
|
||||
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
|
||||
|
||||
-- Mods can override this to restict portal connections.
|
||||
-- Admins ignore this.
|
||||
meseportals.can_connect = function(src_portal, dest_portal)
|
||||
return dest_portal["destination"] == nil, "Destination portal is busy."
|
||||
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.ceil(list_index / 24)
|
||||
local pagemax
|
||||
if meseportals_gui["players"][player_name]["dest_type"] == "own" then
|
||||
pagemax = math.ceil((meseportals_gui["players"][player_name]["own_portals_count"] / 24))
|
||||
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.ceil(meseportals_gui["players"][player_name]["public_portals_count"] / 24)
|
||||
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: "..((pagemax > 0) and (page + 1) or 0).." 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;]"
|
||||
if isAdmin then formspec = formspec.."image_button_exit[5.1,9.3;.8,.8;meseportal_adminlock.png;lock_and_save;]" end
|
||||
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"]
|
||||
if not temp_portal then return end
|
||||
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"] and temp_portal["type"] == "private" and not isAdmin) and meseportals.allowPrivatePortals then
|
||||
reportFormspecViolation(player_name, "accessed someone else's private portal!")
|
||||
return
|
||||
end
|
||||
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.ceil((meseportals_gui["players"][player_name]["own_portals_count"]) / 24)
|
||||
else
|
||||
pagemax = math.ceil((meseportals_gui["players"][player_name]["public_portals_count"]) / 24)
|
||||
end
|
||||
if pagemax == 0 then pagemax = 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.discard_changes then
|
||||
minetest.sound_play("click", {to_player=player_name, gain = 0.5})
|
||||
end
|
||||
|
||||
if current_portal.admin_lock and not isAdmin then
|
||||
minetest.chat_send_player(player_name, "This portal has been locked by an admin.")
|
||||
return
|
||||
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 or fields.lock_and_save then
|
||||
minetest.sound_play("click", {to_player=player_name, gain = 0.5})
|
||||
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
|
||||
if temp_portal["destination"] then
|
||||
local dest_portal = meseportals.findPortal(temp_portal["destination"])
|
||||
if dest_portal then
|
||||
if isAdmin then
|
||||
current_portal.admin_lock = fields.lock_and_save
|
||||
dest_portal.admin_lock = fields.lock_and_save
|
||||
|
||||
elseif fields.lock_and_save then
|
||||
reportFormspecViolation(player_name, "attempted to admin-lock a portal while missing msp_admin privilege!")
|
||||
end
|
||||
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 destination portal seems to have vanished while you were 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 not temp_portal["destination"] then
|
||||
current_portal.admin_lock = nil
|
||||
end
|
||||
if meseportals.findPortal(current_portal["destination_deactivate"]) then
|
||||
meseportals.findPortal(current_portal["destination_deactivate"]).admin_lock = nil
|
||||
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"])
|
||||
local can_connect, fail_reason = meseportals.can_connect(table.copy(current_portal), table.copy(dest_portal))
|
||||
if can_connect or isAdmin then
|
||||
dest_portal.admin_lock = current_portal.admin_lock
|
||||
-- Connecting to a portal, its locked state becomes the same as this portal.
|
||||
if dest_portal["destination"] then --Admin can interrupt any 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)
|
||||
current_portal["time"] = meseportals.close_after
|
||||
else
|
||||
if fail_reason then
|
||||
minetest.chat_send_player(player_name, "Connection failed: " .. fail_reason)
|
||||
else
|
||||
minetest.chat_send_player(player_name, "Connection failed.")
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
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"]=vector.new(dest_portal["pos"])
|
||||
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)
|
|
@ -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
|
||||
|
|
@ -0,0 +1 @@
|
|||
name = meseportals
|
|
@ -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
|
|
@ -0,0 +1,182 @@
|
|||
|
||||
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 not current_portal then
|
||||
minetest.remove_node(pos)
|
||||
return
|
||||
end
|
||||
|
||||
end
|
||||
})
|
||||
|
||||
|
||||
minetest.register_globalstep(function(dtime)
|
||||
local meta, infotext, pos1, pos, dir, dir1, hdiff, dest_portal
|
||||
for _, skip in pairs(meseportals_network) do
|
||||
for __, portal in pairs(skip) do
|
||||
if portal then
|
||||
pos = portal["pos"]
|
||||
if portal["time"] and not portal["admin_lock"] then -- Close portals automatically after a while
|
||||
if portal["time"] > 0 then
|
||||
portal["time"] = portal["time"] - dtime
|
||||
else
|
||||
portal["time"] = nil
|
||||
if portal["destination"] then
|
||||
meseportals.deactivatePortal(portal["destination"])
|
||||
end
|
||||
meseportals.deactivatePortal(pos)
|
||||
end
|
||||
end
|
||||
|
||||
if minetest.get_node_or_nil(pos) then -- Do the complicated stuff only if the portal is loaded
|
||||
if minetest.get_node(pos).name ~= "meseportals:portalnode_off"
|
||||
and minetest.get_node(pos).name ~= "meseportals:portalnode_on"
|
||||
then --Portal broke
|
||||
if portal["destination"] then
|
||||
meseportals.deactivatePortal(portal["destination"])
|
||||
end
|
||||
meseportals.unregisterPortal(pos)
|
||||
elseif portal["updateme"] then -- Node needs to update
|
||||
if portal["destination"] == nil then
|
||||
if minetest.get_node(pos).name ~= "meseportals:portalnode_off" then
|
||||
minetest.sound_play("meseportal_close", {pos = pos, gain=0.6, max_hear_distance = 40})
|
||||
end
|
||||
meseportals.swap_portal_node(pos,"meseportals:portalnode_off",portal["dir"])
|
||||
else
|
||||
meseportals.swap_portal_node(pos,"meseportals:portalnode_on",portal["dir"])
|
||||
minetest.sound_play("meseportal_open", {pos = pos, gain=0.6, max_hear_distance = 40})
|
||||
end
|
||||
portal["updateme"] = false
|
||||
meseportals.save_data(portal["owner"])
|
||||
meta = minetest.get_meta(pos)
|
||||
if portal["type"]=="private" and meseportals.allowPrivatePortals then
|
||||
infotext="Private Portal"
|
||||
else
|
||||
infotext=(portal["description"])
|
||||
if meseportals.allowPrivatePortals then
|
||||
infotext=infotext.." ("..portal["owner"].."'s Public Portal)"
|
||||
end
|
||||
dest_portal = meseportals.findPortal(portal["destination"])
|
||||
if dest_portal then
|
||||
if dest_portal["type"] == "public" or not meseportals.allowPrivatePortals then
|
||||
infotext=infotext.."\nDestination: " ..portal["destination_description"] .." ("..portal["destination"].x..","..portal["destination"].y..","..portal["destination"].z..") "
|
||||
else
|
||||
infotext=infotext.."\nDestination: Private Portal"
|
||||
end
|
||||
end
|
||||
end
|
||||
if portal.admin_lock then
|
||||
infotext=infotext.."\nAdmin connection (Can not be closed)"
|
||||
end
|
||||
meta:set_string("infotext",infotext)
|
||||
end
|
||||
|
||||
--Teleport players
|
||||
dest_portal=meseportals.findPortal(portal["destination"])
|
||||
if dest_portal then
|
||||
pos1 = vector.new(dest_portal["pos"])
|
||||
dir = portal.dir
|
||||
dir1 = portal.destination_dir
|
||||
for _,object in pairs(core.get_objects_inside_radius({x = pos.x, y = pos.y, z = pos.z}, 2)) do
|
||||
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)
|
||||
|
||||
dest_angle = ((object:get_look_horizontal() or object:get_yaw()) + math.pi) + ((dir1 - dir) * -(math.pi/2))
|
||||
|
||||
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
|
||||
local vel = object:get_velocity() or object:get_player_velocity()
|
||||
vel.x = -vel.x
|
||||
local magnitude = math.sqrt((vel.x*vel.x) + (vel.z*vel.z))
|
||||
if math.abs(vel.z) < 0.01 then
|
||||
vel.z = 0.01
|
||||
end
|
||||
local direction = math.atan(vel.x/vel.z)
|
||||
-- Direction of velocity plus the change in look direction
|
||||
if vel.z < 0 then
|
||||
direction = direction + math.pi
|
||||
end
|
||||
direction = direction + math.pi + ((dir1 - dir) * -(math.pi/2))
|
||||
vel.x = magnitude * -math.sin(direction)
|
||||
vel.z = magnitude * math.cos(direction)
|
||||
local moved = false
|
||||
if object:is_player() then
|
||||
object:set_pos(pos1)
|
||||
if vector.equals(vector.round(object:get_pos()), vector.round(pos1)) then moved = true end
|
||||
elseif object:get_properties().physical == true then
|
||||
object:set_pos(pos1)
|
||||
moved = true
|
||||
end
|
||||
if moved then
|
||||
if object:is_player() then
|
||||
--player:set_player_velocity(vel) -- TODO: Bother the devs more about this
|
||||
object:set_look_horizontal(dest_angle)
|
||||
minetest.sound_play("meseportal_warp", {to_player=object:get_player_name(), gain=0.6, max_hear_distance=15})
|
||||
else
|
||||
object:set_velocity(vel)
|
||||
object:set_yaw(dest_angle)
|
||||
end
|
||||
minetest.sound_play("meseportal_warp", {pos = pos, gain=0.6, max_hear_distance=15})
|
||||
minetest.sound_play("meseportal_warp", {pos = pos1, gain=0.6, 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
|
||||
end)
|
|
@ -0,0 +1,469 @@
|
|||
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",
|
||||
on_blast = function() end,
|
||||
drop = "",
|
||||
groups = {not_in_creative_inventory=1,immovable=2},
|
||||
sunlight_propagates = true,
|
||||
can_dig = false,
|
||||
paramtype = "light",
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
fixed={0.0,0.0,0.0,0.0,0.0,0.0}},
|
||||
})
|
||||
|
||||
|
||||
function placeportalCollider(pos, pos1, player)
|
||||
local placed = false
|
||||
if minetest.check_player_privs(player, {protection_bypass=true}) or not minetest.is_protected(pos, player:get_player_name()) then
|
||||
if minetest.registered_nodes[minetest.get_node(pos).name] then
|
||||
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))
|
||||
placed = true
|
||||
end
|
||||
end
|
||||
end
|
||||
return placed
|
||||
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, player)
|
||||
pos1.y=pos1.y+1
|
||||
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
|
||||
pos1.y=pos1.y+1
|
||||
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
|
||||
pos1.y=pos1.y+1
|
||||
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
|
||||
pos1.z=pos1.z-1
|
||||
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
|
||||
pos1.z=pos1.z-1
|
||||
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
|
||||
pos1.z=pos1.z-1
|
||||
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
|
||||
pos1.z=pos1.z-1
|
||||
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
|
||||
pos1.y=pos1.y-1
|
||||
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
|
||||
pos1.y=pos1.y-1
|
||||
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
|
||||
pos1.y=pos1.y-1
|
||||
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
|
||||
pos1.y=pos1.y-1
|
||||
placeportalCollider(pos1, pos, player)
|
||||
pos1.z=pos1.z+1
|
||||
placeportalCollider(pos1, pos, player)
|
||||
pos1.z=pos1.z+1
|
||||
placeportalCollider(pos1, pos, player)
|
||||
pos1.z=pos1.z+1
|
||||
placeportalCollider(pos1, pos, player)
|
||||
pos1.z=pos1.z+1
|
||||
placeportalCollider(pos1, pos, player)
|
||||
else
|
||||
pos1.x=pos1.x+2
|
||||
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
|
||||
pos1.y=pos1.y+1
|
||||
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
|
||||
pos1.y=pos1.y+1
|
||||
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
|
||||
pos1.y=pos1.y+1
|
||||
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
|
||||
pos1.x=pos1.x-1
|
||||
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
|
||||
pos1.x=pos1.x-1
|
||||
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
|
||||
pos1.x=pos1.x-1
|
||||
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
|
||||
pos1.x=pos1.x-1
|
||||
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
|
||||
pos1.y=pos1.y-1
|
||||
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
|
||||
pos1.y=pos1.y-1
|
||||
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
|
||||
pos1.y=pos1.y-1
|
||||
hadRoom = hadRoom and placeportalCollider(pos1, pos, player)
|
||||
pos1.y=pos1.y-1
|
||||
placeportalCollider(pos1, pos, player)
|
||||
pos1.x=pos1.x+1
|
||||
placeportalCollider(pos1, pos, player)
|
||||
pos1.x=pos1.x+1
|
||||
placeportalCollider(pos1, pos, player)
|
||||
pos1.x=pos1.x+1
|
||||
placeportalCollider(pos1, pos, player)
|
||||
pos1.x=pos1.x+1
|
||||
placeportalCollider(pos1, pos, player)
|
||||
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)
|
||||
end
|
||||
end
|
||||
|
||||
local msp_selection_box = {
|
||||
type = "fixed",
|
||||
fixed={{-2.5,-1.5,-0.2,2.5,3.5,0.2},},
|
||||
}
|
||||
|
||||
local msp_groups = {cracky=2,not_in_creative_inventory=1,immovable=2}
|
||||
local msp_groups1 = {cracky=2,immovabl=2}
|
||||
|
||||
|
||||
local old_pttfp = minetest.pointed_thing_to_face_pos
|
||||
minetest.pointed_thing_to_face_pos = function(placer, pointed_thing)
|
||||
if pointed_thing and placer and pointed_thing.above and pointed_thing.under then
|
||||
if pointed_thing.under.x == pointed_thing.above.x and pointed_thing.under.y == pointed_thing.above.y and pointed_thing.under.z == pointed_thing.above.z then
|
||||
return placer:get_pos()
|
||||
else
|
||||
return old_pttfp(placer, pointed_thing)
|
||||
end
|
||||
else
|
||||
return vector.new(0,0,0)
|
||||
end
|
||||
end
|
||||
|
||||
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_vortex.png",--Portal
|
||||
animation = {
|
||||
type = "vertical_frames",
|
||||
},
|
||||
},
|
||||
{name = "meseportal_mese_on.png", --Buttons
|
||||
animation = {
|
||||
type = "vertical_frames",
|
||||
},
|
||||
},
|
||||
{name = "meseportal_mese_on.png", --Cables
|
||||
animation = {
|
||||
type = "vertical_frames",
|
||||
},
|
||||
},
|
||||
{name = "meseportal_mese_on.png", --Coil
|
||||
animation = {
|
||||
type = "vertical_frames",
|
||||
},
|
||||
},
|
||||
{name = "meseportal_frame.png"}, --Frame
|
||||
},
|
||||
drawtype = "mesh",
|
||||
mesh = "meseportal.obj",
|
||||
visual_scale = 5.0,
|
||||
groups = msp_groups,
|
||||
drop = "meseportals:portalnode_off",
|
||||
paramtype2 = "facedir",
|
||||
paramtype = "light",
|
||||
light_source = 5,
|
||||
selection_box = msp_selection_box,
|
||||
walkable = false,
|
||||
on_destruct = removeportal,
|
||||
on_rightclick=meseportals.portalFormspecHandler,
|
||||
})
|
||||
|
||||
minetest.register_node("meseportals:portalnode_off",{
|
||||
description = "Mese Portal (Sneak+Place = Buried)",
|
||||
inventory_image = "meseportal.png",
|
||||
wield_image = "meseportal.png",
|
||||
tiles = {
|
||||
{name = "meseportal_null.png"},
|
||||
{name = "meseportal_mese_off.png"},
|
||||
{name = "meseportal_mese_off.png"},
|
||||
{name = "meseportal_mese_off.png"},
|
||||
{name = "meseportal_frame.png"},
|
||||
},
|
||||
groups = msp_groups1,
|
||||
paramtype2 = "facedir",
|
||||
paramtype = "light",
|
||||
drawtype = "mesh",
|
||||
drop = "meseportals:portalnode_off",
|
||||
mesh = "meseportal.obj",
|
||||
visual_scale = 5.0,
|
||||
selection_box = msp_selection_box,
|
||||
walkable = false,
|
||||
on_destruct = removeportal,
|
||||
on_place = function(itemstack, placer, pointed_thing)
|
||||
|
||||
local pos = pointed_thing.above
|
||||
if minetest.registered_nodes[minetest.get_node(pointed_thing.under).name] then
|
||||
if minetest.registered_nodes[minetest.get_node(pointed_thing.under).name].on_rightclick and not placer:get_player_control().sneak then
|
||||
return minetest.registered_nodes[minetest.get_node(pointed_thing.under).name].on_rightclick(pointed_thing.under, minetest.get_node(pointed_thing.under), placer, itemstack, pointed_thing)
|
||||
end
|
||||
if minetest.registered_nodes[minetest.get_node(pointed_thing.under).name].buildable_to then
|
||||
pos = pointed_thing.under
|
||||
end
|
||||
end
|
||||
if minetest.check_player_privs(placer, {protection_bypass=true}) or not minetest.is_protected(pos, placer:get_player_name()) then
|
||||
minetest.item_place(itemstack, placer, pointed_thing, minetest.dir_to_facedir(placer:get_look_dir()))
|
||||
local node = minetest.get_node(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
if placer:get_player_control().sneak then
|
||||
minetest.set_node(pos, node)
|
||||
else
|
||||
minetest.remove_node(pos)
|
||||
pos.y = pos.y + 1
|
||||
minetest.set_node(pos, node)
|
||||
end
|
||||
if placeportal(placer,pos) then
|
||||
return itemstack
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
end,
|
||||
on_rightclick=meseportals.portalFormspecHandler,
|
||||
})
|
||||
|
||||
local old_protected = minetest.is_protected
|
||||
|
||||
local basecheck = { --f = face (x or z axis)
|
||||
{x=0, z=0, f=0},
|
||||
{x=1, z=0, f=1},
|
||||
{x=2, z=0, f=1},
|
||||
{x=-1, z=0, f=1},
|
||||
{x=-2, z=0, f=1},
|
||||
{x=0, z=1, f=2},
|
||||
{x=0, z=2, f=2},
|
||||
{x=0, z=-1, f=2},
|
||||
{x=0, z=-2, f=2},
|
||||
}
|
||||
minetest.is_protected = function(pos, player, ...) --Protect the bottom of the portal
|
||||
if not pos then return end
|
||||
local pos1 = vector.new(pos.x, pos.y + 1, pos.z) --Allocate
|
||||
local portal
|
||||
for _,pos2 in pairs(basecheck) do
|
||||
pos1.x = pos.x + pos2.x
|
||||
pos1.z = pos.z + pos2.z
|
||||
portal = meseportals.findPortal(pos1)
|
||||
if portal then
|
||||
if pos2.f == 0 then return true end --Right under
|
||||
if (pos2.f == 1) == (portal.dir == 0 or portal.dir == 2) then --Adjacent, XNOR with facedir
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
portal = meseportals.findPortal(pos)
|
||||
if portal and not minetest.check_player_privs(player, {msp_admin=true}) then
|
||||
if portal.owner ~= player then
|
||||
minetest.chat_send_player(player, "This portal belongs to " ..portal["owner"] .."!")
|
||||
return true
|
||||
end
|
||||
if portal.admin_lock then
|
||||
minetest.chat_send_player(player, "This portal has been locked by an admin.")
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return old_protected(pos, player, ...)
|
||||
end
|
||||
|
||||
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",
|
||||
drop = "meseportals:unlinked_portal_controller",
|
||||
groups = {cracky=3,oddly_breakable_by_hand=2,not_in_creative_inventory=1},
|
||||
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)
|
||||
if minetest.check_player_privs(placer, {protection_bypass=true}) or not minetest.is_protected(pointed_thing.above, placer:get_player_name()) then
|
||||
local rightClicked = minetest.get_node(pointed_thing.under).name
|
||||
if not placer:get_player_control().sneak then
|
||||
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
|
||||
elseif minetest.registered_nodes[rightClicked] and minetest.registered_nodes[rightClicked].on_rightclick then
|
||||
return minetest.registered_nodes[rightClicked].on_rightclick(pointed_thing.under, minetest.get_node(pointed_thing.under), placer, itemstack, pointed_thing)
|
||||
end
|
||||
end
|
||||
local p
|
||||
if minetest.registered_nodes[minetest.get_node(pointed_thing.under).name] and minetest.registered_nodes[minetest.get_node(pointed_thing.under).name].buildable_to then
|
||||
p = pointed_thing.under
|
||||
else
|
||||
p = pointed_thing.above
|
||||
end
|
||||
local portalID = itemstack:get_meta():get_string("portal")
|
||||
minetest.item_place(itemstack, placer, pointed_thing, minetest.dir_to_facedir(placer:get_look_dir()))
|
||||
local meta = minetest.get_meta(p)
|
||||
meta:set_string("portal", portalID)
|
||||
return itemstack
|
||||
end
|
||||
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",
|
||||
drop = "meseportals:unlinked_portal_controller",
|
||||
groups = {cracky=3,oddly_breakable_by_hand=2},
|
||||
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 not placer:get_player_control().sneak then
|
||||
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"])
|
||||
itemstack:set_name("meseportals:linked_portal_controller")
|
||||
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.")
|
||||
return
|
||||
end
|
||||
else
|
||||
minetest.chat_send_player(placer:get_player_name(), "This portal is broken.")
|
||||
end
|
||||
elseif minetest.registered_nodes[rightClicked] and minetest.registered_nodes[rightClicked].on_rightclick then
|
||||
return minetest.registered_nodes[rightClicked].on_rightclick(pointed_thing.under, minetest.get_node(pointed_thing.under), placer, itemstack, pointed_thing)
|
||||
end
|
||||
end
|
||||
return minetest.item_place(itemstack, placer, pointed_thing, minetest.dir_to_facedir(placer:get_look_dir()))
|
||||
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",
|
||||
})
|
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 8.8 KiB |
After Width: | Height: | Size: 13 KiB |
|
@ -0,0 +1,46 @@
|
|||
local OB = "default:obsidian"
|
||||
local MC = "default:mese_crystal"
|
||||
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, MC, DI},
|
||||
{MC, OB, MC},
|
||||
{DI, MC, DI},
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "meseportals:portal_segment",
|
||||
recipe = {
|
||||
{OB, OB, OB},
|
||||
{MB, LV, MB},
|
||||
{OB, OB, OB},
|
||||
},
|
||||
replacements = {{"bucket:bucket_lava", "bucket:bucket_empty"}}
|
||||
})
|
||||
|
||||
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},
|
||||
}
|
||||
})
|
After Width: | Height: | Size: 132 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 82 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 937 B |
After Width: | Height: | Size: 52 KiB |
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 124 KiB |
After Width: | Height: | Size: 91 B |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 521 B |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 246 B |
After Width: | Height: | Size: 988 B |
After Width: | Height: | Size: 6.3 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 373 KiB |