ptol/init.lua

219 lines
6.6 KiB
Lua
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

--
-- Ptolomey King Protector
-- License:GPLv3
--
local modname = minetest.get_current_modname()
local S = minetest.get_translator(modname)
local modpath = minetest.get_modpath(modname)
local ptol = {}
ptol.settings = {}
ptol.players = {}
ptol.warnings = {}
local static_spawnpoint = minetest.setting_get_pos("static_spawnpoint")
--Settings
local settings = Settings(modpath .. "/ptol.conf")
ptol.settings.shape = settings:get("shape") or "box"
ptol.settings.radius = tonumber(settings:get("radius")) or 120
ptol.settings.world_center = minetest.string_to_pos(settings:get("world_center")) or static_spawnpoint or {x=0, y=0, z=0}
ptol.settings.allowed_angle = tonumber(settings:get("allowed_angle")) or 45
ptol.settings.time = tonumber(settings:get("time")) or 1
local function player_inside_sphere(player_pos, ptol_level)
player_pos.y = player_pos.y - 1
--If sphere's centre coordinates is (cx,cy,cz) and its radius is r,
--then point (x,y,z) is in the sphere if (xcx)2+(ycy)2+(zcz)2<r2.
local distance_to_center = math.sqrt((player_pos.x - ptol.settings.world_center.x)^2+
(player_pos.y - ptol.settings.world_center.y)^2 +
(player_pos.z - ptol.settings.world_center.z)^2)
--minetest.chat_send_all(tostring(ptol_level))
if (ptol.settings.radius * ptol_level) >= distance_to_center then
return true
else
return false
end
end
local function player_inside_box(player_pos, ptol_level)
player_pos.y = player_pos.y - 1
local radius = ptol.settings.radius * ptol_level
local p1 = {
x = ptol.settings.world_center.x - radius,
y = ptol.settings.world_center.y - radius,
z = ptol.settings.world_center.z - radius,
}
local p2 = {
x = ptol.settings.world_center.x + radius,
y = ptol.settings.world_center.y + radius,
z = ptol.settings.world_center.z + radius,
}
if (p1.x <= player_pos.x) and (player_pos.x <= p2.x)
and (p1.y <= player_pos.y) and (player_pos.y <= p2.y)
and (p1.z <= player_pos.z) and (player_pos.z <= p2.z) then
return true
else
return false
end
end
--Freeze Player Code
function ptol.is_frozen(player)
return ptol.players[player:get_player_name()]
end
minetest.register_entity("ptol:freeze", {
-- This entity needs to be visible otherwise the frozen player won't be visible.
initial_properties = {
visual = "sprite",
visual_size = { x = 0, y = 0 },
textures = {"ptol_blank.png"},
physical = false, -- Disable collision
pointable = false, -- Disable selection box
makes_footstep_sound = false,
},
on_step = function(self, dtime)
local player = self.pname and minetest.get_player_by_name(self.pname)
if not player or not ptol.is_frozen(player) then
self.object:remove()
return
end
end,
on_activate = function(self, staticdata, dtime_s) --on_activate, required
if dtime_s > 0 then --loaded, nor new
self.object:remove()
end
end,
set_frozen_player = function(self, player)
self.pname = player:get_player_name()
player:set_attach(self.object, "", {x = 0, y = 0, z = 0 }, { x = 0, y = 0, z = 0 })
ptol.players[self.pname] = self.object
end,
})
function ptol.freeze(player)
local parent = player:get_attach()
if parent and parent:get_luaentity() and
parent:get_luaentity().set_frozen_player then
-- Already attached
return
end
local obj = minetest.add_entity(player:get_pos(), "ptol:freeze")
obj:get_luaentity():set_frozen_player(player)
ptol.show_warning(player)
minetest.sound_play("ptol_warning", {to_player = player:get_player_name(), gain = 1.0, max_hear_distance = 10,})
end
function ptol.unfreeze(player)
local player_name = player:get_player_name()
ptol.players[player_name]:remove() --remove the entity
ptol.players[player_name] = nil --remove the player registry
ptol.remove_warning(player)
end
function ptol.show_warning(player)
local hud_id = player:hud_add({
hud_elem_type = "text",
position = {x = 0.5, y = 0.5},
offset = {x = 0, y = 0},
text = S("You have reached the limits of your world.\nTurn around and go back where you came from."),
alignment = {x = 0, y = 0}, -- center aligned
scale = {x = 100, y = 100}, -- covered later
})
ptol.warnings[player:get_player_name()] = hud_id
end
function ptol.remove_warning(player)
player:hud_remove(ptol.warnings[player:get_player_name()])
end
minetest.register_on_leaveplayer(function(player)
if ptol.is_frozen(player) then
ptol.unfreeze(player)
end
end)
local timer = 0
minetest.register_globalstep(function(dtime)
timer = timer + dtime
if timer <= ptol.settings.time then
return
else
timer = 0
end
for _, player in pairs(minetest.get_connected_players()) do
local player_pos = player:get_pos()
local ptol_level = player:get_meta():get_int("ptol:level")
if ptol_level == 0 then
ptol_level = 1
end
--minetest.chat_send_all(tostring(ptol_level))
local player_inside
if ptol.settings.shape == "sphere" then
player_inside = player_inside_sphere(player_pos, ptol_level)
else
player_inside = player_inside_box(player_pos, ptol_level)
end
local frozen = ptol.is_frozen(player)
if not player_inside then
local dir_to_center = vector.direction(player_pos, ptol.settings.world_center)
local player_dir = player:get_look_dir()
local angle_to_center = math.deg(vector.angle(dir_to_center, player_dir))
--minetest.chat_send_all(tostring(angle_to_center))
--minetest.chat_send_all(tostring(angle_to_center)..":"..tostring(ptol.settings.allowed_angle))
local controls = player:get_player_control()
local not_allowed_control = false
if controls["down"] or controls["right"] or controls["left"] then
not_allowed_control = true
end
if not(frozen) and ((angle_to_center > ptol.settings.allowed_angle) or not_allowed_control) then
ptol.freeze(player)
--minetest.chat_send_all("freeze")
elseif frozen and (angle_to_center <= ptol.settings.allowed_angle) and not(not_allowed_control) then
ptol.unfreeze(player)
--minetest.chat_send_all("unfreeze")
end
else
if frozen then
ptol.unfreeze(player)
end
end
end
end)
--COMMANDS
minetest.register_chatcommand("ptol", {
privs = {
server = true,
},
description = "Ptolomey Commands",
func = function(name, param)
local player_name, value
local i = 0
for word in string.gmatch(param, "([%a%d_-]+)") do
if i == 0 then
player_name = word
else
value = word
end
i = i + 1
end
local player = minetest.get_player_by_name(player_name)
if not player then
return true, "Error: The player does not exist or not online."
end
local level = tonumber(value)
if not level then
return true, "Error: Value of the level missed."
end
player:get_meta():set_int("ptol:level", level)
minetest.chat_send_player(name, "The level for "..player_name.." ".."set to".." "..value)
end,
})