244 lines
6.5 KiB
Lua
244 lines
6.5 KiB
Lua
--= Teleport Book (paper) mod by jaandrle
|
||
--! based on Teleport Potion mod by TenPlus1 (SFX are license free)
|
||
--
|
||
-- !!! Mainly tested inside LOTT game !!!
|
||
|
||
-- support for MT game translation.
|
||
local S = default.get_translator
|
||
|
||
-- max teleport distance
|
||
local dist = tonumber(minetest.settings:get("map_generation_limit") or 31000)
|
||
|
||
local function check_coordinates(str)
|
||
if not str or str == "" then
|
||
return nil
|
||
end
|
||
-- get coords from string
|
||
local x, y, z = string.match(str, "^(-?%d+),(-?%d+),(-?%d+)$")
|
||
-- check coords
|
||
if x == nil or string.len(x) > 6
|
||
or y == nil or string.len(y) > 6
|
||
or z == nil or string.len(z) > 6 then
|
||
return nil
|
||
end
|
||
-- convert string coords to numbers
|
||
x = tonumber(x)
|
||
y = tonumber(y)
|
||
z = tonumber(z)
|
||
-- are coords in map range ?
|
||
if x > dist or x < -dist
|
||
or y > dist or y < -dist
|
||
or z > dist or z < -dist then
|
||
return nil
|
||
end
|
||
-- return ok coords
|
||
return {x = x, y = y, z = z}
|
||
end
|
||
|
||
-- particle effects
|
||
local function add_particlespawner(src, teleport_type)
|
||
local amount, xz, y, minexptime, maxexptime
|
||
local sound_name, max_hear_distance= "teleport", 30
|
||
if teleport_type=="teleport_to" then
|
||
amount= 100
|
||
xz= 0.4
|
||
y= 0.3
|
||
minexptime= 6
|
||
maxexptime= 12
|
||
else
|
||
amount= 50
|
||
xz= 0.2
|
||
y= 0.2
|
||
minexptime= 3
|
||
maxexptime= 4.5
|
||
end
|
||
minetest.sound_play({name=sound_name, gain=1}, {pos=src, max_hear_distance=max_hear_distance})
|
||
minetest.add_particlespawner({
|
||
amount= amount,
|
||
time= 0.1,
|
||
minpos= {x=src.x-0.4, y=src.y+0.25, z=src.z-0.4},
|
||
maxpos= {x=src.x+0.4, y=src.y+0.75, z=src.z+0.4},
|
||
minvel= {x=-xz, y=-y, z=-xz},
|
||
maxvel= {x=xz, y=y, z=xz},
|
||
minexptime= minexptime,
|
||
maxexptime= maxexptime,
|
||
minsize=1,
|
||
maxsize=1.25,
|
||
texture= "particle.png",
|
||
glow= 15
|
||
})
|
||
end
|
||
|
||
|
||
local teleport_paper_entity = {
|
||
physical = true,
|
||
visual = "sprite",
|
||
visual_size = {x = 1.0, y = 1.0},
|
||
textures = {"teleport_paper.png"},
|
||
collisionbox = {-0.1,-0.1,-0.1,0.1,0.1,0.1},
|
||
lastpos = {},
|
||
player = "",
|
||
}
|
||
|
||
teleport_paper_entity.on_step = function(self, dtime)
|
||
if not self.player then self.object:remove() return end
|
||
|
||
local pos = self.object:get_pos()
|
||
if self.lastpos.x ~= nil then
|
||
local vel = self.object:get_velocity()
|
||
-- only when potion hits something physical
|
||
if vel.x == 0
|
||
or vel.y == 0
|
||
or vel.z == 0 then
|
||
if self.player ~= "" then
|
||
-- round up coords to fix glitching through doors
|
||
self.lastpos = vector.round(self.lastpos)
|
||
self.player:set_pos(self.lastpos)
|
||
add_particlespawner(self.lastpos, "teleport_to")
|
||
end
|
||
self.object:remove()
|
||
return
|
||
end
|
||
end
|
||
|
||
self.lastpos = pos
|
||
end
|
||
|
||
minetest.register_entity("teleport_book:teleport_paper_entity", teleport_paper_entity)
|
||
|
||
local book_writers = {}
|
||
minetest.register_on_leaveplayer(function(player)
|
||
book_writers[player:get_player_name()] = nil
|
||
end)
|
||
|
||
local name_book= "Teleport book"
|
||
local id_book= "teleport_book:book"
|
||
minetest.register_craftitem(id_book, {
|
||
description= name_book,
|
||
inventory_image= "teleport_book.png",
|
||
stack_max= 1,
|
||
range= 2,
|
||
groups= { book= 1 },
|
||
on_use= function(itemstack, user)
|
||
local meta= itemstack:get_meta()
|
||
local dest= minetest.string_to_pos(meta:get_string("_dest"))
|
||
local src= user:getpos()
|
||
if dest == nil then
|
||
meta:set_string("_dest", minetest.pos_to_string(src))
|
||
meta:set_int("_usages", math.random(25, 75))
|
||
meta:set_string("description", name_book.." for "..minetest.pos_to_string(src, 2))
|
||
local player_name = user:get_player_name()
|
||
book_writers[player_name] = {wield_index = user:get_wield_index()}
|
||
minetest.show_formspec(player_name, id_book,
|
||
"size[5,3]" ..
|
||
"field[0.25,1.5;4.75,1;name;"..S("Write a description of the book (optional):")..";]" ..
|
||
"button_exit[1.5,2;2,1;exit;Save]")
|
||
|
||
add_particlespawner(src, "teleport_from")
|
||
return itemstack
|
||
end
|
||
local usages= meta:get_int("_usages") - 1
|
||
--minetest.chat_send_player(user:get_player_name(), usages)
|
||
if usages==1 then
|
||
meta:set_string("description",
|
||
meta:get_string("description").." – almost destroyed!")
|
||
end
|
||
meta:set_int("_usages", usages)
|
||
add_particlespawner(src, "teleport_from")
|
||
user:setpos(dest)
|
||
add_particlespawner(dest, "teleport_to")
|
||
if usages==0 then itemstack:take_item() end
|
||
return itemstack
|
||
end
|
||
})
|
||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||
if formname ~= id_book then return end
|
||
|
||
local player_name = player:get_player_name()
|
||
local inv = player:get_inventory()
|
||
if not book_writers[player_name] or not fields.name or fields.name == "" then
|
||
return
|
||
end
|
||
local wield_index = book_writers[player_name].wield_index
|
||
local wield_list = player:get_wield_list()
|
||
local stack = inv:get_stack(wield_list, wield_index)
|
||
if stack:get_name() ~= id_book then
|
||
-- No book in the wield slot, abort & inform the player
|
||
minetest.chat_send_player(player_name, S("The book you were writing to mysteriously disappeared."))
|
||
return
|
||
end
|
||
local meta= stack:get_meta()
|
||
meta:set_string("description", name_book .. " – " .. fields.name)
|
||
inv:set_stack(wield_list, wield_index, stack)
|
||
end)
|
||
minetest.register_node("teleport_book:paper", {
|
||
tiles = {"teleport_paper.png"},
|
||
drawtype = "signlike",
|
||
paramtype = "light",
|
||
paramtype2 = "wallmounted",
|
||
walkable = true,
|
||
sunlight_propagates = true,
|
||
description = "Teleport paper plane",
|
||
inventory_image = "teleport_paper.png",
|
||
wield_image = "teleport_paper.png",
|
||
selection_box = {type = "wallmounted"},
|
||
groups= { snappy = 2, flammable = 3, oddly_breakable_by_hand = 3, choppy = 2, carpet = 1 },
|
||
|
||
after_place_node= function(_1, _2, itemstack)
|
||
itemstack:take_item()
|
||
return itemstack
|
||
end,
|
||
on_dig= function(pos, node, player)
|
||
minetest.remove_node(pos)
|
||
player:get_inventory():add_item("main", "teleport_book:paper")
|
||
end,
|
||
on_drop= function(itemstack, player)
|
||
local playerpos = player:get_pos()
|
||
|
||
local obj = minetest.add_entity({
|
||
x = playerpos.x,
|
||
y = playerpos.y + 1.5,
|
||
z = playerpos.z
|
||
}, "teleport_book:teleport_paper_entity")
|
||
|
||
local dir = player:get_look_dir()
|
||
local velocity = 20
|
||
|
||
obj:set_velocity({
|
||
x = dir.x * velocity,
|
||
y = dir.y * velocity,
|
||
z = dir.z * velocity
|
||
})
|
||
|
||
obj:set_acceleration({
|
||
x = dir.x * -3,
|
||
y = -9.5,
|
||
z = dir.z * -3
|
||
})
|
||
|
||
obj:set_yaw(player:get_look_horizontal())
|
||
obj:get_luaentity().player = player
|
||
if math.random(0,6) > 5 then
|
||
itemstack:set_count(itemstack:get_count()-1)
|
||
end
|
||
return itemstack
|
||
end,
|
||
})
|
||
|
||
-- Recipes
|
||
minetest.register_craft({
|
||
output = "teleport_book:paper 27",
|
||
recipe = {
|
||
{"teleport_book:book"},
|
||
},
|
||
})
|
||
minetest.register_craft({
|
||
output = "teleport_book:book",
|
||
recipe = {
|
||
{"default:mese_crystal"},
|
||
{"default:book"},
|
||
},
|
||
})
|
||
|
||
print("[MOD] Teleport Book loaded")
|