diff --git a/config.lua b/config.lua index 3a48d7a2..698c27dc 100644 --- a/config.lua +++ b/config.lua @@ -167,7 +167,7 @@ global.config = { -- prints messages when the player joins join_messages = { 'Welcome to this map created by the RedMew team. You can join our discord at: redmew.com/discord', - 'Click the question mark in the top left corner for server information and map details.' + 'Click the infomation icon in the top left corner for server information and map details.' }, cutscene = false, -- format is a table: {{message, weight}, {message, weight}}, where a higher weight has more chance to be shown diff --git a/locale/en/redmew_maps.cfg b/locale/en/redmew_maps.cfg index 692f05b0..9decba2b 100644 --- a/locale/en/redmew_maps.cfg +++ b/locale/en/redmew_maps.cfg @@ -126,3 +126,18 @@ switch_msg=Go ahead and pick a quadrant you'd like to help out! force_sync_research=New research complete: train_notice1=## - Your items have been returned to __1__ at: + +# locale linked to concrete jungle +[concrete_jungle] +welcome_popup_title=Welcome to Concrete jungle +welcome_popup_player_name=Hello __1__ +welcome_popup_line_1=Most items can't be placed on the ground! +welcome_popup_line_2=Place stone brick, concrete or reinforced concrete on the ground,\nbefore placing items and machines! +welcome_popup_line_3=More information can be found in the __1__ tab\nin __3__ __2__ + +blueprint=blueprint +blueprint_not_enough_ground_support=Some parts of this __1__ cannot be placed here, they need better ground support! +entity_not_enough_ground_support=__1__ requires at least: __2__ + +anti_grief_kick_reason=Spilling too many items on the ground +anti_grief_jail_reason=You have spilled too many items on the ground, contact an admin diff --git a/map_gen/maps/concrete_jungle.lua b/map_gen/maps/concrete_jungle.lua index 77becc33..4cd82634 100644 --- a/map_gen/maps/concrete_jungle.lua +++ b/map_gen/maps/concrete_jungle.lua @@ -7,6 +7,8 @@ local Color = require 'resources.color_presets' local Retailer = require 'features.retailer' local Task = require 'utils.task' local Popup = require 'features.gui.popup' +local Global = require 'utils.global' +local Report = require 'features.report' local redmew_config = global.config @@ -43,6 +45,16 @@ if concrete_unlocker then ) end +local times_spilled = {} +Global.register( + { + times_spilled = times_spilled + }, + function(tbl) + times_spilled = tbl.times_spilled + end +) + local ScenarioInfo = require 'features.gui.info' ScenarioInfo.set_map_name('Concrete Jungle') @@ -195,6 +207,7 @@ Thanks to Sangria_Louie for the map suggestion! ) RestrictEntities.set_tile_bp() +RestrictEntities.enable_spill() --- The logic for checking that there are the correct ground support under the entity's position RestrictEntities.set_keep_alive_callback( @@ -230,6 +243,56 @@ RestrictEntities.set_keep_alive_callback( ) ) +local clean_cursor_delay = + Token.register( + function(params) + params.player.clean_cursor() + end +) + +--- Anti griefing + +local anti_grief_tries = 3 -- Change this number to change how many 'shots' a player has got +local forgiveness_time = 432000 -- Time before previous offences are forgiven, in ticks (60 ticks/sec) +local anti_grief_kick_tries = math.ceil(anti_grief_tries / 2) -- Tries before kick warning + +RestrictEntities.set_anti_grief_callback( + Token.register( + function(_, player) + Popup.player(player, [[ +Look out! + +You are trying to replace entities which have items inside! +This is causing the items to spill out on the ground. + +Please be careful! +]], nil, nil, 'entity_placement_restriction_inventory_warning') + local player_stat = times_spilled[player.index] + local number_of_spilled = player_stat and player_stat.count or 0 + + local last_offence = player_stat and player_stat.tick or 0 + local time_since_last_offence = game.tick - last_offence + + if (last_offence > 0 and time_since_last_offence >= forgiveness_time) then + game.print('Forgiven!') + number_of_spilled = 0 + end + + if number_of_spilled >= anti_grief_tries then + Report.jail(player, nil) + player.print({'', '[color=yellow]', {'concrete_jungle.anti_grief_jail_reason'}, '[/color]'}) + Report.report(nil, player, 'Spilling too many items on the ground') + times_spilled[player.index] = nil + return + elseif number_of_spilled == anti_grief_kick_tries then + game.kick_player(player, {'concrete_jungle.anti_grief_kick_reason'}) + end + times_spilled[player.index] = {count = number_of_spilled + 1, tick = game.tick} + Task.set_timeout_in_ticks(1, clean_cursor_delay, {player = player}) + end + ) +) + local function print_floating_text(player, entity, text, color) color = color or Color.white local surface = player.surface @@ -259,17 +322,17 @@ local function on_destroy(event) if p and p.valid then if not (name == 'blueprint') then - local tier = '[tile=stone-path] stone path' + local tier = {'item-name.stone-path'} if (entity_tiers[name] == 2) then - tier = '[tile=concrete] concrete' + tier = {'item-name.concrete'} elseif (entity_tiers[name] == 3) then - tier = '[tile=refined-concrete] refined concrete' + tier = {'item-name.refined-concrete'} end - local text = '[item=' .. name .. '] requires at least ' .. tier + local text = {'concrete_jungle.entity_not_enough_ground_support', '[item=' .. name .. ']', tier} --local text = '[color=yellow]This [/color][item=' .. name .. '][color=yellow] cannot be placed here, it needs ground support of at least [/color]' .. tier print_floating_text(p, entity, text) else - p.print('[color=yellow]Some parts of this [/color][color=red]blueprint[/color][color=yellow] cannot be placed here, they need better ground support![/color]') + p.print({'', '[color=yellow]', {'concrete_jungle.blueprint_not_enough_ground_support', {'', '[/color][color=red]', {'concrete_jungle.blueprint'}, '[/color][color=yellow]'}}, '[/color]'}) end end end @@ -361,32 +424,44 @@ local function player_built_tile(event) end end -local function first_time(event) - local p = game.get_player(event.player_index) - Popup.player(p, '[color=yellow]Hello ' .. p.name .. '[/color]' .. -[[ - - -Most items can't be placed on the ground! - -Place stone brick, concrete or reinforced concrete on the ground, -before placing items and machines! - -More information can be found in the [color=red]Map Info[/color] tab -in [virtual-signal=signal-info] [color=red]Redmew Info[/color] -]], -'Welcome to Concrete Jungle', nil, 'concrete_jungle_intro') -end +local first_time = + Token.register( + function(params) + local p = game.get_player(params.event.player_index) + Popup.player( + p, + { + '', + '[color=yellow]', + {'concrete_jungle.welcome_popup_player_name', p.name}, + '[/color]\n\n', + {'concrete_jungle.welcome_popup_line_1'}, + '\n\n', + {'concrete_jungle.welcome_popup_line_2'}, + '\n\n', + {'concrete_jungle.welcome_popup_line_3', '[color=red]Map Info[/color]', '[color=red]Redmew Info[/color]', '[virtual-signal=signal-info]'} + }, + {'concrete_jungle.welcome_popup_title'}, + nil, + 'concrete_jungle_intro' + ) + end +) Event.add(RestrictEntities.events.on_pre_restricted_entity_destroyed, on_destroy) Event.add(defines.events.on_player_mined_tile, player_mined_tile) Event.add(defines.events.on_marked_for_deconstruction, marked_for_deconstruction) Event.add(defines.events.on_player_built_tile, player_built_tile) Event.add(defines.events.on_robot_built_tile, player_built_tile) -Event.add(defines.events.on_player_created, first_time) +Event.add( + defines.events.on_player_created, + function(event) + Task.set_timeout_in_ticks(900, first_time, {event = event}) + end +) Event.on_init(on_init) ---Creating the starting circle +--- Creating the starting circle (Map_gen) local circle = b.circle(6) local square = b.rectangle(3, 3) local concrete_square = b.change_tile(square, true, 'hazard-concrete-left') diff --git a/map_gen/shared/entity_placement_restriction.lua b/map_gen/shared/entity_placement_restriction.lua index ea84e558..ca14f3d1 100644 --- a/map_gen/shared/entity_placement_restriction.lua +++ b/map_gen/shared/entity_placement_restriction.lua @@ -44,8 +44,6 @@ local Event = require 'utils.event' local Global = require 'utils.global' local Token = require 'utils.token' local table = require 'utils.table' -local Popup = require 'features.gui.popup' -local Report = require 'features.report' -- Localized functions local raise_event = script.raise_event @@ -87,30 +85,65 @@ local primitives = { event = nil, -- if the event is registered or not refund = true, -- if we issue a refund or not prevent_tile_bp = false, -- prevents players from placing blueprints with tiles - keep_alive_callback = nil -- the function to process entities through + spill = false, -- spills items from entities with inventories to prevent destroying items when upgrading + keep_alive_callback = nil, -- the token registered function to process entities through + anti_grief_callback = nil -- the token registered function to process anti griefing through } -local times_spilled = {} Global.register( { allowed_entities = allowed_entities, banned_entities = banned_entities, - primitives = primitives, - times_spilled = times_spilled + primitives = primitives }, function(tbl) allowed_entities = tbl.allowed_entities banned_entities = tbl.banned_entities primitives = tbl.primitives - times_spilled = tbl.times_spilled end ) -- Local functions +--- Spill items stacks +-- @param entity the entity from which the items should be spilled +-- @param item the item stack that should be spilled local function spill_item_stack(entity, item) entity.surface.spill_item_stack(entity.position, item, true, entity.force, false) end +--- Checks if entity has an inventory with items inside, and spills them on the ground +local function entities_with_inventory(entity, player) + if primitives.spill and entity.has_items_inside() then + local type = entity.type + if type == 'container' or type == 'logistic-container' then + for item, count in pairs(entity.get_inventory(defines.inventory.chest).get_contents()) do + spill_item_stack(entity, {name = item, count = count}) + end + elseif type == 'furnace' then + for item, count in pairs(entity.get_inventory(defines.inventory.fuel).get_contents()) do + spill_item_stack(entity, {name = item, count = count}) + end + for item, count in pairs(entity.get_inventory(defines.inventory.furnace_result).get_contents()) do + spill_item_stack(entity, {name = item, count = count}) + end + for item, count in pairs(entity.get_inventory(defines.inventory.furnace_source).get_contents()) do + spill_item_stack(entity, {name = item, count = count}) + end + elseif type == 'assembling-machine' then + for item, count in pairs(entity.get_inventory(defines.inventory.assembling_machine_input).get_contents()) do + spill_item_stack(entity, {name = item, count = count}) + end + for item, count in pairs(entity.get_inventory(defines.inventory.assembling_machine_modules).get_contents()) do + spill_item_stack(entity, {name = item, count = count}) + end + for item, count in pairs(entity.get_inventory(defines.inventory.assembling_machine_output).get_contents()) do + spill_item_stack(entity, {name = item, count = count}) + end + end + + Token.get(primitives.anti_grief_callback)(entity, player) + end +end --- Token for the on_built event callback, checks if an entity should be destroyed. local on_built_token = @@ -170,49 +203,8 @@ local on_built_token = -- Need to revalidate the entity since we sent it to the raised event if entity.valid then - local type = entity.type - if entity.has_items_inside() then - if type == 'container' or type == 'logistic-container' then - for item, count in pairs(entity.get_inventory(defines.inventory.chest).get_contents()) do - spill_item_stack(entity, {name = item, count = count}) - end - elseif type == 'furnace' then - for item, count in pairs(entity.get_inventory(defines.inventory.fuel).get_contents()) do - spill_item_stack(entity, {name = item, count = count}) - end - for item, count in pairs(entity.get_inventory(defines.inventory.furnace_result).get_contents()) do - spill_item_stack(entity, {name = item, count = count}) - end - for item, count in pairs(entity.get_inventory(defines.inventory.furnace_source).get_contents()) do - spill_item_stack(entity, {name = item, count = count}) - end - elseif type == 'assembling-machine' then - for item, count in pairs(entity.get_inventory(defines.inventory.assembling_machine_input).get_contents()) do - spill_item_stack(entity, {name = item, count = count}) - end - for item, count in pairs(entity.get_inventory(defines.inventory.assembling_machine_modules).get_contents()) do - spill_item_stack(entity, {name = item, count = count}) - end - for item, count in pairs(entity.get_inventory(defines.inventory.assembling_machine_output).get_contents()) do - spill_item_stack(entity, {name = item, count = count}) - end - end - Popup.player(player, [[ -Look out! - -You are trying to replace entities which have items inside! -This is causing the items to spill out on the ground. - -Please be careful! -]], nil, nil, 'entity_placement_restriction_inventory_warning') - local number_of_spilled = times_spilled[player.index] or 0 - times_spilled[player.index] = number_of_spilled + 1 - if number_of_spilled >= 3 then - Report.jail(player, nil) - player.print('[color=yellow]You have spilled too many items on the ground, contact an admin[/color]') - Report.report(nil, player, 'Spilling too many items on the ground') - end - end + -- Checking if the entity has an inventory and spills the content on the ground to prevent destroying those too + entities_with_inventory(entity, player) entity.destroy() end @@ -275,6 +267,21 @@ function Public.remove_keep_alive_callback() check_event_status() end +--- Sets the anti_grief_callback function. This function is used to provide +-- logic on what entities should and should not be destroyed. +-- @param anti_grief_callback +function Public.set_anti_grief_callback(anti_grief_callback) + if type(anti_grief_callback) ~= 'number' then + error('Sending a non-token function') + end + primitives.anti_grief_callback = anti_grief_callback +end + +--- Removes the anti_grief_callback function +function Public.remove_anti_grief_callback() + primitives.anti_grief_callback = nil +end + --- Adds to the list of allowed entities -- @param ents array of string entity names function Public.add_allowed(ents) @@ -333,14 +340,24 @@ function Public.set_refund() primitives.refund = false end ---- Enables the returning of items that are destroyed by this module +--- Enables the ability to blueprint tiles (Landfill always enabled) function Public.enable_tile_bp() primitives.prevent_tile_bp = false end ---- Disables the returning of items that are destroyed by this module +--- Disables the ability to blueprint tiles (Landfill always enabled) function Public.set_tile_bp() primitives.prevent_tile_bp = true end +--- Enables the spill function +function Public.enable_spill() + primitives.spill = true +end + +--- Disables the spill function +function Public.set_spill() + primitives.spill = false +end + return Public