teleportpotion/init.lua

567 lines
13 KiB
Lua
Raw Normal View History

2014-11-09 19:20:46 +00:00
2023-04-15 11:00:35 +01:00
--= Teleport Potion mod by TenPlus1
2014-11-09 19:20:46 +00:00
2020-04-30 20:24:58 +01:00
-- Craft teleport potion or pad, use to bookmark location, place to open
-- portal or place pad, portals show a blue flame that you can walk into
-- before it closes (10 seconds), potions can also be thrown for local teleport.
2014-11-09 19:20:46 +00:00
2023-08-08 14:16:03 +01:00
-- translation support
2023-09-23 14:12:16 +01:00
local S = minetest.get_translator("teleport_potion")
2016-05-30 12:42:09 +01:00
-- check for MineClone2
local mcl = minetest.get_modpath("mcl_core")
-- max teleport distance
2017-10-09 14:58:53 +01:00
local dist = tonumber(minetest.settings:get("map_generation_limit") or 31000)
2014-11-09 19:20:46 +00:00
2017-10-09 14:58:53 +01:00
-- creative check
local creative_mode_cache = minetest.settings:get_bool("creative_mode")
2021-04-02 19:41:59 +01:00
2018-04-09 19:09:59 +01:00
local function is_creative(name)
2017-10-09 14:58:53 +01:00
return creative_mode_cache or minetest.check_player_privs(name, {creative = true})
end
-- choose texture for teleport pad
local teleport_pad_texture = "teleport_potion_pad.png"
if minetest.settings:get_bool("teleport_potion_use_old_texture") == true then
teleport_pad_texture = "teleport_potion_pad_v1.png"
end
2021-04-02 19:41:59 +01:00
-- make sure coordinates are valid
local check_coordinates = function(str)
2014-11-09 19:20:46 +00:00
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)
2015-05-12 18:08:01 +01:00
-- 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
2023-04-15 11:00:35 +01:00
-- particle effect
local effect = function(pos, amount, texture, min_size, max_size, radius, gravity, glow)
radius = radius or 2
gravity = gravity or -10
2021-04-02 19:41:59 +01:00
minetest.add_particlespawner({
2023-04-15 11:00:35 +01:00
amount = amount,
time = 0.25,
minpos = pos,
maxpos = pos,
2023-04-15 11:00:35 +01:00
minvel = {x = -radius, y = -radius, z = -radius},
maxvel = {x = radius, y = radius, z = radius},
minacc = {x = 0, y = gravity, z = 0},
maxacc = {x = 0, y = gravity, z = 0},
minexptime = 0.1,
maxexptime = 1,
2023-04-15 11:00:35 +01:00
minsize = min_size or 0.5,
maxsize = max_size or 1.0,
texture = texture,
glow = glow
})
end
2014-11-09 19:20:46 +00:00
2023-04-15 11:00:35 +01:00
local teleport_destinations = {}
2018-04-09 19:09:59 +01:00
local function set_teleport_destination(playername, dest)
2021-04-02 19:41:59 +01:00
teleport_destinations[playername] = dest
2021-04-02 19:41:59 +01:00
2023-04-15 11:00:35 +01:00
effect(dest, 20, "teleport_potion_particle.png", 0.5, 1.5, 1, 7, 15)
2021-04-02 19:41:59 +01:00
minetest.sound_play("portal_open", {
2021-04-02 19:41:59 +01:00
pos = dest, gain = 1.0, max_hear_distance = 10}, true)
end
--- Teleport portal
2014-11-09 19:20:46 +00:00
minetest.register_node("teleport_potion:portal", {
drawtype = "plantlike",
2015-07-05 16:47:35 +01:00
tiles = {
2021-04-02 19:41:59 +01:00
{
name = "teleport_potion_portal.png",
2015-07-05 16:47:35 +01:00
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 1.0
}
}
},
2015-11-18 10:10:03 +00:00
light_source = 13,
2014-11-09 19:20:46 +00:00
walkable = false,
2015-05-12 18:08:01 +01:00
paramtype = "light",
2014-11-09 19:20:46 +00:00
pointable = false,
buildable_to = true,
waving = 1,
sunlight_propagates = true,
damage_per_second = 1, -- walking into portal hurts player
groups = {not_in_creative_inventory = 1},
2023-04-15 11:00:35 +01:00
drop = {},
2014-11-09 19:20:46 +00:00
2015-09-08 16:56:22 +01:00
-- start timer when portal appears
2014-11-09 19:20:46 +00:00
on_construct = function(pos)
minetest.get_node_timer(pos):start(10)
2014-11-09 19:20:46 +00:00
end,
2015-09-08 16:56:22 +01:00
-- remove portal after 10 seconds
2014-11-09 19:20:46 +00:00
on_timer = function(pos)
2015-11-18 10:10:03 +00:00
2015-07-05 16:47:35 +01:00
minetest.sound_play("portal_close", {
2021-04-02 19:41:59 +01:00
pos = pos, gain = 1.0, max_hear_distance = 10}, true)
2015-11-18 10:10:03 +00:00
minetest.remove_node(pos)
2014-11-09 19:20:46 +00:00
end,
2023-04-15 11:00:35 +01:00
2018-09-30 22:06:23 +01:00
on_blast = function() end,
2014-11-09 19:20:46 +00:00
})
2018-04-09 19:07:45 +01:00
-- Throwable potion
local function throw_potion(itemstack, player)
local playerpos = player:get_pos()
local obj = minetest.add_entity({
x = playerpos.x,
y = playerpos.y + 1.5,
z = playerpos.z
}, "teleport_potion:potion_entity")
local dir = player:get_look_dir()
local velocity = 20
2023-04-15 11:00:35 +01:00
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())
2018-04-09 19:07:45 +01:00
obj:get_luaentity().player = player
end
2021-04-02 19:41:59 +01:00
-- potion entity
2018-04-09 19:07:45 +01:00
local potion_entity = {
2023-09-23 14:12:16 +01:00
initial_properties = {
physical = true,
visual = "sprite",
visual_size = {x = 1.0, y = 1.0},
textures = {"teleport_potion_potion.png"},
collisionbox = {-0.1,-0.1,-0.1,0.1,0.1,0.1},
},
2018-04-09 19:07:45 +01:00
lastpos = {},
2021-04-02 19:41:59 +01:00
player = ""
2018-04-09 19:07:45 +01:00
}
potion_entity.on_step = function(self, dtime)
if not self.player then
2021-04-02 19:41:59 +01:00
2018-04-09 19:07:45 +01:00
self.object:remove()
2021-04-02 19:41:59 +01:00
2018-04-09 19:07:45 +01:00
return
end
local pos = self.object:get_pos()
if self.lastpos.x ~= nil then
local vel = self.object:get_velocity()
2018-04-09 19:07:45 +01:00
-- only when potion hits something physical
2023-04-15 11:00:35 +01:00
if vel.x == 0 or vel.y == 0 or vel.z == 0 then
2018-04-09 19:07:45 +01:00
if self.player ~= "" then
-- round up coords to fix glitching through doors
self.lastpos = vector.round(self.lastpos)
2023-04-15 11:00:35 +01:00
local oldpos = self.player:get_pos()
-- play sound and disappearing particle effect at current position
minetest.sound_play("portal_close", {
pos = oldpos, gain = 1.0, max_hear_distance = 5}, true)
oldpos.y = oldpos.y + 1
effect(oldpos, 25, "teleport_potion_particle.png", 2, 2, 1, -10, 15)
-- teleport to new position, play sound and show appear effect
self.player:set_pos(self.lastpos)
2018-04-09 19:07:45 +01:00
minetest.sound_play("portal_close", {
2023-04-15 11:00:35 +01:00
pos = self.lastpos, gain = 1.0, max_hear_distance = 5}, true)
2018-04-09 19:07:45 +01:00
2023-04-15 11:00:35 +01:00
effect(self.lastpos, 20, "teleport_potion_particle.png", 2, 2, 1, 10, 15)
2018-04-09 19:07:45 +01:00
end
self.object:remove()
return
end
end
self.lastpos = pos
end
minetest.register_entity("teleport_potion:potion_entity", potion_entity)
--- Teleport potion
2014-11-09 19:20:46 +00:00
minetest.register_node("teleport_potion:potion", {
2021-04-02 19:41:59 +01:00
tiles = {"teleport_potion_potion.png"},
2014-11-09 19:20:46 +00:00
drawtype = "signlike",
paramtype = "light",
paramtype2 = "wallmounted",
walkable = false,
sunlight_propagates = true,
2021-06-10 09:38:10 +01:00
description = S("Teleport Potion (use to set destination, place to open portal)"),
2021-04-02 19:41:59 +01:00
inventory_image = "teleport_potion_potion.png",
wield_image = "teleport_potion_potion.png",
2019-01-30 09:09:49 +00:00
groups = {dig_immediate = 3, vessel = 1},
2015-07-05 16:47:35 +01:00
selection_box = {type = "wallmounted"},
2014-11-09 19:20:46 +00:00
on_use = function(itemstack, user, pointed_thing)
2021-04-02 19:41:59 +01:00
if pointed_thing.type == "node" then
set_teleport_destination(user:get_player_name(), pointed_thing.above)
else
throw_potion(itemstack, user)
2021-04-02 19:41:59 +01:00
if not is_creative(user:get_player_name()) then
2021-04-02 19:41:59 +01:00
itemstack:take_item()
2021-04-02 19:41:59 +01:00
return itemstack
end
end
end,
2015-11-04 19:34:58 +00:00
after_place_node = function(pos, placer, itemstack, pointed_thing)
2021-04-02 19:41:59 +01:00
local name = placer:get_player_name()
local dest = teleport_destinations[name]
2021-04-02 19:41:59 +01:00
if dest then
2021-04-02 19:41:59 +01:00
minetest.set_node(pos, {name = "teleport_potion:portal"})
2021-04-02 19:41:59 +01:00
local meta = minetest.get_meta(pos)
2021-04-02 19:41:59 +01:00
-- Set portal destination
meta:set_int("x", dest.x)
meta:set_int("y", dest.y)
meta:set_int("z", dest.z)
2021-04-02 19:41:59 +01:00
-- Portal open effect and sound
2023-04-15 11:00:35 +01:00
effect(pos, 20, "teleport_potion_particle.png", 0.5, 1.5, 1, 7, 15)
2021-04-02 19:41:59 +01:00
2015-07-05 16:47:35 +01:00
minetest.sound_play("portal_open", {
2021-04-02 19:41:59 +01:00
pos = pos, gain = 1.0, max_hear_distance = 10}, true)
2014-11-09 19:20:46 +00:00
else
2016-05-30 12:42:09 +01:00
minetest.chat_send_player(name, S("Potion failed!"))
minetest.remove_node(pos)
2016-05-30 12:42:09 +01:00
minetest.add_item(pos, "teleport_potion:potion")
2014-11-09 19:20:46 +00:00
end
2021-04-02 19:41:59 +01:00
end
2014-11-09 19:20:46 +00:00
})
-- teleport potion recipe
if mcl then
minetest.register_craft({
output = "teleport_potion:potion",
recipe = {
{"", "mcl_core:diamond", ""},
{"mcl_core:diamond", "mcl_potions:glass_bottle", "mcl_core:diamond"},
2021-06-10 09:38:10 +01:00
{"", "mcl_core:diamond", ""}
}
})
else
minetest.register_craft({
2016-05-30 12:42:09 +01:00
output = "teleport_potion:potion",
recipe = {
{"", "default:diamond", ""},
{"default:diamond", "vessels:glass_bottle", "default:diamond"},
2021-06-10 09:38:10 +01:00
{"", "default:diamond", ""}
}
})
end
--- Teleport pad
local teleport_formspec_context = {}
2014-11-09 19:20:46 +00:00
minetest.register_node("teleport_potion:pad", {
tiles = {teleport_pad_texture, teleport_pad_texture .. "^[transformFY"},
2016-10-03 10:42:37 +01:00
drawtype = "nodebox",
2014-11-09 19:20:46 +00:00
paramtype = "light",
2016-10-03 10:42:37 +01:00
paramtype2 = "facedir",
2015-11-23 11:46:34 +00:00
legacy_wallmounted = true,
2014-11-09 19:20:46 +00:00
walkable = true,
sunlight_propagates = true,
2021-06-10 09:38:10 +01:00
description = S("Teleport Pad (use to set destination, place to open portal)"),
inventory_image = teleport_pad_texture,
wield_image = teleport_pad_texture,
2014-11-09 19:20:46 +00:00
light_source = 5,
2015-09-08 16:56:22 +01:00
groups = {snappy = 3},
2014-11-09 19:20:46 +00:00
node_box = {
2016-10-03 10:42:37 +01:00
type = "fixed",
fixed = {-0.5, -0.5, -0.5, 0.5, -6/16, 0.5}
},
selection_box = {
type = "fixed",
fixed = {-0.5, -0.5, -0.5, 0.5, -6/16, 0.5}
2014-11-09 19:20:46 +00:00
},
-- Save pointed nodes coordinates as destination for further portals
on_use = function(itemstack, user, pointed_thing)
2021-04-02 19:41:59 +01:00
if pointed_thing.type == "node" then
set_teleport_destination(user:get_player_name(), pointed_thing.above)
end
end,
2014-11-09 19:20:46 +00:00
-- Initialize teleport to saved location or the current position
after_place_node = function(pos, placer, itemstack, pointed_thing)
2021-04-02 19:41:59 +01:00
local meta = minetest.get_meta(pos)
local name = placer:get_player_name()
local dest = teleport_destinations[name]
2021-04-02 19:41:59 +01:00
if not dest then
dest = pos
end
2021-04-02 19:41:59 +01:00
-- Set coords
meta:set_int("x", dest.x)
meta:set_int("y", dest.y)
meta:set_int("z", dest.z)
2014-11-09 19:20:46 +00:00
meta:set_string("infotext", S("Pad Active (@1,@2,@3)",
dest.x, dest.y, dest.z))
2014-11-09 19:20:46 +00:00
2023-04-15 11:00:35 +01:00
effect(pos, 20, "teleport_potion_particle.png", 0.5, 1.5, 1, 7, 15)
minetest.sound_play("portal_open", {
2021-04-02 19:41:59 +01:00
pos = pos, gain = 1.0, max_hear_distance = 10}, true)
2014-11-09 19:20:46 +00:00
end,
-- Show formspec depending on the players privileges.
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
2021-04-02 19:41:59 +01:00
local name = clicker:get_player_name()
2014-11-09 19:20:46 +00:00
if minetest.is_protected(pos, name) then
2021-04-02 19:41:59 +01:00
2014-11-09 19:20:46 +00:00
minetest.record_protection_violation(pos, name)
2021-04-02 19:41:59 +01:00
2014-11-09 19:20:46 +00:00
return
end
local meta = minetest.get_meta(pos)
local coords = meta:get_int("x") .. "," .. meta:get_int("y") .. "," .. meta:get_int("z")
local desc = meta:get_string("desc")
local formspec = "field[desc;" .. S("Description") .. ";"
.. minetest.formspec_escape(desc) .. "]"
2021-04-02 19:41:59 +01:00
-- Only allow privileged players to change coordinates
if minetest.check_player_privs(name, "teleport") then
formspec = formspec ..
"field[coords;" .. S("Teleport coordinates") .. ";" .. coords .. "]"
end
2014-11-09 19:20:46 +00:00
teleport_formspec_context[name] = {
pos = pos,
coords = coords,
desc = desc,
}
2021-04-02 19:41:59 +01:00
minetest.show_formspec(name, "teleport_potion:set_destination", formspec)
2021-04-02 19:41:59 +01:00
end
})
-- Check and set coordinates
minetest.register_on_player_receive_fields(function(player, formname, fields)
2021-04-02 19:41:59 +01:00
if formname ~= "teleport_potion:set_destination" then
return false
end
2021-04-02 19:41:59 +01:00
local name = player:get_player_name()
local context = teleport_formspec_context[name]
2021-04-02 19:41:59 +01:00
if not context then return false end
2021-04-02 19:41:59 +01:00
teleport_formspec_context[name] = nil
2021-04-02 19:41:59 +01:00
if fields.control == nil and fields.desc == nil then
return false
end
local meta = minetest.get_meta(context.pos)
2021-04-02 19:41:59 +01:00
-- Coordinates were changed
if fields.coords and fields.coords ~= context.coords then
2021-04-02 19:41:59 +01:00
local coords = check_coordinates(fields.coords)
2021-04-02 19:41:59 +01:00
if coords then
meta:set_int("x", coords.x)
meta:set_int("y", coords.y)
meta:set_int("z", coords.z)
2014-11-09 19:20:46 +00:00
else
2016-05-30 12:42:09 +01:00
minetest.chat_send_player(name, S("Teleport Pad coordinates failed!"))
2014-11-09 19:20:46 +00:00
end
end
2021-04-02 19:41:59 +01:00
-- Update infotext
if fields.desc then
meta:set_string("desc", fields.desc)
end
if fields.desc and fields.desc ~= "" then
meta:set_string("infotext", S("Teleport to @1", fields.desc))
else
local coords = minetest.string_to_pos("(" .. context.coords .. ")")
2021-04-02 19:41:59 +01:00
meta:set_string("infotext", S("Pad Active (@1,@2,@3)",
coords.x, coords.y, coords.z))
end
2021-04-02 19:41:59 +01:00
return true
end)
-- teleport pad recipe
if mcl then
minetest.register_craft({
output = "teleport_potion:pad",
recipe = {
{"teleport_potion:potion", "mcl_core:glass", "teleport_potion:potion"},
{"mcl_core:glass", "mesecons:redstone", "mcl_core:glass"},
2021-06-10 09:38:10 +01:00
{"teleport_potion:potion", "mcl_core:glass", "teleport_potion:potion"}
}
})
else
minetest.register_craft({
2019-08-05 10:06:30 +01:00
output = "teleport_potion:pad",
recipe = {
2019-08-05 10:06:30 +01:00
{"teleport_potion:potion", "default:glass", "teleport_potion:potion"},
{"default:glass", "default:mese", "default:glass"},
{"teleport_potion:potion", "default:glass", "teleport_potion:potion"}
}
})
end
-- check portal & pad, teleport any entities on top
2014-11-09 19:20:46 +00:00
minetest.register_abm({
2016-08-19 19:37:56 +01:00
label = "Potion/Pad teleportation",
2014-11-09 19:20:46 +00:00
nodenames = {"teleport_potion:portal", "teleport_potion:pad"},
interval = 2,
2014-11-09 19:20:46 +00:00
chance = 1,
2015-11-07 20:54:57 +00:00
catch_up = false,
2014-11-09 19:20:46 +00:00
action = function(pos, node, active_object_count, active_object_count_wider)
2015-09-08 16:56:22 +01:00
-- check objects inside pad/portal
local objs = minetest.get_objects_inside_radius(pos, 1)
2015-11-18 10:10:03 +00:00
if #objs == 0 then
return
end
2015-09-08 16:56:22 +01:00
-- get coords from pad/portal
local meta = minetest.get_meta(pos)
2016-06-01 13:28:54 +01:00
if not meta then return end -- errorcheck
2015-09-08 16:56:22 +01:00
local target_coords = {
x = meta:get_int("x"),
y = meta:get_int("y"),
z = meta:get_int("z")
2015-09-08 16:56:22 +01:00
}
2016-06-05 12:24:11 +01:00
for n = 1, #objs do
if objs[n]:is_player() then
2015-09-08 16:56:22 +01:00
-- play sound on portal end
2015-07-05 16:47:35 +01:00
minetest.sound_play("portal_close", {
pos = pos,
gain = 1.0,
max_hear_distance = 5
2023-04-15 11:00:35 +01:00
2020-04-30 20:24:58 +01:00
}, true)
2015-09-08 16:56:22 +01:00
2023-04-15 11:00:35 +01:00
pos.y = pos.y + 1
-- particle effect on disappear
effect(pos, 25, "teleport_potion_particle.png", 2, 2, 1, -10, 15)
-- move player
objs[n]:set_pos(target_coords)
2015-09-08 16:56:22 +01:00
-- paricle effects on arrival
2023-04-15 11:00:35 +01:00
effect(target_coords, 20, "teleport_potion_particle.png", 2, 2, 1, 10, 15)
2015-09-08 16:56:22 +01:00
-- play sound on destination end
2015-07-05 16:47:35 +01:00
minetest.sound_play("portal_close", {
pos = target_coords,
gain = 1.0,
max_hear_distance = 5
2020-04-30 20:24:58 +01:00
}, true)
2016-10-03 10:42:37 +01:00
-- rotate player to look in pad placement direction
local rot = node.param2
local yaw = 0
if rot == 0 or rot == 20 then
yaw = 0 -- north
elseif rot == 2 or rot == 22 then
yaw = 3.14 -- south
elseif rot == 1 or rot == 23 then
yaw = 4.71 -- west
elseif rot == 3 or rot == 21 then
yaw = 1.57 -- east
2016-10-03 10:42:37 +01:00
end
objs[n]:set_look_horizontal(yaw)
2014-11-09 19:20:46 +00:00
end
end
2015-09-08 16:56:22 +01:00
end
2015-11-04 19:34:58 +00:00
})
2021-04-02 19:41:59 +01:00
-- lucky blocks
2016-11-12 10:45:57 +00:00
if minetest.get_modpath("lucky_block") then
2021-04-02 19:41:59 +01:00
2016-11-12 10:45:57 +00:00
lucky_block:add_blocks({
{"dro", {"teleport_potion:potion"}, 2},
{"tel"},
{"dro", {"teleport_potion:pad"}, 1},
2021-04-02 19:41:59 +01:00
{"lig"}
2016-11-12 10:45:57 +00:00
})
end
2023-08-08 14:16:03 +01:00
2016-11-12 10:45:57 +00:00
print ("[MOD] Teleport Potion loaded")