waypoint_announce/init.lua

210 lines
6.9 KiB
Lua

-- TODO show some text on screen for a short while?
-- TODO "admin" command version with configurable pos, radius and timeout
local ANNOUNCE_PREPARE_COMMAND_NAME = "look"
local ANNOUNCE_COMMAND_NAME = "look!"
local ANNOUNCE_RADIUS = 256 -- players within this radius will see a waypoint
local ANNOUNCE_ICON = "waypoint_announce_exclamation_mark.png"
local ANNOUNCE_TIMEOUT = 20 -- time until waypoint disappears
local WAYPOINT_COLOR = 0xFFFFFF -- color of the waypoint label
local ICON_SCALE = {x=-3,y=-3} -- size is 3% of the screen
local ICON_COLOR = "#E78C13"
local ARROW_FORMAT = "waypoint_announce_arrow_%03d.png"
local ARROW_QUADS_STEPS = 9
local POINT_RANGE = 180 -- maximun range player can point at (raycast range)
local POINT_TO_OBJECTS = true
local POINT_TO_LIQUIDS = true
local CHAT_MESSAGE_COLOR = "#FF90A8" -- argument to minetest.colorize()
local waypoint_lib = dofile(minetest.get_modpath("waypoint_announce") .. "/waypoint_lib.lua")
waypoint_announce = {
post_announcement_hook = function(announcer_name, message, pointed_pos) end,
}
local function show_hud_waypoint(player, point_pos, name, icon_name)
local size = {x=-9,y=-16} -- scale for 16:9 displays
local alignment = {x=100/9,y=100/16*0.7} -- int the middle above the crosshair
local do_auto_update = true
local hud = waypoint_lib.WaypointHUD:new(player, point_pos,
name, WAYPOINT_COLOR,
icon_name, ICON_SCALE, ICON_COLOR,
size, alignment, ARROW_FORMAT, ICON_COLOR, ARROW_QUADS_STEPS,
do_auto_update)
hud:show(player)
return hud
end
local Announcement = {}
function Announcement:new(announcer_name, radius, message, icon, timeout)
local a = {
announcer_name = announcer_name,
radius = radius,
message = message,
point = nil,
icon = icon,
timeout = timeout,
players_hud = {},
timeout_job = nil,
}
self.__index = self
setmetatable(a, self)
return a
end
local prepared_announcements = {}
local function prepare_announcement(announcer_name, radius, message, icon, timeout)
--prepared_announcements[select(1,...)] = table.pack(...) -- does not work in older lua?
prepared_announcements[announcer_name] = Announcement:new(announcer_name, radius, message, icon, timeout)
end
local function remove_announcement(announcement)
local announcer_name = announcement.announcer_name
for player_name, hud in pairs(announcement.players_hud) do
local player = minetest.get_player_by_name(player_name)
if player then
hud:hide(player)
end
end
announcement.timeout_job.cancel()
end
local function post_announcement(announcer, announcement)
local announcer_pos = announcer:get_pos()
-- TODO use pointed thing to provide some description?
local pointed_pos, pointed_thing = waypoint_lib.get_pointed_position(announcer, POINT_RANGE, POINT_TO_OBJECTS, POINT_TO_LIQUIDS)
if not pointed_pos then
-- player is pointing into the void, use him as target
pointed_pos = announcer_pos
end
announcement.point = pointed_pos
for i, object in pairs(minetest.get_objects_inside_radius(announcer_pos, announcement.radius)) do
if object:is_player() then
local player = object
local player_name = player:get_player_name()
local hud = show_hud_waypoint(player, pointed_pos, announcement.message, announcement.icon)
announcement.players_hud[player_name] = hud
end
end
local rounded_pos = vector.round(pointed_pos)
local chat_message = "[ANNOUNCE] (" ..
announcement.announcer_name ..
") Look: " ..
announcement.message .. " " ..
minetest.pos_to_string(rounded_pos)
minetest.chat_send_all(minetest.colorize(CHAT_MESSAGE_COLOR, chat_message))
announcement.timeout_job = minetest.after(announcement.timeout, remove_announcement, announcement)
waypoint_announce.post_announcement_hook(announcement.announcer_name, announcement.message, announcement.point)
end
local function check_click_for_prepared_players(dtime)
for player_name, announcement in pairs(prepared_announcements) do
local player = minetest.get_player_by_name(player_name)
if player then
local player_controls = player:get_player_control()
if player_controls['dig'] then
-- place prepared announcement at pointed position
post_announcement(player, announcement)
prepared_announcements[player_name] = nil
elseif player_controls['place'] then
-- cancel prepared announcement
minetest.chat_send_player(player_name, "Announcement canceled.")
prepared_announcements[player_name] = nil
end
else
-- player is not online anymore, remove prepared announcement
prepared_announcements[player_name] = nil
end
end
end
minetest.register_globalstep(check_click_for_prepared_players)
minetest.register_chatcommand(ANNOUNCE_PREPARE_COMMAND_NAME, {
privs = {
shout = true,
},
func = function(name, param)
local player = minetest.get_player_by_name(name)
if player then -- player is online
local player_name = player:get_player_name()
-- TODO limit message length?
prepare_announcement(player_name, ANNOUNCE_RADIUS, param, ANNOUNCE_ICON, ANNOUNCE_TIMEOUT)
return true, "Prepared announcement: \"" .. param .. "\". Point and <hit> where to put it. (<place> to cancel)."
else
return false
end
end,
})
minetest.register_chatcommand(ANNOUNCE_COMMAND_NAME, {
privs = {
shout = true,
},
func = function(name, param)
local player = minetest.get_player_by_name(name)
if player then -- player is online
local player_name = player:get_player_name()
local announcement = Announcement:new(player_name, ANNOUNCE_RADIUS, param, ANNOUNCE_ICON, ANNOUNCE_TIMEOUT)
post_announcement(player, announcement)
return true
else
return false
end
end,
})
local test_time = 0
local test_registered = false
local test_enabled = false
local function step_test_spam_look(player_name)
return function(dtime)
if not test_enabled then
return
end
test_time = test_time + dtime
if test_time < 0.2 then
return
else
test_time = 0
end
player_name = player_name or "singleplayer"
local player = minetest.get_player_by_name(player_name)
if player then -- player is online
local player_name = player:get_player_name()
local param = ""
local announcement = Announcement:new(player_name, ANNOUNCE_RADIUS, param, ANNOUNCE_ICON, ANNOUNCE_TIMEOUT)
post_announcement(player, announcement)
end
end
end
function announce_waypoint_test_spam_look(player_name)
if not test_registered then
minetest.register_globalstep(step_test_spam_look(player_name))
end
test_enabled = not test_enabled
end