diff --git a/config/_file_loader.lua b/config/_file_loader.lua index bff9c441..e468afc2 100644 --- a/config/_file_loader.lua +++ b/config/_file_loader.lua @@ -51,6 +51,7 @@ return { 'modules.addons.report-jail', 'modules.addons.protection-jail', 'modules.addons.deconlog', + 'modules.addons.nukeprotect', --- Data 'modules.data.statistics', diff --git a/config/expcore/roles.lua b/config/expcore/roles.lua index a89b92cc..3f6dd512 100644 --- a/config/expcore/roles.lua +++ b/config/expcore/roles.lua @@ -224,7 +224,8 @@ Roles.new_role('Regular','Reg') 'command/go-to-spawn', 'command/me', 'standard-decon', - 'bypass-entity-protection' + 'bypass-entity-protection', + 'bypass-nukeprotect' } :set_auto_assign_condition(function(player) if player.online_time >= hours3 then diff --git a/config/nukeprotect.lua b/config/nukeprotect.lua new file mode 100644 index 00000000..26b919ca --- /dev/null +++ b/config/nukeprotect.lua @@ -0,0 +1,30 @@ +return { + inventories = { + { + inventory = defines.inventory.character_ammo, + event = defines.events.on_player_ammo_inventory_changed, + items = { + ["atomic-bomb"] = true + }, + }, + { + inventory = defines.inventory.character_armor, + event = defines.events.on_player_armor_inventory_changed, + items = {}, + }, + { + inventory = defines.inventory.character_guns, + event = defines.events.on_player_gun_inventory_changed, + items = {}, + }, + { + inventory = defines.inventory.character_main, + event = defines.events.on_player_main_inventory_changed, + items = { + ["atomic-bomb"] = true + }, + }, + }, + ignore_permisison = "bypass-nukeprotect", -- @setting ignore_permisison The permission that nukeprotect will ignore + ignore_admins = true, -- @setting ignore_admins Ignore admins, true by default. Allows usage outside of the roles module +} diff --git a/expcore/common.lua b/expcore/common.lua index 38d58e52..4cabdef4 100644 --- a/expcore/common.lua +++ b/expcore/common.lua @@ -6,7 +6,6 @@ local Colours = require 'utils.color_presets' --- @dep utils.color_presets local Game = require 'utils.game' --- @dep utils.game -local Util = require 'util' --- @dep util local Common = {} @@ -538,62 +537,65 @@ end --- Factorio. -- @section factorio ---[[-- Moves items to the position and stores them in the closest entity of the type given +--[[-- Copies items to the position and stores them in the closest entity of the type given -- Copies the items by prototype name, but keeps them in the original inventory -@tparam table items items which are to be added to the chests, ['name']=count -@tparam[opt=navies] LuaSurface surface the surface that the items will be moved to -@tparam[opt={0, 0}] table position the position that the items will be moved to {x=100, y=100} +@tparam table items items which are to be added to the chests, an array of LuaItemStack +@tparam[opt=navies] LuaSurface surface the surface that the items will be copied to +@tparam[opt={0, 0}] table position the position that the items will be copied to {x=100, y=100} @tparam[opt=32] number radius the radius in which the items are allowed to be placed -@tparam[opt=iron-chest] string chest_type the chest type that the items should be moved into +@tparam[opt=iron-chest] string chest_type the chest type that the items should be copied into @treturn LuaEntity the last chest that had items inserted into it @usage-- Copy all the items in a players inventory and place them in chests at {0, 0} -move_items(game.player.get_main_inventory().get_contents()) +copy_items_stack(game.player.get_main_inventory().get_contents()) ]] -function Common.move_items(items, surface, position, radius, chest_type) - chest_type = chest_type or 'iron-chest' - surface = surface or game.surfaces[1] - if position and type(position) ~= 'table' then return end - if type(items) ~= 'table' then return end - -- Finds all entities of the given type - local p = position or {x=0, y=0} - local r = radius or 32 - local entities = surface.find_entities_filtered{area={{p.x-r, p.y-r}, {p.x+r, p.y+r}}, name=chest_type} or {} - local count = #entities - local current = 1 - -- Makes a new empty chest when it is needed - local function make_new_chest() - local pos = surface.find_non_colliding_position(chest_type, position, 32, 1) - local chest = surface.create_entity{name=chest_type, position=pos, force='neutral'} - table.insert(entities, chest) - count = count + 1 - return chest - end - -- Function used to round robin the items into all chests - local function next_chest(item) - local chest = entities[current] - if count == 0 then return make_new_chest() end - if chest.get_inventory(defines.inventory.chest).can_insert(item) then - -- If the item can be inserted then the chest is returned - current = current+1 - if current > count then current = 1 end - return chest - else - -- Other wise it is removed from the list - table.remove(entities, current) - count = count - 1 - end - end - -- Inserts the items into the chests - local last_chest - for item_name, item_count in pairs(items) do - local chest = next_chest{name=item_name, count=item_count} - if not chest then return error(string.format('Cant move item %s to %s{%s, %s} no valid chest in radius', item_name, surface.name, p.x, p.y)) end - Util.insert_safe(chest, {[item_name]=item_count}) - last_chest = chest - end - return last_chest +function Common.copy_items_stack(items, surface, position, radius, chest_type) + chest_type = chest_type or 'iron-chest' + surface = surface or game.surfaces[1] + if position and type(position) ~= 'table' then return end + if type(items) ~= 'table' then return end + -- Finds all entities of the given type + local p = position or {x=0, y=0} + local r = radius or 32 + local entities = surface.find_entities_filtered{area={{p.x-r, p.y-r}, {p.x+r, p.y+r}}, name=chest_type} or {} + local count = #entities + local current = 1 + -- Makes a new empty chest when it is needed + local function make_new_chest() + local pos = surface.find_non_colliding_position(chest_type, position, 32, 1) + local chest = surface.create_entity{name=chest_type, position=pos, force='neutral'} + table.insert(entities, chest) + count = count + 1 + return chest + end + -- Function used to round robin the items into all chests + local function next_chest(item) + local chest = entities[current] + if count == 0 then return make_new_chest() end + if chest.get_inventory(defines.inventory.chest).can_insert(item) then + -- If the item can be inserted then the chest is returned + current = current+1 + if current > count then current = 1 end + return chest + else + -- Other wise it is removed from the list + table.remove(entities, current) + count = count - 1 + end + end + -- Inserts the items into the chests + local last_chest + for i=1,#items do + local item = items[i] + if item.valid_for_read then + local chest = next_chest(item) + if not chest or not chest.valid then return error(string.format('Cant move item %s to %s{%s, %s} no valid chest in radius', item.name, surface.name, p.x, p.y)) end + chest.insert(item) + last_chest = chest + end + end + return last_chest end --[[-- Moves items to the position and stores them in the closest entity of the type given @@ -606,7 +608,7 @@ end @treturn LuaEntity the last chest that had items inserted into it @usage-- Copy all the items in a players inventory and place them in chests at {0, 0} -move_items(game.player.get_main_inventory()) +move_items_stack(game.player.get_main_inventory()) ]] function Common.move_items_stack(items, surface, position, radius, chest_type) @@ -650,7 +652,9 @@ function Common.move_items_stack(items, surface, position, radius, chest_type) if item.valid_for_read then local chest = next_chest(item) if not chest or not chest.valid then return error(string.format('Cant move item %s to %s{%s, %s} no valid chest in radius', item.name, surface.name, p.x, p.y)) end - chest.insert(item) + local empty_stack = chest.get_inventory(defines.inventory.chest).find_empty_stack(item.name) + if not empty_stack then return error(string.format('Cant move item %s to %s{%s, %s} no valid chest in radius', item.name, surface.name, p.x, p.y)) end + empty_stack.transfer_stack(item) last_chest = chest end end diff --git a/locale/en/addons.cfg b/locale/en/addons.cfg index 1cac74dc..0bd2c2fa 100644 --- a/locale/en/addons.cfg +++ b/locale/en/addons.cfg @@ -83,3 +83,6 @@ jail=__1__ was jailed because they were reported too many times. Please wait for [protection-jail] jail=__1__ was jailed because they removed too many protected entities. Please wait for a moderator. + +[nukeprotect] +found=You cannot have __1__ in your inventory, so it was placed into the chests at spawn. diff --git a/modules/addons/nukeprotect.lua b/modules/addons/nukeprotect.lua new file mode 100644 index 00000000..c633e32b --- /dev/null +++ b/modules/addons/nukeprotect.lua @@ -0,0 +1,36 @@ +--- Disable new players from having certain items in their inventory, most commonly nukes +-- @addon Nukeprotect + +local Event = require 'utils.event' --- @dep utils.event +local Roles = require 'expcore.roles' --- @dep expcore.roles +local config = require 'config.nukeprotect' --- @dep config.nukeprotect +local move_items_stack = _C.move_items_stack --- @dep expcore.common + + +local function check_items(player, type) + -- if the player has perms to be ignored, then they should be + if config.ignore_permisison and Roles.player_allowed(player, config.ignore_permisison) then return end + -- if the players + if config.ignore_admins and player.admin then return end + + local inventory = player.get_inventory(type) + for i = 1, #inventory do + local item = inventory[i] + if item.valid and item.valid_for_read and config[tostring(type)][item.name] then + player.print({ "nukeprotect.found", { "item-name." .. item.name } }) + -- insert the items into the table so all items are transferred at once + move_items_stack({ item }) + end + end +end + +for _, inventory in ipairs(config.inventories) do + if #inventory.items > 0 then + Event.add(inventory.event, function(event) + local player = game.get_player(event.player_index) + if player and player.valid then + check_items(player, inventory.inventory) + end + end) + end +end