1
0
mirror of https://github.com/ComfyFactory/ComfyFactorio.git synced 2025-01-14 02:34:09 +02:00
ComfyFactorio/utils/alert.lua

408 lines
12 KiB
Lua
Raw Normal View History

2020-06-05 23:53:58 +02:00
local Event = require 'utils.event'
local Global = require 'utils.global'
local Gui = require 'utils.gui'
2024-06-04 23:27:12 +02:00
local Task = require 'utils.task_token'
2020-06-05 23:53:58 +02:00
local Color = require 'utils.color_presets'
2022-02-14 00:32:57 +02:00
local SpamProtection = require 'utils.spam_protection'
2024-06-04 23:27:12 +02:00
local Commands = require 'utils.commands'
2020-06-05 23:53:58 +02:00
local pairs = pairs
local next = next
local Public = {}
local active_alerts = {}
2024-06-04 23:27:12 +02:00
local id_counter = { 0 }
2020-06-05 23:53:58 +02:00
local alert_zoom_to_pos = Gui.uid_name()
local on_tick
Global.register(
2024-06-04 23:27:12 +02:00
{ active_alerts = active_alerts, id_counter = id_counter },
function (tbl)
2020-06-05 23:53:58 +02:00
active_alerts = tbl.active_alerts
id_counter = tbl.id_counter
2024-03-21 00:08:54 +02:00
end
2020-06-05 23:53:58 +02:00
)
local alert_frame_name = Gui.uid_name()
local alert_container_name = Gui.uid_name()
local alert_progress_name = Gui.uid_name()
local close_alert_name = Gui.uid_name()
--- Apply this name to an element to have it close the alert when clicked.
-- Two elements in the same parent cannot have the same name. If you need your
-- own name you can use Public.close_alert(element)
Public.close_alert_name = close_alert_name
2024-06-04 23:27:12 +02:00
local delay_print_alert_token =
Task.register(
function (event)
local text = event.text
if not text then
return
end
local ttl = event.ttl
if not ttl then
ttl = 60
end
local sprite = event.sprite
local color = event.color
Public.alert_all_players(ttl, text, color, sprite, 1)
end
)
Public.set_timeout_in_ticks_alert = function (delay, data)
if not data then
return error('Data was not provided', 2)
end
if type(data) ~= 'table' then
return error("Data must be of type 'table'", 2)
end
if not delay then
return error('No delay was provided', 2)
end
Task.set_timeout_in_ticks(delay, delay_print_alert_token, data)
end
2020-06-05 23:53:58 +02:00
---Creates a unique ID for a alert message
local function autoincrement()
local id = id_counter[1] + 1
id_counter[1] = id
return id
end
---Attempts to get a alert based on the element, will traverse through parents to find it.
---@param element LuaGuiElement
local function get_alert(element)
if not element or not element.valid then
return nil
end
if element.name == alert_frame_name then
return element.parent
end
return get_alert(element.parent)
end
--- Closes the alert for the element.
--@param element LuaGuiElement
function Public.close_alert(element)
local alert = get_alert(element)
if not alert then
return
end
local data = Gui.get_data(alert)
2021-06-06 20:14:26 +02:00
if not data then
return
end
2020-06-05 23:53:58 +02:00
active_alerts[data.alert_id] = nil
Gui.destroy(alert)
end
---Message to a specific player
---@param player LuaPlayer
---@param duration number in seconds
---@param sound string sound to play, nil to not play anything
2020-07-06 15:45:09 +02:00
local function alert_to(player, duration, sound, volume)
2024-06-04 23:27:12 +02:00
local frame_holder = player.gui.left.add({ type = 'flow' })
2020-06-05 23:53:58 +02:00
local frame = frame_holder.add({ type = 'frame', name = alert_frame_name, direction = 'vertical' })
2020-06-05 23:53:58 +02:00
frame.style.width = 300
frame.style.padding = 3
2020-06-05 23:53:58 +02:00
2024-06-04 23:27:12 +02:00
local container = frame.add({ type = 'flow', name = alert_container_name, direction = 'horizontal' })
2020-06-05 23:53:58 +02:00
container.style.horizontally_stretchable = true
2024-06-04 23:27:12 +02:00
local progressbar = frame.add({ type = 'progressbar', name = alert_progress_name })
2020-06-05 23:53:58 +02:00
local style = progressbar.style
style.width = 290
style.height = 4
style.color = Color.orange
progressbar.value = 1 -- it starts full
local id = autoincrement()
local tick = game.tick
if not duration then
duration = 15
end
Gui.set_data(
frame_holder,
{
alert_id = id,
progressbar = progressbar,
start_tick = tick,
end_tick = tick + duration * 60
}
)
if not next(active_alerts) then
Event.add_removable_nth_tick(2, on_tick)
end
active_alerts[id] = frame_holder
if sound then
2020-10-30 23:05:05 +02:00
volume = volume or 0.60
2024-06-04 23:27:12 +02:00
player.play_sound({ path = sound, volume_modifier = volume })
2020-06-05 23:53:58 +02:00
end
return container
end
local function zoom_to_pos(event)
2022-02-14 00:32:57 +02:00
local is_spamming = SpamProtection.is_spamming(event.player, nil, 'Alert Zoom to Pos')
if is_spamming then
return
end
2024-11-01 11:51:36 +02:00
local player = event.player
2020-06-05 23:53:58 +02:00
local element = event.element
2024-11-01 11:51:36 +02:00
local data = Gui.get_data(element)
if not data then return end
2020-06-05 23:53:58 +02:00
2024-11-01 11:51:36 +02:00
if player.controller_type == defines.controllers.remote then
2024-10-26 01:25:43 +02:00
return
end
2024-11-01 11:51:36 +02:00
player.set_controller({
type = defines.controllers.remote,
position = data.position,
surface = player.surface,
zoom = 4
})
2020-06-05 23:53:58 +02:00
end
local close_alert = Public.close_alert
local function on_click_close_alert(event)
2022-02-14 00:32:57 +02:00
local is_spamming = SpamProtection.is_spamming(event.player, nil, 'Alert Close')
if is_spamming then
return
end
2020-06-05 23:53:58 +02:00
close_alert(event.element)
end
Gui.on_click(alert_zoom_to_pos, zoom_to_pos)
Gui.on_click(alert_frame_name, on_click_close_alert)
Gui.on_click(alert_container_name, on_click_close_alert)
Gui.on_click(alert_progress_name, on_click_close_alert)
Gui.on_click(close_alert_name, on_click_close_alert)
local function update_alert(id, frame, tick)
if not frame.valid then
active_alerts[id] = nil
return
end
local data = Gui.get_data(frame)
2022-09-03 21:26:20 +02:00
if not data then
return
end
2020-06-05 23:53:58 +02:00
local end_tick = data.end_tick
if tick > end_tick then
Gui.destroy(frame)
active_alerts[data.alert_id] = nil
else
local limit = end_tick - data.start_tick
local current = end_tick - tick
data.progressbar.value = current / limit
end
end
on_tick =
2024-06-04 23:27:12 +02:00
Task.register(
function (event)
if not next(active_alerts) then
Event.remove_removable_nth_tick(2, on_tick)
return
end
2020-06-05 23:53:58 +02:00
2024-06-04 23:27:12 +02:00
local tick = event.tick
2020-06-05 23:53:58 +02:00
2024-06-04 23:27:12 +02:00
for id, frame in pairs(active_alerts) do
update_alert(id, frame, tick)
end
2020-06-05 23:53:58 +02:00
end
2024-06-04 23:27:12 +02:00
)
2020-06-05 23:53:58 +02:00
---Message a specific player, template is a callable that receives a LuaGuiElement
---to add contents to and a player as second argument.
---@param player LuaPlayer
2022-09-03 21:26:20 +02:00
---@param duration number
2020-06-05 23:53:58 +02:00
---@param template function
2022-09-03 21:26:20 +02:00
---@param sound string|nil sound to play, nil to not play anything
2020-07-06 15:45:09 +02:00
function Public.alert_player_template(player, duration, template, sound, volume)
2020-06-05 23:53:58 +02:00
sound = sound or 'utility/new_objective'
2020-07-06 15:45:09 +02:00
local container = alert_to(player, duration, sound, volume)
2020-06-05 23:53:58 +02:00
if container then
template(container, player)
end
end
---Message all players of the given force, template is a callable that receives a LuaGuiElement
---to add contents to and a player as second argument.
---@param force LuaForce
---@param duration number
---@param template function
---@param sound string sound to play, nil to not play anything
function Public.alert_force_template(force, duration, template, sound)
sound = sound or 'utility/new_objective'
local players = force.connected_players
for i = 1, #players do
local player = players[i]
template(alert_to(player, duration, sound), player)
end
end
---Message all players, template is a callable that receives a LuaGuiElement
---to add contents to and a player as second argument.
---@param duration number
---@param template function
2022-09-03 21:26:20 +02:00
---@param sound string|nil sound to play, nil to not play anything
2020-06-05 23:53:58 +02:00
function Public.alert_all_players_template(duration, template, sound)
sound = sound or 'utility/new_objective'
local players = game.connected_players
for i = 1, #players do
local player = players[i]
template(alert_to(player, duration, sound), player)
end
end
---Message all players at a given location
---@param player LuaPlayer
2022-09-03 21:26:20 +02:00
---@param message string|table
2022-07-10 19:42:07 +02:00
---@param color string|nil
2020-08-09 20:22:33 +02:00
function Public.alert_all_players_location(player, message, color, duration)
local length = duration or 15
2020-06-05 23:53:58 +02:00
Public.alert_all_players_template(
2020-08-09 20:22:33 +02:00
length,
2024-06-04 23:27:12 +02:00
function (container)
2020-06-05 23:53:58 +02:00
local sprite =
container.add {
2024-06-04 23:27:12 +02:00
type = 'sprite-button',
name = alert_zoom_to_pos,
sprite = 'utility/search_icon',
style = 'slot_button'
}
2020-06-05 23:53:58 +02:00
2024-11-01 11:51:36 +02:00
Gui.set_data(sprite, player.position)
2020-06-05 23:53:58 +02:00
local label =
container.add {
2024-06-04 23:27:12 +02:00
type = 'label',
name = Public.close_alert_name,
caption = message
}
2020-06-05 23:53:58 +02:00
local label_style = label.style
label_style.single_line = false
label_style.font_color = color or Color.comfy
end
)
end
---Message to a specific player
---@param player LuaPlayer
---@param duration number
2022-09-03 21:26:20 +02:00
---@param message string|table
2022-07-10 19:42:07 +02:00
---@param color string|nil
2020-07-06 15:45:09 +02:00
function Public.alert_player(player, duration, message, color, sprite, volume)
2020-06-05 23:53:58 +02:00
Public.alert_player_template(
player,
duration,
2024-06-04 23:27:12 +02:00
function (container)
2020-06-07 13:33:24 +02:00
container.add {
type = 'sprite-button',
2020-07-06 15:45:09 +02:00
sprite = sprite or 'achievement/you-are-doing-it-right',
2020-06-07 13:33:24 +02:00
style = 'slot_button'
}
2024-06-04 23:27:12 +02:00
local label = container.add({ type = 'label', name = close_alert_name, caption = message })
2020-06-07 13:33:24 +02:00
label.style.single_line = false
label.style.font_color = color or Color.comfy
2020-07-06 15:45:09 +02:00
end,
nil,
volume
2020-06-07 13:33:24 +02:00
)
end
---Message to a specific player as warning
---@param player LuaPlayer
---@param duration number
---@param message string|table
2022-09-03 21:26:20 +02:00
---@param color string|nil
2020-06-07 13:33:24 +02:00
function Public.alert_player_warning(player, duration, message, color)
Public.alert_player_template(
player,
duration,
2024-06-04 23:27:12 +02:00
function (container)
2020-06-07 13:33:24 +02:00
container.add {
type = 'sprite-button',
sprite = 'achievement/golem',
style = 'slot_button'
}
2024-06-04 23:27:12 +02:00
local label = container.add({ type = 'label', name = close_alert_name, caption = message })
2020-06-05 23:53:58 +02:00
label.style.single_line = false
label.style.font_color = color or Color.comfy
end
)
end
---Message to all players of a given force
---@param force LuaForce
---@param duration number
---@param message string|table
2020-06-05 23:53:58 +02:00
function Public.alert_force(force, duration, message)
local players = force.connected_players
for i = 1, #players do
local player = players[i]
Public.alert_player(player, duration, message)
end
end
---Message to all players
---@param duration number
2022-09-03 21:26:20 +02:00
---@param message string|table
2022-07-10 19:42:07 +02:00
---@param color string|nil
2020-07-06 15:45:09 +02:00
function Public.alert_all_players(duration, message, color, sprite, volume)
2020-06-05 23:53:58 +02:00
local players = game.connected_players
for i = 1, #players do
local player = players[i]
2020-07-06 15:45:09 +02:00
Public.alert_player(player, duration, message, color, sprite, volume)
2020-06-05 23:53:58 +02:00
end
end
2024-06-04 23:27:12 +02:00
Commands.new('notify_all_players', 'Usable only for admins - sends an alert message to all players!')
:add_parameter('message', false, 'string')
:callback(
function (player, message)
local comfy = '[color=blue]' .. player.name .. ':[/color] \n'
message = comfy .. message
Public.alert_all_players_location(player, message)
2020-06-05 23:53:58 +02:00
end
2024-06-04 23:27:12 +02:00
)
2020-06-05 23:53:58 +02:00
2024-06-04 23:27:12 +02:00
Commands.new('notify_player', 'Usable only for admins - sends an alert message to a player!')
:add_parameter('player', false, 'player-online')
:add_parameter('message', false, 'string')
:callback(
function (player, target_player, message)
if target_player then
local comfy = '[color=blue]' .. player.name .. ':[/color] \n'
message = comfy .. message
Public.alert_player_warning(target_player, 15, message)
2020-06-05 23:53:58 +02:00
end
end
2024-06-04 23:27:12 +02:00
)
2020-06-05 23:53:58 +02:00
return Public