ptol/init.lua

209 lines
6.5 KiB
Lua
Raw 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,
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 })
end,
})
function ptol.freeze(player)
ptol.players[player:get_player_name()] = true
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)
end
function ptol.unfreeze(player)
ptol.players[player:get_player_name()] = nil
local pname = player:get_player_name()
local objects = minetest.get_objects_inside_radius(player:get_pos(), 2)
for i=1, #objects do
local entity = objects[i]:get_luaentity()
if entity and entity.set_frozen_player and entity.pname == pname then
objects[i]:remove()
end
end
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
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
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))
local frozen = ptol.is_frozen(player)
--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)
ptol.show_warning(player)
minetest.sound_play("ptol_warning", {to_player = player:get_player_name(), gain = 1.0, max_hear_distance = 10,})
--minetest.chat_send_all("freeze")
elseif frozen and (angle_to_center <= ptol.settings.allowed_angle) and not(not_allowed_control) then
ptol.unfreeze(player)
ptol.remove_warning(player)
--minetest.chat_send_all("unfreeze")
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,
})