diff --git a/maps/mountain_fortress_v3/charging_station.lua b/maps/mountain_fortress_v3/charging_station.lua index 05599e06..f3f22dc8 100644 --- a/maps/mountain_fortress_v3/charging_station.lua +++ b/maps/mountain_fortress_v3/charging_station.lua @@ -62,6 +62,9 @@ local function charge(player) if not player.character then return player.print(module_name .. 'It seems that you are not in the realm of living.', { color = Color.warning }) end + if player.controller_type == defines.controllers.remote then + return player.print(module_name .. 'It seems that you are not in the realm of living.', { color = Color.warning }) + end local armor_inventory = player.get_inventory(defines.inventory.character_armor) if not armor_inventory.valid then return player.print(module_name .. 'No valid armor to charge was found.', { color = Color.warning }) diff --git a/maps/mountain_fortress_v3/functions.lua b/maps/mountain_fortress_v3/functions.lua index 06880c4f..ccddb177 100644 --- a/maps/mountain_fortress_v3/functions.lua +++ b/maps/mountain_fortress_v3/functions.lua @@ -912,11 +912,17 @@ remove_boost_movement_speed_on_respawn = return end + Modifiers.update_single_modifier(player, 'character_running_speed_modifier', 'v3_move_boost') Modifiers.update_player_modifiers(player) + if not Public.is_task_done() then return end player.print('Movement speed bonus removed!', { color = Color.info }) local rpg_t = RPG.get_value_from_player(player.index) + if not rpg_t then + return + end + rpg_t.has_boost_on_respawn = nil end ) diff --git a/maps/mountain_fortress_v3/icw/commands.lua b/maps/mountain_fortress_v3/icw/commands.lua new file mode 100644 index 00000000..2136c644 --- /dev/null +++ b/maps/mountain_fortress_v3/icw/commands.lua @@ -0,0 +1,22 @@ +local ICW = require 'maps.mountain_fortress_v3.icw.table' +local ICW_Func = require 'maps.mountain_fortress_v3.icw.functions' +local Discord = require 'utils.discord_handler' +local Commands = require 'utils.commands' +local mapkeeper = '[color=blue]Mapkeeper:[/color]' + +Commands.new('icw_reconnect_train', 'Usable only for admins - reconnects all trains!') + :require_admin() + :require_validation() + :callback( + function (player) + local icw = ICW.get() + local suc = ICW_Func.reconstruct_all_trains(icw) + Discord.send_notification_raw(ICW.discord_name, player.name .. ' is reconnecting all trains via icw module.') + if suc then + player.print(mapkeeper .. 'All trains have been reconnected!') + else + player.print(mapkeeper .. 'Failed to reconnect all trains!') + end + return true + end + ) diff --git a/maps/mountain_fortress_v3/icw/functions.lua b/maps/mountain_fortress_v3/icw/functions.lua index fd4295e7..0bc3e7aa 100644 --- a/maps/mountain_fortress_v3/icw/functions.lua +++ b/maps/mountain_fortress_v3/icw/functions.lua @@ -448,7 +448,7 @@ local function get_wagon_for_entity(icw, entity) end local position = entity.position - for k, unit_number in pairs(train.wagons) do + for _, unit_number in pairs(train.wagons) do local wagon = icw.wagons[unit_number] if wagon then local left_top = wagon.area.left_top @@ -972,6 +972,7 @@ function Public.reconstruct_all_trains(icw) Public.construct_train(icw, locomotive, carriages) end delete_empty_surfaces(icw) + return true end function Public.item_transfer() diff --git a/maps/mountain_fortress_v3/icw/main.lua b/maps/mountain_fortress_v3/icw/main.lua index 801a5fec..7b800309 100644 --- a/maps/mountain_fortress_v3/icw/main.lua +++ b/maps/mountain_fortress_v3/icw/main.lua @@ -1,3 +1,5 @@ +require 'maps.mountain_fortress_v3.icw.commands' + local Event = require 'utils.event' local Functions = require 'maps.mountain_fortress_v3.icw.functions' local ICW = require 'maps.mountain_fortress_v3.icw.table' diff --git a/maps/mountain_fortress_v3/icw/table.lua b/maps/mountain_fortress_v3/icw/table.lua index ecf98f2e..e6d82f44 100644 --- a/maps/mountain_fortress_v3/icw/table.lua +++ b/maps/mountain_fortress_v3/icw/table.lua @@ -3,13 +3,16 @@ local Global = require 'utils.global' local this = {} Global.register( this, - function(tbl) + function (tbl) this = tbl end ) local Public = {} +local discord_name = 'Mtn Fortress' +Public.discord_name = discord_name + function Public.reset() if this.surfaces then for _, surface in pairs(this.surfaces) do @@ -39,10 +42,10 @@ function Public.reset() } this.wagon_areas = { - ['cargo-wagon'] = {left_top = {x = -40, y = 0}, right_bottom = {x = 40, y = 100}}, - ['artillery-wagon'] = {left_top = {x = -40, y = 0}, right_bottom = {x = 40, y = 100}}, - ['fluid-wagon'] = {left_top = {x = -40, y = 0}, right_bottom = {x = 40, y = 100}}, - ['locomotive'] = {left_top = {x = -40, y = 0}, right_bottom = {x = 40, y = 100}} + ['cargo-wagon'] = { left_top = { x = -40, y = 0 }, right_bottom = { x = 40, y = 100 } }, + ['artillery-wagon'] = { left_top = { x = -40, y = 0 }, right_bottom = { x = 40, y = 100 } }, + ['fluid-wagon'] = { left_top = { x = -40, y = 0 }, right_bottom = { x = 40, y = 100 } }, + ['locomotive'] = { left_top = { x = -40, y = 0 }, right_bottom = { x = 40, y = 100 } } } end diff --git a/modules/autostash.lua b/modules/autostash.lua index 59a91642..4ed28902 100644 --- a/modules/autostash.lua +++ b/modules/autostash.lua @@ -795,7 +795,11 @@ Gui.on_click( end local player = event.player if not player or not player.valid or not player.character then - return + return player.print(module_name .. 'It seems that you are not in the realm of living.', { color = Color.warning }) + end + + if player.controller_type == defines.controllers.remote then + return player.print(module_name .. 'It seems that you are not in the realm of living.', { color = Color.warning }) end auto_stash(event.player, event) diff --git a/modules/rpg/functions.lua b/modules/rpg/functions.lua index b386be56..4d4ffbe7 100644 --- a/modules/rpg/functions.lua +++ b/modules/rpg/functions.lua @@ -375,6 +375,10 @@ function Public.remove_mana(player, mana_to_remove) return end + if not Public.check_is_surface_valid(player) then + return + end + if not mana_to_remove then return end @@ -425,6 +429,10 @@ function Public.update_mana(player) return end + if not Public.check_is_surface_valid(player) then + return + end + if not rpg_t then return end @@ -527,6 +535,10 @@ function Public.update_health(player) return end + if not Public.check_is_surface_valid(player) then + return + end + if not rpg_t then return end @@ -1338,12 +1350,12 @@ function Public.check_is_surface_valid(player) local surface_name = Public.get('rpg_extra').surface_name if type(surface_name) == 'table' then for _, tbl_surface in pairs(surface_name) do - if sub(player.surface.name, 0, #tbl_surface) == tbl_surface then + if sub(player.physical_surface.name, 0, #tbl_surface) == tbl_surface then is_surface_valid = true end end else - if sub(player.surface.name, 0, #surface_name) ~= surface_name then + if sub(player.physical_surface.name, 0, #surface_name) ~= surface_name then return false else return true diff --git a/modules/rpg/main.lua b/modules/rpg/main.lua index 7bca64d8..cc94af52 100644 --- a/modules/rpg/main.lua +++ b/modules/rpg/main.lua @@ -749,6 +749,8 @@ local function on_player_crafted_item(event) local final_xp = recipe.energy * amount local get_dex_modifier = Public.get_dex_modifier(player) + if not get_dex_modifier then return end + if get_dex_modifier >= 10 then local chance = Public.get_crafting_bonus_chance(player) * 10 local r = random(0, 1999) diff --git a/utils/commands.lua b/utils/commands.lua index 52c41c12..8cdeab74 100644 --- a/utils/commands.lua +++ b/utils/commands.lua @@ -117,7 +117,7 @@ local function execute(event) player = game.get_player(event.player_index) else player = { - name = 'Server', + name = '', position = { x = 0, y = 0 }, surface = game.get_surface('nauvis'), force = game.forces.player, @@ -267,6 +267,18 @@ local function execute(event) handled_parameters[index] = player_data index = index + 1 end + if param_data.as_type == 'surface' and param ~= nil then + local surface_name = param + if type(surface_name) ~= 'string' then + return reject('Inputted value is not of type string. Valid values are: "string"') + end + local surface_data = game.get_surface(surface_name) --[[@type LuaSurface]] + if not surface_data then + return reject('Surface was not found.') + end + handled_parameters[index] = surface_data + index = index + 1 + end if param_data.as_type == 'player-online' and param ~= nil then local player_name = param if type(player_name) ~= 'string' then @@ -345,7 +357,6 @@ local function execute(event) end -- Run the command callback if everything is validated - handled_parameters[#handled_parameters + 1] = input_text local callback = Task.get(command_data.callback) local success, err = pcall(callback, player, unpack(handled_parameters)) if internal_error(success, command_data.name, err) then diff --git a/utils/commands/misc.lua b/utils/commands/misc.lua index 44ffab87..9983cc7b 100644 --- a/utils/commands/misc.lua +++ b/utils/commands/misc.lua @@ -10,6 +10,8 @@ local Gui = require 'utils.gui' local SpamProtection = require 'utils.spam_protection' local Discord = require 'utils.discord_handler' local Commands = require 'utils.commands' +local mapkeeper = '[color=blue]Mapkeeper:[/color]' +local Task = require 'utils.task_token' local this = { enabled = true, @@ -24,28 +26,191 @@ Global.register( end ) -local Public = { -} +local Public = {} local clear_corpse_button_name = Gui.uid_name() +local floor = math.floor -Commands.new('playtime', 'Fetches a player total playtime or nil.') +local clear_chunk_token = + Task.register( + function (event) + local chunk = event.chunk + if not chunk then + return + end + + local surface = game.get_surface(event.surface_index) + if not surface or not surface.valid then + return + end + + if chunk and #chunk > 2 then + for _, c in pairs(chunk) do + surface.delete_chunk(c) + end + else + surface.delete_chunk(chunk) + end + end + ) + +local remove_offline_players_token = + Task.register( + function (event) + local list = event.list + if not list then + return + end + game.remove_offline_players(list) + end + ) + +local function tick_to_hours(t) + local seconds = t * 60 + local minutes = floor((seconds) * 60) + return floor((minutes) * 60) +end + +local function hours_to_tick(t) + local seconds = t / 60 + local minutes = floor((seconds) / 60) + return floor((minutes) / 60) +end + +Commands.new('clear_all_enemies', 'Iterates over the current player surface and removes all generated enemies.') + :require_admin() + :require_validation("This will remove all enemies from the map.") + :add_parameter('surface', true, 'surface') + :add_parameter('force', true, 'string') + :callback( + function (player, surface_arg, force_arg) + local surface = surface_arg or player.surface + local force = force_arg or 'enemy' + local count = 0 + for c in surface.get_chunks() do + for _, entity in pairs(surface.find_entities_filtered({ area = { { c.x * 32, c.y * 32 }, { c.x * 32 + 32, c.y * 32 + 32 } }, force = force })) do + if entity and entity.valid then + entity.destroy() + count = count + 1 + end + end + end + if count == 0 then + player.print('No enemies to remove were found!') + return false + end + + game.print(mapkeeper .. ' ' .. player.name .. ' removed ' .. count .. ' enemies.') + Discord.send_notification_raw(nil, player.name .. ' removed ' .. count .. ' enemies.') + return true + end + ) + +Commands.new('remove_chunks', 'Iterates over a surface and removes chunks that are charted but does not have any player entitie.') + :require_validation("This will remove all chunks that are charted but does not have any player entities.") + :require_admin() + :add_parameter('force', true, 'string') + :callback( + function (player, args) + local surface = player.surface + local chunks = surface.get_chunks() + local tick = 0 + local force = args or player.force.name + + local chunks_to_remove = {} + + for chunk in chunks do + if surface.is_chunk_generated(chunk) then + local area = { + left_top = { chunk.area.left_top.x - 64, chunk.area.left_top.y - 64 }, + right_bottom = { chunk.area.right_bottom.x + 64, chunk.area.right_bottom.y + 64 } + } + + local ents = surface.find_entities_filtered { area = area, force = { force } } + local total_count = #ents + + if total_count <= 0 then + chunks_to_remove[#chunks_to_remove + 1] = chunk + end + end + if chunks_to_remove and #chunks_to_remove >= 10 then + tick = tick + 2 + Task.set_timeout_in_ticks(tick, clear_chunk_token, + { chunk = chunks_to_remove, surface_index = surface.index }) + + chunks_to_remove = {} + end + end + + game.print(mapkeeper .. ' ' .. player.name .. ' scheduled ' .. surface.name .. ' for chunk removal.') + Discord.send_notification_raw(nil, player.name .. ' scheduled ' .. surface.name .. ' for chunk removal.') + return true + end + ) + +Commands.new('remove_offline_players', 'Remove offline players.') + :require_validation("This will remove offline players that has not connected in the given hours.") + :add_parameter('hours', false, "number") + :require_admin() + :callback( + function (player, hours) + local surface = player.surface + local remove_players = {} + local tick = 0 + local count = 0 + local converted_hours = tick_to_hours(hours) + local converted_game_tick = hours_to_tick(game.tick) + + if game.tick < converted_hours then + player.print('Cannot remove players that has not been offline for less than ' .. hours .. ' hours when the server has been running for ' .. converted_game_tick .. ' hours.') + return false + end + + for _, p in pairs(game.players) do + if p.last_online < converted_hours then + count = count + 1 + remove_players[#remove_players + 1] = p.name + + if remove_players and #remove_players >= 10 then + tick = tick + 2 + Task.set_timeout_in_ticks(tick, remove_offline_players_token, + { list = remove_players }) + + remove_players = {} + end + end + end + + + local message = player.name .. ' scheduled ' .. surface.name .. ' for offline player removal of count: ' .. count .. '.' + game.print(mapkeeper .. ' ' .. message) + Discord.send_notification_raw(nil, message) + return true + end + ) + +Commands.new('playtime', 'Gets a single player total playtime or nil.') :require_backend() :add_parameter('target', false, 'string') :callback( function (player, target) Session.get_and_print_to_player(player, target) + return true end ) Commands.new('refresh', 'Reloads game script') :require_admin() + :require_validation("Running this command will freeze the server if run in multiplayer.") + :add_alias('reload') :callback( - function () + function (player) game.print('Reloading game script...', Color.warning) - Server.to_discord_bold('Reloading game script...') + Server.to_discord_bold(player.name .. ' is reloading the game script.') + Discord.send_notification_raw(nil, player.name .. ' is reloading the game script.') game.reload_script() + return true end ) @@ -75,6 +240,7 @@ Commands.new('spaghetti', 'Toggle between disabling bots.') force.technologies['worker-robots-speed-5'].enabled = false force.technologies['worker-robots-speed-6'].enabled = false this.spaghetti_enabled = true + return true elseif args == 'false' then game.print('The world is no longer spaghett!', Color.yellow) force.technologies['logistic-system'].enabled = true @@ -93,7 +259,9 @@ Commands.new('spaghetti', 'Toggle between disabling bots.') force.technologies['worker-robots-speed-5'].enabled = true force.technologies['worker-robots-speed-6'].enabled = true this.spaghetti_enabled = false + return true end + return false end ) @@ -106,7 +274,7 @@ Commands.new('generate_map', 'Pregenerates map.') local radius = args local surface = player.surface if surface.is_chunk_generated({ radius, radius }) then - player.print('Map generation done') + player.print('Map generation is already generated') return true end surface.request_to_generate_chunks({ 0, 0 }, radius) @@ -115,6 +283,7 @@ Commands.new('generate_map', 'Pregenerates map.') pl.play_sound { path = 'utility/new_objective', volume_modifier = 1 } end player.print('Map generation done') + return true end ) diff --git a/utils/datastore/jail_data.lua b/utils/datastore/jail_data.lua index 22882db8..375dcffd 100644 --- a/utils/datastore/jail_data.lua +++ b/utils/datastore/jail_data.lua @@ -558,7 +558,7 @@ local function vote_to_jail(player, offender, msg) return end - if type(offender) == 'table' then + if type(offender) == 'userdata' then offender = offender.name end @@ -586,7 +586,7 @@ local function vote_to_free(player, offender) return end - if type(offender) == 'table' then + if type(offender) == 'userdata' then offender = offender.name end diff --git a/utils/game.lua b/utils/game.lua index 5660fd0a..15f8061e 100644 --- a/utils/game.lua +++ b/utils/game.lua @@ -6,7 +6,7 @@ local Game = {} local bad_name_players = {} Global.register( bad_name_players, - function(tbl) + function (tbl) bad_name_players = tbl end ) @@ -53,7 +53,7 @@ function Game.get_player_from_any(obj) p = Game.get_player_by_index(obj) elseif o_type == 'string' then p = game.players[obj] - elseif o_type == 'table' and obj.valid and obj.is_player() then + elseif o_type == 'userdata' and obj.valid and obj.is_player() then return obj end @@ -72,7 +72,7 @@ function Game.player_print(str) end function Game.get_player(mixed) - if type(mixed) == 'table' then + if type(mixed) == 'userdata' then if mixed.__self then return mixed and mixed.valid and mixed elseif mixed.player_index then @@ -120,7 +120,7 @@ function Game.print_player_floating_text_position(player_index, text, color, x_o end local position = player.position - return Game.print_floating_text(player.surface, {x = position.x + x_offset, y = position.y + y_offset}, text, color) + return Game.print_floating_text(player.surface, { x = position.x + x_offset, y = position.y + y_offset }, text, color) end function Game.print_player_floating_text(player_index, text, color) diff --git a/utils/gui/poll.lua b/utils/gui/poll.lua index 87227e00..4c12257a 100644 --- a/utils/gui/poll.lua +++ b/utils/gui/poll.lua @@ -829,7 +829,7 @@ local function tick() local player_index = p.index local tbl = player_create_poll_data[player_index] if tbl then - for k, element in pairs(tbl) do + for _, element in pairs(tbl) do if type(element) == 'table' then if not element.valid then player_create_poll_data[player_index] = nil diff --git a/utils/server.lua b/utils/server.lua index d1ff8a3f..8449d76b 100644 --- a/utils/server.lua +++ b/utils/server.lua @@ -1148,11 +1148,10 @@ function Public.export_stats() } for _, statName in pairs(statistics) do - flow_statistics[statName] = { - [surface.name] = { - input = force[statName](surface).input_counts, - output = force[statName](surface).output_counts - }, + local surface_stats = flow_statistics[statName] or {} + surface_stats[surface.name] = { + input = force[statName](surface).input_counts, + output = force[statName](surface).output_counts } end end