diff --git a/features/nuke_control.lua b/features/nuke_control.lua index 2cf34572..059dcc27 100644 --- a/features/nuke_control.lua +++ b/features/nuke_control.lua @@ -2,19 +2,62 @@ local Event = require 'utils.event' local Rank = require 'features.rank_system' local Utils = require 'utils.core' local Game = require 'utils.game' +local Task = require 'utils.task' +local Token = require 'utils.token' +local Global = require 'utils.global' local Server = require 'features.server' +local Report = require 'features.report' +local Popup = require 'features.gui.popup' local Ranks = require 'resources.ranks' local format = string.format local match = string.match -local function allowed_to_nuke(player) +local players_warned = {} +local entities_allowed_to_bomb = { + ['stone-wall'] = true, + ['transport-belt'] = true, + ['fast-transport-belt'] = true, + ['express-transport-belt'] = true, + ['construction-robot'] = true, + ['player'] = true, + ['gun-turret'] = true, + ['laser-turret'] = true, + ['flamethrower-turret'] = true, + ['rail'] = true, + ['rail-chain-signal'] = true, + ['rail-signal'] = true, + ['tile-ghost'] = true, + ['entity-ghost'] = true, + ['gate'] = true, + ['electric-pole'] = true, + ['small-electric-pole'] = true, + ['medium-electric-pole'] = true, + ['big-electric-pole'] = true, + ['logistic-robot'] = true, + ['defender'] = true, + ['destroyer'] = true, + ['distractor'] = true +} + +Global.register( + { + players_warned = players_warned, + entities_allowed_to_bomb = entities_allowed_to_bomb + }, + function(tbl) + players_warned = tbl.players_warned + entities_allowed_to_bomb = tbl.entities_allowed_to_bomb + end +) + +local function is_trusted(player) return Rank.equal_or_greater_than(player.name, Ranks.auto_trusted) end local function ammo_changed(event) local player = Game.get_player_by_index(event.player_index) - if allowed_to_nuke(player) then + if is_trusted(player) then return end local nukes = player.remove_item({name = 'atomic-bomb', count = 1000}) @@ -35,7 +78,7 @@ end local function on_player_deconstructed_area(event) local player = Game.get_player_by_index(event.player_index) - if allowed_to_nuke(player) then + if is_trusted(player) then return end player.remove_item({name = 'deconstruction-planner', count = 1000}) @@ -76,37 +119,6 @@ local function item_not_sanctioned(item) return (name:find('capsule') or name == 'cliff-explosives' or name == 'raw-fish' or name == 'discharge-defense-remote') end -global.nuke_control = { - entities_allowed_to_bomb = { - ['stone-wall'] = true, - ['transport-belt'] = true, - ['fast-transport-belt'] = true, - ['express-transport-belt'] = true, - ['construction-robot'] = true, - ['player'] = true, - ['gun-turret'] = true, - ['laser-turret'] = true, - ['flamethrower-turret'] = true, - ['rail'] = true, - ['rail-chain-signal'] = true, - ['rail-signal'] = true, - ['tile-ghost'] = true, - ['entity-ghost'] = true, - ['gate'] = true, - ['electric-pole'] = true, - ['small-electric-pole'] = true, - ['medium-electric-pole'] = true, - ['big-electric-pole'] = true, - ['logistic-robot'] = true, - ['defender'] = true, - ['destroyer'] = true, - ['distractor'] = true - }, - players_warned = {} -} -local entities_allowed_to_bomb = global.nuke_control.entities_allowed_to_bomb -local players_warned = global.nuke_control.players_warned - local function entity_allowed_to_bomb(entity) return entities_allowed_to_bomb[entity.name] end @@ -137,7 +149,7 @@ local function on_capsule_used(event) return end - if not allowed_to_nuke(player) then + if not is_trusted(player) then local area = {{event.position.x - 5, event.position.y - 5}, {event.position.x + 5, event.position.y + 5}} local count = 0 local entities = player.surface.find_entities_filtered {force = player.force, area = area} @@ -168,8 +180,78 @@ local function on_player_joined(event) end end +local train_to_manual = + Token.register( + function(train) + if train.valid then + train.manual_mode = true + end + end +) + +local function on_entity_died(event) + -- We only care if a train is killed by a member of its own force + local entity = event.entity + if (not entity or not entity.valid) or not entity.train or (event.force ~= entity.force) then + return + end + -- Check that an entity did the killing + local cause = event.cause + if not cause or not cause.valid then + return + end + -- Check that the entity was a train and in manual + local train = cause.train + if not train or not train.manual_mode then + return + end + -- Check if the train has passengers + local passengers = train.passengers + local num_passengers = #passengers + if num_passengers == 0 then + train.manual_mode = false -- if the train is in manual and has no passengers, stop it + Task.set_timeout_in_ticks(30, train_to_manual, train) + return + end + + -- Go through the passengers and punish any guests involved + local player_punished + local player_unpunished + local name_list = {} + for i = 1, num_passengers do + local player = passengers[i] + if player.valid then + if is_trusted(player) then + player_unpunished = true + name_list[#name_list + 1] = player.name + else + -- If they aren't allowed to nuke, stop the train and act accordingly. + player_punished = true + name_list[#name_list + 1] = player.name + player.driving = false + train.manual_mode = false + Task.set_timeout_in_ticks(30, train_to_manual, train) + if players_warned[player.index] and num_passengers == 1 then -- jail for later offenses if they're solely guilty + Report.jail(player) + Utils.print_admins({'nuke_control.train_jailing', player.name}) + else -- warn for first offense or if there's someone else in the train + players_warned[player.index] = true + Utils.print_admins({'nuke_control.train_warning', player.name}) + Popup.player(player, {'nuke_control.train_player_warning'}) + end + end + end + end + + -- If there was a passenger who was unpunished along with a punished passenger, let the admins know + if player_punished and player_unpunished then + local name_string = table.concat(name_list, ', ') + Utils.print_admins({'nuke_control.multiple_passengers', num_passengers, name_string}) + end +end + Event.add(defines.events.on_player_ammo_inventory_changed, ammo_changed) Event.add(defines.events.on_player_joined_game, on_player_joined) Event.add(defines.events.on_player_deconstructed_area, on_player_deconstructed_area) ---Event.add(defines.events.on_player_mined_entity, on_player_mined_item) Event.add(defines.events.on_player_used_capsule, on_capsule_used) +Event.add(defines.events.on_entity_died, on_entity_died) diff --git a/locale/en/redmew.cfg b/locale/en/redmew.cfg index c08194fb..95dd9091 100644 --- a/locale/en/redmew.cfg +++ b/locale/en/redmew.cfg @@ -38,3 +38,12 @@ toast_message=The end times are here. The four biters of the apocalypse have bee [toast] toast_all=__1__ sent a toast to all players. toast_player=__1__ sent a toast to __2__. + +[nuke_control] +train_warning=__1__ used a train to destroy another train and has been warned. +train_player_warning=You have destroyed another train with yours.\nRepeated infractions will be punished. +train_jailing=__1__ used a train to destroy another train and has been jailed. +multiple_passengers=Note: There were __1__ players in the train and any could have been controlling it: __2__ + +[utils_core] +print_admins=__1__(ADMIN) __2__: __3__ diff --git a/utils/core.lua b/utils/core.lua index c43937fb..d8bdc6b3 100644 --- a/utils/core.lua +++ b/utils/core.lua @@ -65,8 +65,8 @@ function Module.print_admins(msg, source) source_name = 'Server' chat_color = Color.yellow end - local formatted_msg = format('%s(ADMIN) %s: %s', prefix, source_name, msg) -- to the server - print(formatted_msg) + local formatted_msg = {'utils_core.print_admins',prefix, source_name, msg} + log(formatted_msg) for _, p in pairs(game.connected_players) do if p.admin then p.print(formatted_msg, chat_color)