1
0
mirror of https://github.com/ComfyFactory/ComfyFactorio.git synced 2024-12-30 23:17:53 +02:00
ComfyFactorio/modules/show_inventory.lua

526 lines
13 KiB
Lua

local Global = require 'utils.global'
local Color = require 'utils.color_presets'
local SpamProtection = require 'utils.spam_protection'
local Event = require 'utils.event'
local this = {
data = {},
module_disabled = false
}
local Public = {}
Global.register(
this,
function(tbl)
this = tbl
end
)
local space = {
minimal_height = 10,
top_padding = 0,
bottom_padding = 0
}
local function get_player_data(player, remove)
if remove and this.data[player.index] then
this.data[player.index] = nil
return
end
if not this.data[player.index] then
this.data[player.index] = {}
end
return this.data[player.index]
end
local function unpack_inventory(inventory)
if not inventory then
return
end
local unpacked = {}
for i = 1, #inventory do
unpacked[i] = inventory[i]
end
return unpacked
end
local function addStyle(guiIn, styleIn)
for k, v in pairs(styleIn) do
guiIn.style[k] = v
end
end
local function adjustSpace(guiIn)
addStyle(guiIn.add {type = 'line', direction = 'horizontal'}, space)
end
local function validate_object(obj)
if not obj then
return false
end
if not obj.valid then
return false
end
return true
end
local function get_target_player(index)
local viewingPlayer = game.get_player(index)
if not viewingPlayer or not viewingPlayer.valid then
return false
end
return viewingPlayer
end
local function watching_inventory(player)
for index, data in pairs(this.data) do
if data and data.player_opened == player.index then
local sourcePlayer = game.get_player(index)
if not sourcePlayer or not sourcePlayer.valid then
return false
else
return sourcePlayer
end
end
end
return false
end
local function player_opened(player)
local data = get_player_data(player)
if not data then
return false
end
local opened = data.player_opened
if not opened then
return false
end
return true, opened
end
local function last_tab(player)
local data = get_player_data(player)
if not data then
return false
end
local tab = data.last_tab
if not tab then
return false
end
return true, tab
end
local function validate_player(player)
if not player then
return false
end
if not player.valid then
return false
end
if not player.character then
return false
end
if not player.connected then
return false
end
if not game.players[player.index] then
return false
end
return true
end
local function close_player_inventory(player)
local data = get_player_data(player)
if not data then
return
end
local gui = player.gui.screen
if not validate_object(gui) then
return
end
local element = gui.inventory_gui
if not validate_object(element) then
return
end
element.destroy()
get_player_data(player, true)
end
local function redraw_inventory(gui, source, target, caption, panel_type)
gui.clear()
local items_table = gui.add({type = 'table', column_count = 11})
local types = game.item_prototypes
local screen = source.gui.screen
if not validate_object(screen) then
return
end
local inventory_gui = screen.inventory_gui
inventory_gui.caption = 'Inventory of ' .. target.name
for i = 1, #panel_type do
if panel_type[i] and panel_type[i].valid_for_read then
local name = panel_type[i].name
local count = panel_type[i].count
local flow = items_table.add({type = 'flow'})
flow.style.vertical_align = 'bottom'
local button =
flow.add(
{
type = 'sprite-button',
sprite = 'item/' .. name,
number = count,
name = name,
tooltip = types[name].localised_name,
style = 'slot_button'
}
)
button.enabled = false
if caption == 'Armor' then
if target.get_inventory(5)[1].grid then
local p_armor = target.get_inventory(5)[1].grid.get_contents()
for k, v in pairs(p_armor) do
local armor_gui =
flow.add(
{
type = 'sprite-button',
sprite = 'item/' .. k,
number = v,
name = k,
tooltip = types[name].localised_name,
style = 'slot_button'
}
)
armor_gui.enabled = false
end
end
end
end
end
end
local function add_inventory(panel, source, target, caption, panel_type)
local data = get_player_data(source)
data.panel_type = data.panel_type or {}
local pane_name = panel.add({type = 'tab', caption = caption, name = caption})
local scroll_pane =
panel.add {
type = 'scroll-pane',
name = caption .. 'tab',
direction = 'vertical',
vertical_scroll_policy = 'always',
horizontal_scroll_policy = 'never'
}
scroll_pane.style.maximal_height = 200
scroll_pane.style.horizontally_stretchable = true
scroll_pane.style.minimal_height = 200
scroll_pane.style.right_padding = 0
panel.add_tab(pane_name, scroll_pane)
data.panel_type[caption] = panel_type
redraw_inventory(scroll_pane, source, target, caption, panel_type)
end
local function open_inventory(source, target)
if not validate_player(source) then
return
end
source.opened = nil
if not validate_player(target) then
return
end
local screen = source.gui.screen
if not validate_object(screen) then
return
end
local inventory_gui = screen.inventory_gui
if inventory_gui then
close_player_inventory(source)
end
local frame =
screen.add(
{
type = 'frame',
caption = 'Inventory',
direction = 'vertical',
name = 'inventory_gui'
}
)
if not (frame and frame.valid) then
return
end
frame.auto_center = true
frame.style.minimal_width = 500
frame.style.minimal_height = 250
adjustSpace(frame)
local panel = frame.add({type = 'tabbed-pane', name = 'tabbed_pane'})
panel.selected_tab_index = 1
local data = get_player_data(source)
data.player_opened = target.index
data.last_tab = 'Main'
local main = unpack_inventory(target.get_main_inventory())
if not main then
return
end
local armor = unpack_inventory(target.get_inventory(defines.inventory.character_armor))
local guns = unpack_inventory(target.get_inventory(defines.inventory.character_guns))
local ammo = unpack_inventory(target.get_inventory(defines.inventory.character_ammo))
local trash = unpack_inventory(target.get_inventory(defines.inventory.character_trash))
local types = {
['Main'] = main,
['Armor'] = armor,
['Guns'] = guns,
['Ammo'] = ammo,
['Trash'] = trash
}
for k, v in pairs(types) do
if v ~= nil then
add_inventory(panel, source, target, k, v)
end
end
source.opened = frame
end
local function on_gui_click(event)
local player = game.players[event.player_index]
if not this.data[player.index] then
return
end
local element = event.element
if not element or not element.valid then
return
end
local types = {
['Main'] = true,
['Armor'] = true,
['Guns'] = true,
['Ammo'] = true,
['Trash'] = true
}
local name = element.name
if not types[name] then
return
end
local is_spamming = SpamProtection.is_spamming(player, nil, 'Player Inventory')
if is_spamming then
return
end
local data = get_player_data(player)
if not data then
return
end
data.last_tab = name
local valid, target = player_opened(player)
if valid and target then
local viewingPlayer = get_target_player(target)
if not viewingPlayer then
return false
end
local main = unpack_inventory(viewingPlayer.get_main_inventory())
if not main then
return
end
local armor = unpack_inventory(viewingPlayer.get_inventory(defines.inventory.character_armor))
local guns = unpack_inventory(viewingPlayer.get_inventory(defines.inventory.character_guns))
local ammo = unpack_inventory(viewingPlayer.get_inventory(defines.inventory.character_ammo))
local trash = unpack_inventory(viewingPlayer.get_inventory(defines.inventory.character_trash))
local target_types = {
['Main'] = main,
['Armor'] = armor,
['Guns'] = guns,
['Ammo'] = ammo,
['Trash'] = trash
}
local frame = Public.get_active_frame(player)
local panel_type = target_types[name]
redraw_inventory(frame, player, viewingPlayer, name, panel_type)
end
end
local function gui_closed(event)
local player = game.players[event.player_index]
if not this.data[player.index] then
return
end
local type = event.gui_type
if type == defines.gui_type.custom then
local data = get_player_data(player)
if not data then
return
end
close_player_inventory(player)
end
end
local function on_pre_player_left_game(event)
local player = game.players[event.player_index]
if not this.data[player.index] then
return
end
close_player_inventory(player)
end
local function update_gui(event)
local player = game.get_player(event.player_index)
if not player or not player.valid then
return
end
if not this.data[player.index] then
return
end
local sourcePlayer = watching_inventory(player)
local success, tab = last_tab(player)
if sourcePlayer and sourcePlayer.valid then
if success then
local main = player.get_main_inventory()
if not main then
return
end
main = unpack_inventory(player.get_main_inventory())
if not main then
return
end
local armor = unpack_inventory(player.get_inventory(defines.inventory.character_armor))
local guns = unpack_inventory(player.get_inventory(defines.inventory.character_guns))
local ammo = unpack_inventory(player.get_inventory(defines.inventory.character_ammo))
local trash = unpack_inventory(player.get_inventory(defines.inventory.character_trash))
local types = {
['Main'] = main,
['Armor'] = armor,
['Guns'] = guns,
['Ammo'] = ammo,
['Trash'] = trash
}
local frame = Public.get_active_frame(player)
local panel_type = types[tab]
if frame then
if frame.name == tab .. 'tab' then
redraw_inventory(frame, sourcePlayer, player, tab, panel_type)
end
end
end
end
end
commands.add_command(
'inventory',
'Opens a players inventory!',
function(cmd)
local player = game.player
if this.module_disabled then
return
end
if validate_player(player) then
if not cmd.parameter then
return
end
local target_player = game.players[cmd.parameter]
if target_player == player and not player.admin then
return player.print('Cannot open self.', Color.warning)
end
local valid, opened = player_opened(player)
if valid then
if target_player == opened then
return player.print('You are already viewing this players inventory.', Color.warning)
end
end
if validate_player(target_player) then
open_inventory(player, target_player)
else
player.print('[Inventory] Please type a name of a player who is connected.', Color.warning)
end
else
return
end
end
)
function Public.get_active_frame(player)
if not player.gui.screen.inventory_gui then
return false
end
return player.gui.screen.inventory_gui.tabbed_pane.tabs[player.gui.screen.inventory_gui.tabbed_pane.selected_tab_index].content
end
function Public.get(key)
if key then
return this[key]
else
return this
end
end
--- Disables the module.
---@param state boolean
function Public.module_disabled(state)
this.module_disabled = state or false
end
Event.add(defines.events.on_player_main_inventory_changed, update_gui)
Event.add(defines.events.on_gui_closed, gui_closed)
Event.add(defines.events.on_gui_click, on_gui_click)
Event.add(defines.events.on_pre_player_left_game, on_pre_player_left_game)
return Public