diff --git a/config/_file_loader.lua b/config/_file_loader.lua index 5b0cb63a..78f7ab97 100644 --- a/config/_file_loader.lua +++ b/config/_file_loader.lua @@ -45,6 +45,7 @@ return { 'modules.commands.enemy', 'modules.commands.waterfill', 'modules.commands.artillery', + 'modules.commands.surface-clearing', --- Addons 'modules.addons.chat-popups', @@ -93,6 +94,7 @@ return { 'modules.gui.vlayer', 'modules.gui.research', 'modules.gui.module', + 'modules.gui.surveillance', 'modules.graftorio.require', -- graftorio --- Config Files diff --git a/config/expcore/roles.lua b/config/expcore/roles.lua index eabeb9c0..4ee94ee9 100644 --- a/config/expcore/roles.lua +++ b/config/expcore/roles.lua @@ -231,7 +231,10 @@ Roles.new_role('Member','Mem') 'command/manual-train', 'command/lawnmower', 'command/waterfill', - 'command/artillery-target-remote' + 'command/artillery-target-remote', + 'command/clear-item-on-ground', + 'command/clear-blueprint', + 'gui/surveillance' } local hours3, hours15 = 3*216000, 15*60 diff --git a/config/module.lua b/config/module.lua index 9b50224e..a2a8e906 100644 --- a/config/module.lua +++ b/config/module.lua @@ -1,6 +1,6 @@ return { -- type of machine to handle together - default_module_row_count = 4, + default_module_row_count = 6, module_slot_max = 4, machine_prod_disallow = { ['beacon'] = true diff --git a/modules/addons/tree-decon.lua b/modules/addons/tree-decon.lua index d4a2c206..6e7934d1 100644 --- a/modules/addons/tree-decon.lua +++ b/modules/addons/tree-decon.lua @@ -7,14 +7,24 @@ local Roles = require 'expcore.roles' --- @dep expcore.roles local Gui = require 'expcore.gui' --- @dep expcore.gui local PlayerData = require 'expcore.player_data' --- @dep expcore.player_data --- Global queue used to store trees that need to be removed, also chache for player roles -local chache = {} +-- Global queue used to store trees that need to be removed, also cache for player roles +local cache = {} local tree_queue = { _head=0 } -Global.register({tree_queue, chache}, function(tbl) +Global.register({tree_queue, cache}, function(tbl) tree_queue = tbl[1] - chache = tbl[2] + cache = tbl[2] end) +local function get_permission(player_index) + if cache[player_index] == nil then + local player = game.players[player_index] + if Roles.player_allowed(player, 'fast-tree-decon') then cache[player_index] = 'fast' + elseif Roles.player_allowed(player, 'standard-decon') then cache[player_index] = 'standard' + else cache[player_index] = player.force end + end + + return cache[player_index] +end -- Left menu button to toggle between fast decon and normal decon marking local HasEnabledDecon = PlayerData.Settings:combine('HasEnabledDecon') @@ -36,20 +46,14 @@ Event.add(defines.events.on_marked_for_deconstruction, function(event) -- Check which type of decon a player is allowed local index = event.player_index if not index then return end - if chache[index] == nil then - local player = game.players[index] - if Roles.player_allowed(player, 'fast-tree-decon') then chache[index] = 'fast' - elseif Roles.player_allowed(player, 'standard-decon') then chache[index] = 'standard' - else chache[index] = player.force end - end -- Check what should happen to this entity local entity = event.entity - local allow = chache[index] if not entity or not entity.valid then return end -- Not allowed to decon this entity local last_user = entity.last_user + local allow = get_permission(index) if last_user and allow ~= 'standard' and allow ~= 'fast' then entity.cancel_deconstruction(allow) return @@ -58,7 +62,6 @@ Event.add(defines.events.on_marked_for_deconstruction, function(event) -- Allowed to decon this entity, but not fast if allow ~= 'fast' then return end - local player = game.get_player(index) if not HasEnabledDecon:get(player) then return end @@ -91,9 +94,34 @@ Event.add(defines.events.on_tick, function() tree_queue._head = head end) --- Clear the chache +-- Clear the cache Event.on_nth_tick(300, function() - for key, _ in pairs(chache) do - chache[key] = nil + for key, _ in pairs(cache) do + cache[key] = nil end -end) \ No newline at end of file +end) + +-- Clear trees when hit with a car +Event.add(defines.events.on_entity_damaged, function(event) + if not (event.damage_type.name == 'impact' and event.force) then + return + end + + if not (event.entity.type == 'tree' or event.entity.type == 'simple-entity') then + return + end + + if (not event.cause) or (event.cause.type ~= 'car')then + return + end + + local driver = event.cause.get_driver() + if not driver then return end + + local allow = get_permission(driver.player.index) + if allow == "fast" and HasEnabledDecon:get(driver.player) then + event.entity.destroy() + else + event.entity.order_deconstruction(event.force, driver.player) + end +end) diff --git a/modules/commands/last-location.lua b/modules/commands/last-location.lua index b020efc4..44763a17 100644 --- a/modules/commands/last-location.lua +++ b/modules/commands/last-location.lua @@ -15,5 +15,5 @@ Commands.new_command('last-location', 'Sends you the last location of a player') :add_param('player', false, 'player') :register(function(player, action_player) local action_player_name_color = format_chat_player_name(action_player) - player.print{'expcom-lastlocation.response', action_player_name_color, action_player.position.x, action_player.position.y} -end) \ No newline at end of file + player.print{'expcom-lastlocation.response', action_player_name_color, string.format('%.1f', action_player.position.x), string.format('%.1f', action_player.position.y)} +end) diff --git a/modules/commands/surface-clearing.lua b/modules/commands/surface-clearing.lua new file mode 100644 index 00000000..99e4254a --- /dev/null +++ b/modules/commands/surface-clearing.lua @@ -0,0 +1,33 @@ +--[[-- Commands Module - Clear Item On Ground + - Adds a command that clear item on ground so blueprint can deploy safely + @commands Clear Item On Ground +]] + +local copy_items_stack = _C.copy_items_stack --- @dep expcore.common +local Commands = require 'expcore.commands' --- @dep expcore.commands +require 'config.expcore.command_general_parse' + +Commands.new_command('clear-item-on-ground', 'Clear Item On Ground') +:add_param('range', false, 'integer-range', 1, 1000) +:register(function(player, range) + for _, e in pairs(player.surface.find_entities_filtered{position=player.position, radius=range, name='item-on-ground'}) do + if e.stack then + -- calling move_items_stack(e.stack) will crash to desktop + -- https://forums.factorio.com/viewtopic.php?f=7&t=110322 + copy_items_stack{e.stack} + e.stack.clear() + end + end + + return Commands.success +end) + +Commands.new_command('clear-blueprint', 'Clear Blueprint') +:add_param('range', false, 'integer-range', 1, 1000) +:register(function(player, range) + for _, e in pairs(player.surface.find_entities_filtered{position=player.position, radius=range, type='entity-ghost'}) do + e.destroy() + end + + return Commands.success +end) \ No newline at end of file diff --git a/modules/gui/module.lua b/modules/gui/module.lua index 74470348..7cd5d94a 100644 --- a/modules/gui/module.lua +++ b/modules/gui/module.lua @@ -67,21 +67,36 @@ local function clear_module(player, area, machine) end end -local function apply_module(player, area, machine, module) +local function apply_module(player, area, machine, modules) for _, entity in pairs(player.surface.find_entities_filtered{area=area, name=machine, force=player.force}) do if config.machine_craft[machine] then local m_current_recipe = entity.get_recipe() if m_current_recipe ~= nil then if config.module_allowed[m_current_recipe.name] then - entity.surface.create_entity{name='item-request-proxy', target=entity, position=entity.position, force=entity.force, modules=module} end + entity.surface.create_entity{name='item-request-proxy', target=entity, position=entity.position, force=entity.force, modules=modules} + entity.last_user = player + + else + for k in pairs(modules) do + if k:find('productivity') then + modules[k:gsub('productivity', 'effectivity')] = modules[k] + modules[k] = nil + end + end + + entity.surface.create_entity{name='item-request-proxy', target=entity, position=entity.position, force=entity.force, modules=modules} + entity.last_user = player + end else - entity.surface.create_entity{name='item-request-proxy', target=entity, position=entity.position, force=entity.force, modules=module} + entity.surface.create_entity{name='item-request-proxy', target=entity, position=entity.position, force=entity.force, modules=modules} + entity.last_user = player end else - entity.surface.create_entity{name='item-request-proxy', target=entity, position=entity.position, force=entity.force, modules=module} + entity.surface.create_entity{name='item-request-proxy', target=entity, position=entity.position, force=entity.force, modules=modules} + entity.last_user = player end end end diff --git a/modules/gui/surveillance.lua b/modules/gui/surveillance.lua new file mode 100644 index 00000000..262ca2c0 --- /dev/null +++ b/modules/gui/surveillance.lua @@ -0,0 +1,173 @@ +---- module surveillance +-- @addon surveillance + +local Gui = require 'expcore.gui' --- @dep expcore.gui +local Roles = require 'expcore.roles' --- @dep expcore.roles +local Event = require 'utils.event' --- @dep utils.event + +local cctv_container + +local cctv_player = +Gui.element(function(name, parent, player_list) + return parent.add{ + name = name, + type = 'drop-down', + items = player_list, + selected_index = #player_list > 0 and 1 + } +end) +:style{ + horizontally_stretchable = true +} + +local cctv_type = +Gui.element{ + type = 'drop-down', + name = 'cctv_status', + items = {'Enable', 'Disable'}, + selected_index = 2 +}:style{ + width = 96 +}:on_selection_changed(function(_, element, _) + if element.selected_index == 1 then + element.parent.parent.parent.cctv_display.visible = true + else + element.parent.parent.parent.cctv_display.visible = false + end +end) + +local cctv_status = +Gui.element{ + type = 'drop-down', + name = 'cctv_status', + items = {'Player', 'Static'}, + selected_index = 1 +}:style{ + width = 96 +} + +local cctv_location = +Gui.element{ + type = 'button', + caption = 'set' +}:style{ + width = 48 +}:on_click(function(player, element, _) + element.parent.parent.parent.cctv_display.position = player.position +end) + +local zoom_in = +Gui.element{ + type = 'button', + caption = '+' +}:style{ + width = 32 +}:on_click(function(_, element, _) + local display = element.parent.parent.parent.cctv_display + if display.zoom < 2.0 then + display.zoom = display.zoom + 0.05 + end +end) + +local zoom_out = +Gui.element{ + type = 'button', + caption = '-' +}:style{ + width = 32 +}:on_click(function(_, element, _) + local display = element.parent.parent.parent.cctv_display + if display.zoom > 0.2 then + display.zoom = display.zoom - 0.05 + end +end) + +local camera_set = +Gui.element(function(_, parent, name, player_list) + local camera_set = parent.add{type='flow', direction='vertical', name=name} + local buttons = Gui.scroll_table(camera_set, 480, 6, 'buttons') + + cctv_player(buttons, player_list) + cctv_type(buttons) + cctv_status(buttons) + cctv_location(buttons) + zoom_out(buttons) + zoom_in(buttons) + + local camera = camera_set.add{ + type = 'camera', + name = 'cctv_display', + position = {x=0, y=0}, + surface_index = game.surfaces['nauvis'].index, + zoom = 0.75, + } + + camera.visible = false + camera.style.minimal_width = 480 + camera.style.minimal_height = 360 + return camera_set +end) + +cctv_container = +Gui.element(function(event_trigger, parent) + local container = Gui.container(parent, event_trigger, 480) + local scroll = container.add{name='scroll', type='scroll-pane', direction='vertical'} + scroll.style.maximal_height = 704 + local player_list = {} + + for _, player in pairs(game.connected_players) do + table.insert(player_list, player.name) + end + + camera_set(scroll, 'cctv_st_1', player_list) + camera_set(scroll, 'cctv_st_2', player_list) + + return container.parent +end) +:add_to_left_flow() + +Gui.left_toolbar_button('entity/radar', 'Surveillance GUI', cctv_container, function(player) + return Roles.player_allowed(player, 'gui/surveillance') +end) + +local function gui_update() + local player_list = {} + + for _, player in pairs(game.connected_players) do + table.insert(player_list, player.name) + end + + for _, player in pairs(game.connected_players) do + local frame = Gui.get_left_element(player, cctv_container) + frame.container.scroll['cctv_st_1'].buttons.table[cctv_player.name].items = player_list + frame.container.scroll['cctv_st_2'].buttons.table[cctv_player.name].items = player_list + end +end + +Event.add(defines.events.on_player_joined_game, gui_update) +Event.add(defines.events.on_player_left_game, gui_update) + +Event.add(defines.events.on_tick, function(_) + for _, player in pairs(game.connected_players) do + local frame = Gui.get_left_element(player, cctv_container) + + for i=1, 2 do + local scroll_table_name = 'cctv_st_' .. i + local current_camera_set = frame.container.scroll[scroll_table_name] + local switch_index = current_camera_set.buttons.table[cctv_status.name].selected_index + + if switch_index == 1 then + local selected_index = current_camera_set.buttons.table[cctv_player.name].selected_index + + if selected_index > 0 then + current_camera_set['cctv_display'].position = game.players[selected_index].position + current_camera_set['cctv_display'].surface_index = game.players[selected_index].surface_index + + else + current_camera_set['cctv_display'].position = {x=0, y=0} + current_camera_set['cctv_display'].surface_index = game.surfaces['nauvis'].index + end + end + end + end +end)