202 lines
7.7 KiB
Lua

---Handles the lua shortcut button or hotkey being triggered.
---@param event EventData.on_lua_shortcut|EventData.CustomInputEvent Event table
function on_lua_shortcut(event)
-- Exclude irrelevant lua shortcuts
if event.prototype_name and event.prototype_name ~= NAME.shortcut.button then return end
local player = game.get_player(event.player_index) --[[@as LuaPlayer]]
local cursor_stack = player.cursor_stack
-- Abort if player has no cursor stack as they are presumably a spectator
if not cursor_stack then return end
if player.is_cursor_blueprint() then
on_player_selected_blueprint(event)
else
local clear_cursor = player.clear_cursor()
if clear_cursor then
cursor_stack.set_stack({name=NAME.tool.ghost_counter})
end
end
end
script.on_event(defines.events.on_lua_shortcut, on_lua_shortcut)
script.on_event(NAME.input.ghost_counter_selection, on_lua_shortcut)
---Event handler for selection using GC tool
---@param event EventData.on_player_selected_area Event table
---@param ignore_tiles boolean Determines whether tiles are included in count
function on_player_selected_area(event, ignore_tiles)
if event.item ~= NAME.tool.ghost_counter then return end
local ghosts, requests = get_selection_counts(event.entities, ignore_tiles)
-- Open window only if there are non-zero ghost entities
if table_size(requests) > 0 then
local player_index = event.player_index
local playerdata = get_make_playerdata(player_index)
playerdata.job = {
area=event.area,
ghosts=ghosts,
requests=requests,
requests_sorted=sort_requests(requests)
}
update_one_time_logistic_requests(player_index)
update_inventory_info(player_index)
update_logistics_info(player_index)
Gui.toggle(player_index, true)
playerdata.luaplayer.clear_cursor()
end
end
script.on_event(defines.events.on_player_selected_area,
---@param event EventData.on_player_selected_area
function(event) on_player_selected_area(event, true) end)
script.on_event(defines.events.on_player_alt_selected_area,
---@param event EventData.on_player_selected_area
function(event) on_player_selected_area(event, false) end)
---Handles Ghost counter being activated with a blueprint in cursor.
---@param event EventData.on_lua_shortcut|EventData.CustomInputEvent Event table
function on_player_selected_blueprint(event)
local player_index = event.player_index
local playerdata = get_make_playerdata(player_index)
local entities = playerdata.luaplayer.get_blueprint_entities() or {}
local tiles = {}
if (playerdata.luaplayer.is_cursor_blueprint() and
playerdata.luaplayer.cursor_stack.valid_for_read) then
tiles = get_blueprint_tiles(playerdata.luaplayer.cursor_stack)
end
-- Abort if player not holding blueprint or empty blueprint
if not (entities and #entities > 0) and not (tiles and #tiles > 0) then return end
local requests = get_blueprint_counts(entities, tiles)
playerdata.job = {
area={},
ghosts={},
requests=requests,
requests_sorted=sort_requests(requests)
}
update_one_time_logistic_requests(player_index)
update_inventory_info(player_index)
update_logistics_info(player_index)
Gui.toggle(player_index, true)
end
---Updates playerdata.job.requests table as well as one-time requests to see if any can be
---considered fulfilled
---@param event EventData.on_player_main_inventory_changed Event table
function on_player_main_inventory_changed(event)
local playerdata = get_make_playerdata(event.player_index)
if not playerdata.is_active then return end
if playerdata.luaplayer.controller_type ~= defines.controllers.character then return end
register_update(playerdata.index, event.tick)
end
---Updates one-time logistic requests table as well as job.requests
---@param event EventData.on_entity_logistic_slot_changed Event table
function on_entity_logistic_slot_changed(event)
-- Exit if event does not involve a player character
if event.entity.type ~= "character" then return end
local player = event.entity.player or event.entity.associated_player
if not player then return end
local player_index = player.index
local playerdata = get_make_playerdata(player_index)
-- Iterate over known one-time logistic requests to see if the event concerns any of them
for name, request in pairs(playerdata.logistic_requests) do
if request.slot_index == event.slot_index then
if request.is_new then
request.is_new = false
return
else
playerdata.logistic_requests[name] = nil
end
break
end
end
register_update(player_index, event.tick)
end
---Triggers an update if the player respawns.
---@param event EventData.on_player_respawned Event data
function on_player_respawned(event)
local playerdata = get_make_playerdata(event.player_index)
if not playerdata.is_active then return end
register_update(playerdata.index, event.tick)
end
script.on_event(defines.events.on_player_respawned, on_player_respawned)
---Triggers an update if the player dies.
---@param event EventData.on_player_died Event data
function on_player_died(event)
local playerdata = get_make_playerdata(event.player_index)
if not playerdata.is_active then return end
register_update(playerdata.index, event.tick)
end
script.on_event(defines.events.on_player_died, on_player_died)
---Handles `on_entity_destroyed` by looking up `event.unit_number` in ghost tables and updates
---requests tables where appropriate
---@param event EventData.on_entity_destroyed Event table
function on_ghost_destroyed(event)
-- Since even ghost tiles have `unit_number`, exit if none is provided
if not event.unit_number then return end
-- Iterate over each player, and update their requests if they were tracking the entity
for player_index, playerdata in pairs(global.playerdata) do
if playerdata.is_active and playerdata.job.ghosts[event.unit_number] then
local items = playerdata.job.ghosts[event.unit_number]
for _, item in pairs(items) do
local request = playerdata.job.requests[item.name]
request.count = request.count - item.count
end
register_update(player_index, event.tick)
end
end
end
---Handles `on_nth_tick`—processes data for players who have had data updates. Aborts and
---unregisters itself if there were no data updates for any player since the previous function call
---@param event table Event table
function on_nth_tick(event)
-- If no data updates happened over the last 5 ticks, unregister nth_tick handler and exit
if event.tick - global.last_event > global.settings.min_update_interval then
register_nth_tick_handler(false)
return
end
-- Iterate over each player and process their data if they had updates
for player_index, playerdata in pairs(global.playerdata) do
-- If a player had registered data updates, reprocess their data
if playerdata.has_updates then
update_one_time_logistic_requests(player_index)
if playerdata.is_active then
update_inventory_info(player_index)
update_logistics_info(player_index)
Gui.update_list(player_index)
end
-- Reset `has_updates` boolean for that player
playerdata.has_updates = false
end
end
-- Check if event handlers can be unbound
if not is_inventory_monitoring_needed() then register_inventory_monitoring(false) end
if not is_logistics_monitoring_needed() then register_logistics_monitoring(false) end
end