mirror of
https://github.com/Refactorio/RedMew.git
synced 2025-03-17 21:08:08 +02:00
Merge pull request #991 from SimonFlapse/concrete_jungle
Concrete Jungle - the map is complete, only remaining things to do are are - migrate description to wiki - add cutscene - bring into regular map rotation (this is an interesting map that we should run more often)
This commit is contained in:
commit
f474b562af
@ -169,7 +169,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
|
||||
|
@ -154,3 +154,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
|
||||
|
BIN
map_gen/data/.map_previews/concrete_jungle.png
Normal file
BIN
map_gen/data/.map_previews/concrete_jungle.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 967 KiB |
503
map_gen/maps/concrete_jungle.lua
Normal file
503
map_gen/maps/concrete_jungle.lua
Normal file
@ -0,0 +1,503 @@
|
||||
local floor = math.floor
|
||||
local RestrictEntities = require 'map_gen.shared.entity_placement_restriction'
|
||||
local Event = require 'utils.event'
|
||||
local b = require 'map_gen.shared.builders'
|
||||
local Token = require 'utils.token'
|
||||
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 Rank = require 'features.rank_system'
|
||||
local Ranks = require 'resources.ranks'
|
||||
|
||||
local redmew_config = global.config
|
||||
|
||||
-- Needed because refined hazard concrete is needed and must not be changed by this module
|
||||
redmew_config.paint.enabled = false
|
||||
|
||||
local concrete_unlocker = true -- Set to false to disable early unlocking of concrete
|
||||
|
||||
local market_remove_concrete =
|
||||
Token.register(
|
||||
function()
|
||||
Retailer.remove_item('fish_market', 'refined-hazard-concrete')
|
||||
end
|
||||
)
|
||||
|
||||
local function on_init() --Out comment stuff you don't want to enable
|
||||
game.difficulty_settings.technology_price_multiplier = 4
|
||||
--game.forces.player.technologies.logistics.researched = true
|
||||
game.forces.player.technologies.automation.researched = true
|
||||
Task.set_timeout_in_ticks(100, market_remove_concrete)
|
||||
end
|
||||
|
||||
if concrete_unlocker then
|
||||
Event.add(
|
||||
defines.events.on_research_finished,
|
||||
function(event)
|
||||
local p_force = game.forces.player
|
||||
local r = event.research
|
||||
|
||||
if r.name == 'advanced-material-processing' then
|
||||
p_force.recipes['concrete'].enabled = true
|
||||
end
|
||||
end
|
||||
)
|
||||
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')
|
||||
ScenarioInfo.set_map_description([[
|
||||
Extensive underground mining has resulted in brittle soil.
|
||||
New regulations requires that heavy objects are placed
|
||||
on top of proper materials, to support the ground!
|
||||
]])
|
||||
|
||||
-- Tiers of tiles definition (tier 0 is default)
|
||||
local tile_tiers = {
|
||||
['stone-path'] = 1,
|
||||
['concrete'] = 2,
|
||||
['refined-concrete'] = 3,
|
||||
['hazard-concrete-right'] = 2,
|
||||
['hazard-concrete-left'] = 2,
|
||||
['refined-hazard-concrete-right'] = 3,
|
||||
['refined-hazard-concrete-left'] = 3
|
||||
}
|
||||
|
||||
local tier_0 = {
|
||||
'transport-belt',
|
||||
'fast-transport-belt',
|
||||
'express-transport-belt',
|
||||
'underground-belt',
|
||||
'fast-underground-belt',
|
||||
'express-underground-belt',
|
||||
'small-electric-pole',
|
||||
'burner-mining-drill',
|
||||
'pumpjack',
|
||||
'car',
|
||||
'tank',
|
||||
'pipe',
|
||||
'pipe-to-ground',
|
||||
'offshore-pump',
|
||||
'locomotive',
|
||||
'cargo-wagon',
|
||||
'fluid-wagon',
|
||||
'artillery-wagon'
|
||||
}
|
||||
|
||||
--- Items explicitly allowed everywhere (tier 0 and up)
|
||||
--- The RestrictEntities module auto skips all checks for these entities
|
||||
--- They do not trigger set_keep_alive_callback or the on_pre_restricted_entity_destroyed event
|
||||
RestrictEntities.add_allowed(tier_0)
|
||||
|
||||
-- Items only allowed on tiles of tier 2 or higher (tier 1 is the default)
|
||||
local entity_tiers = {
|
||||
-- Tier 2
|
||||
['oil-refinery'] = 2,
|
||||
['chemical-plant'] = 2,
|
||||
['storage-tank'] = 2,
|
||||
['rail'] = 2,
|
||||
['straight-rail'] = 2,
|
||||
['curved-rail'] = 2,
|
||||
['train-stop'] = 2,
|
||||
['solar-panel'] = 2,
|
||||
['flamethrower-turret'] = 2,
|
||||
['assembling-machine-2'] = 2,
|
||||
['steel-furnace'] = 2,
|
||||
['fast-inserter'] = 2,
|
||||
['filter-inserter'] = 2,
|
||||
['accumulator'] = 2,
|
||||
['big-electric-pole'] = 2,
|
||||
-- Tier 3
|
||||
['rocket-silo'] = 3,
|
||||
['nuclear-reactor'] = 3,
|
||||
['centrifuge'] = 3,
|
||||
['heat-exchanger'] = 3,
|
||||
['heat-pipe'] = 3,
|
||||
['steam-turbine'] = 3,
|
||||
['artillery-turret'] = 3,
|
||||
['roboport'] = 3,
|
||||
['beacon'] = 3,
|
||||
['assembling-machine-3'] = 3,
|
||||
['electric-furnace'] = 3,
|
||||
['substation'] = 3,
|
||||
['laser-turret'] = 3,
|
||||
['stack-inserter'] = 3,
|
||||
['stack-filter-inserter'] = 3,
|
||||
['logistic-chest-active-provider'] = 3,
|
||||
['logistic-chest-passive-provider'] = 3,
|
||||
['logistic-chest-buffer'] = 3,
|
||||
['logistic-chest-storage'] = 3,
|
||||
['logistic-chest-requester'] = 3
|
||||
}
|
||||
|
||||
--Creates rich text icons of the tiered entities
|
||||
local tier_0_items = ''
|
||||
local tier_0_counter = 0
|
||||
|
||||
for _, v in pairs(tier_0) do
|
||||
tier_0_items = tier_0_items .. ' [entity=' .. v .. ']'
|
||||
tier_0_counter = tier_0_counter + 1
|
||||
if tier_0_counter > 10 then
|
||||
tier_0_counter = 0
|
||||
tier_0_items = tier_0_items .. '\n'
|
||||
end
|
||||
end
|
||||
|
||||
local tier_2_items = ''
|
||||
local tier_3_items = ''
|
||||
|
||||
local tier_2_counter = 0
|
||||
local tier_3_counter = 0
|
||||
|
||||
for k, v in pairs(entity_tiers) do
|
||||
if not (k == 'rail') then
|
||||
if (v == 3) then
|
||||
tier_3_items = tier_3_items .. ' [entity=' .. k .. ']'
|
||||
tier_3_counter = tier_3_counter + 1
|
||||
elseif (v == 2) then
|
||||
tier_2_items = tier_2_items .. ' [entity=' .. k .. ']'
|
||||
tier_2_counter = tier_2_counter + 1
|
||||
end
|
||||
|
||||
if tier_3_counter > 14 then
|
||||
tier_3_counter = 0
|
||||
tier_3_items = tier_3_items .. '\n'
|
||||
elseif tier_2_counter > 14 then
|
||||
tier_2_counter = 0
|
||||
tier_2_items = tier_2_items .. '\n'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local tile_tiers_entities = '[font=default-bold]You may only build the factory on:[/font]\n'
|
||||
local tile_tiers_entities_counter = 0
|
||||
|
||||
for k, _ in pairs(tile_tiers) do
|
||||
tile_tiers_entities = tile_tiers_entities .. ' [tile=' .. k .. '] ' .. k
|
||||
tile_tiers_entities_counter = tile_tiers_entities_counter + 1
|
||||
if tile_tiers_entities_counter == 3 or tile_tiers_entities_counter == 5 then
|
||||
--tile_tiers_entities_counter = 0
|
||||
tile_tiers_entities = tile_tiers_entities .. '\n'
|
||||
end
|
||||
end
|
||||
|
||||
ScenarioInfo.add_map_extra_info(
|
||||
tile_tiers_entities ..
|
||||
[[
|
||||
|
||||
|
||||
[font=default-bold]Exceptions:[/font]
|
||||
]] ..
|
||||
tier_0_items ..
|
||||
[[
|
||||
|
||||
|
||||
Stone bricks provide ground support for most buildings/entities,
|
||||
but some require better ground support!
|
||||
|
||||
[font=default-bold]Ground support minimum concrete:[/font]
|
||||
]] ..
|
||||
tier_2_items .. [[
|
||||
|
||||
|
||||
[font=default-bold]Ground support minimum refined concrete:[/font]
|
||||
]] .. tier_3_items .. [[
|
||||
|
||||
|
||||
Due to security measures you can not remove ground support nor downgrade it!
|
||||
]]
|
||||
)
|
||||
|
||||
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(
|
||||
Token.register(
|
||||
function(entity)
|
||||
if not (entity and entity.valid) then
|
||||
return false
|
||||
end
|
||||
local get_tile = entity.surface.get_tile
|
||||
local area = entity.bounding_box
|
||||
local left_top = area.left_top
|
||||
local right_bottom = area.right_bottom
|
||||
local name = entity.name
|
||||
|
||||
if name == 'entity-ghost' then
|
||||
name = entity.ghost_name
|
||||
end
|
||||
|
||||
local entity_tier = entity_tiers[name] or 1
|
||||
|
||||
for x = floor(left_top.x), floor(right_bottom.x) do
|
||||
for y = floor(left_top.y), floor(right_bottom.y) do
|
||||
local tile_name = get_tile(x, y).name
|
||||
local tile_tier = tile_tiers[tile_name] or 0
|
||||
|
||||
if entity_tier > tile_tier then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
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')
|
||||
|
||||
if not (Rank.equal_or_greater_than(player.name, Ranks.auto_trusted)) then
|
||||
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
|
||||
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}
|
||||
end
|
||||
end
|
||||
)
|
||||
)
|
||||
|
||||
local function print_floating_text(player, entity, text, color)
|
||||
color = color or Color.white
|
||||
local surface = player.surface
|
||||
local position = entity.position
|
||||
|
||||
return surface.create_entity {
|
||||
name = 'tutorial-flying-text',
|
||||
color = color,
|
||||
text = text,
|
||||
position = position,
|
||||
render_player_index = player.index
|
||||
}
|
||||
end
|
||||
|
||||
--- Warning for players when their entities are destroyed (needs to be pre because of the stack)
|
||||
local function on_destroy(event)
|
||||
local p = game.get_player(event.player_index)
|
||||
local stack = event.stack
|
||||
local entity = event.created_entity
|
||||
local name
|
||||
|
||||
if stack.valid_for_read then
|
||||
name = stack.name
|
||||
else
|
||||
name = entity.name
|
||||
end
|
||||
|
||||
if p and p.valid then
|
||||
if not (name == 'blueprint' or name == 'blueprint-book') then
|
||||
if name == 'entity-ghost' then
|
||||
name = entity.ghost_name
|
||||
end
|
||||
|
||||
local tier = {'item-name.stone-path'}
|
||||
if (entity_tiers[name] == 2) then
|
||||
tier = {'item-name.concrete'}
|
||||
elseif (entity_tiers[name] == 3) then
|
||||
tier = {'item-name.refined-concrete'}
|
||||
end
|
||||
local text = {'concrete_jungle.entity_not_enough_ground_support', '[item=' .. name .. ']', tier}
|
||||
print_floating_text(p, entity, text)
|
||||
else
|
||||
p.print({'', '[color=yellow]', {'concrete_jungle.blueprint_not_enough_ground_support', {'', '[/color][color=red]', {'concrete_jungle.blueprint'}, '[/color][color=yellow]'}}, '[/color]'})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function remove_tile_from_player(name, player)
|
||||
if name == 'stone-path' then
|
||||
name = 'stone-brick'
|
||||
elseif name == 'hazard-concrete-left' or name == 'hazard-concrete-right' then
|
||||
name = 'hazard-concrete'
|
||||
elseif name == 'refined-hazard-concrete-left' or name == 'refined-hazard-concrete-right' then
|
||||
name = 'refined-hazard-concrete'
|
||||
end
|
||||
player.remove_item({name = name})
|
||||
end
|
||||
|
||||
local function player_mined_tile(event)
|
||||
local player_index = event.player_index
|
||||
local surface = game.surfaces[event.surface_index]
|
||||
local oldTiles = event.tiles
|
||||
local tiles = {}
|
||||
|
||||
local player = game.get_player(player_index)
|
||||
player.clean_cursor()
|
||||
|
||||
for _, oldTile in pairs(oldTiles) do
|
||||
local name = oldTile.old_tile.name
|
||||
table.insert(tiles, {name = name, position = oldTile.position})
|
||||
remove_tile_from_player(name, player)
|
||||
end
|
||||
|
||||
surface.set_tiles(tiles, true)
|
||||
end
|
||||
|
||||
local function marked_for_deconstruction(event)
|
||||
local entity = event.entity
|
||||
|
||||
if entity.name == 'deconstructible-tile-proxy' then
|
||||
if entity and entity.valid then
|
||||
entity.destroy()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function player_built_tile(event)
|
||||
local newTile = event.tile
|
||||
local tier = tile_tiers[newTile.name]
|
||||
|
||||
if (tier) then
|
||||
local tiles = {}
|
||||
local oldTiles = event.tiles
|
||||
|
||||
local index = event.player_index
|
||||
local robot = event.robot
|
||||
local player
|
||||
if index then
|
||||
player = game.get_player(index)
|
||||
else
|
||||
player = robot
|
||||
end
|
||||
|
||||
local surface = game.surfaces[event.surface_index]
|
||||
|
||||
for _, oldTile in pairs(oldTiles) do
|
||||
local name = oldTile.old_tile.name
|
||||
local tile_tier = tile_tiers[name] or 0
|
||||
if (tile_tier ~= 0 and tile_tier > tier) then
|
||||
local newName = newTile.name
|
||||
local position = oldTile.position
|
||||
table.insert(tiles, {name = name, position = position})
|
||||
|
||||
remove_tile_from_player(name, player)
|
||||
|
||||
if newName == 'stone-path' then
|
||||
newName = 'stone-brick'
|
||||
elseif newName == 'hazard-concrete-left' or name == 'hazard-concrete-right' then
|
||||
newName = 'hazard-concrete'
|
||||
elseif newName == 'refined-hazard-concrete-left' or name == 'refined-hazard-concrete-right' then
|
||||
newName = 'refined-hazard-concrete'
|
||||
end
|
||||
local item = {name = newName}
|
||||
if player.can_insert(item) then
|
||||
player.insert(item)
|
||||
else
|
||||
player.surface.spill_item_stack(position, item, true, player.force, false)
|
||||
end
|
||||
end
|
||||
end
|
||||
surface.set_tiles(tiles, true)
|
||||
end
|
||||
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,
|
||||
function(event)
|
||||
Task.set_timeout_in_ticks(900, first_time, {event = event})
|
||||
end
|
||||
)
|
||||
Event.on_init(on_init)
|
||||
|
||||
--- 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')
|
||||
local stone_circle = b.change_tile(circle, true, 'stone-path')
|
||||
stone_circle = b.if_else(concrete_square, stone_circle)
|
||||
|
||||
local water_circle = b.circle(250)
|
||||
local land_circle = b.circle(200)
|
||||
|
||||
water_circle = b.subtract(water_circle, land_circle)
|
||||
|
||||
local cross = b.add(b.line_x(4), b.line_y(4))
|
||||
cross = b.change_tile(cross, true, 'landfill')
|
||||
|
||||
cross = b.subtract(cross, b.invert(water_circle))
|
||||
|
||||
water_circle = b.change_tile(water_circle, true, 'water')
|
||||
water_circle = b.fish(water_circle, 0.0025)
|
||||
|
||||
local map = b.if_else(water_circle, b.full_shape)
|
||||
|
||||
map = b.if_else(cross, map)
|
||||
|
||||
map = b.if_else(stone_circle, map)
|
||||
|
||||
return map
|
@ -2,6 +2,7 @@ local Event = require 'utils.event'
|
||||
local Global = require 'utils.global'
|
||||
local RestrictEntities = require 'map_gen.shared.entity_placement_restriction'
|
||||
local Popup = require 'features.gui.popup'
|
||||
local Token = require 'utils.token'
|
||||
|
||||
local floor = math.floor
|
||||
|
||||
@ -37,20 +38,21 @@ local function all_on_landfill(entity)
|
||||
end
|
||||
|
||||
RestrictEntities.set_keep_alive_callback(
|
||||
function(entity)
|
||||
local name = entity.name
|
||||
if name == 'entity-ghost' then
|
||||
name = entity.ghost_name
|
||||
end
|
||||
Token.register(
|
||||
function(entity)
|
||||
local name = entity.name
|
||||
if name == 'entity-ghost' then
|
||||
name = entity.ghost_name
|
||||
end
|
||||
|
||||
if not rail_entities[name] then
|
||||
return true
|
||||
end
|
||||
if not rail_entities[name] then
|
||||
return true
|
||||
end
|
||||
|
||||
return all_on_landfill(entity)
|
||||
end
|
||||
return all_on_landfill(entity)
|
||||
end
|
||||
)
|
||||
)
|
||||
|
||||
-- On first time player places rail entity on invalid tile, show popup explaining the rail mechanic.
|
||||
local function restricted_entity_destroyed(event)
|
||||
local p = event.player
|
||||
@ -74,10 +76,7 @@ local function player_joined_game(event)
|
||||
return
|
||||
end
|
||||
|
||||
player.print(
|
||||
"Welcome to RedMew's Rail Grids Map. Rails can only be built on green tiles.",
|
||||
{r = 0, g = 1, b = 0, a = 1}
|
||||
)
|
||||
player.print("Welcome to RedMew's Rail Grids Map. Rails can only be built on green tiles.", {r = 0, g = 1, b = 0, a = 1})
|
||||
end
|
||||
|
||||
Event.add(RestrictEntities.events.on_restricted_entity_destroyed, restricted_entity_destroyed)
|
||||
|
@ -1,6 +1,7 @@
|
||||
-- This module prevents all but the allowed items from being built on top of resources
|
||||
local RestrictEntities = require 'map_gen.shared.entity_placement_restriction'
|
||||
local Event = require 'utils.event'
|
||||
local Token = require 'utils.token'
|
||||
|
||||
--- Items explicitly allowed on ores
|
||||
RestrictEntities.add_allowed(
|
||||
@ -25,18 +26,20 @@ RestrictEntities.add_allowed(
|
||||
|
||||
--- The logic for checking that there are resources under the entity's position
|
||||
RestrictEntities.set_keep_alive_callback(
|
||||
function(entity)
|
||||
-- Some entities have a bounding_box area of zero, eg robots.
|
||||
local area = entity.bounding_box
|
||||
local left_top, right_bottom = area.left_top, area.right_bottom
|
||||
if left_top.x == right_bottom.x and left_top.y == right_bottom.y then
|
||||
return true
|
||||
Token.register(
|
||||
function(entity)
|
||||
-- Some entities have a bounding_box area of zero, eg robots.
|
||||
local area = entity.bounding_box
|
||||
local left_top, right_bottom = area.left_top, area.right_bottom
|
||||
if left_top.x == right_bottom.x and left_top.y == right_bottom.y then
|
||||
return true
|
||||
end
|
||||
local count = entity.surface.count_entities_filtered {area = area, type = 'resource', limit = 1}
|
||||
if count == 0 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
local count = entity.surface.count_entities_filtered {area = area, type = 'resource', limit = 1}
|
||||
if count == 0 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
)
|
||||
)
|
||||
|
||||
--- Warning for players when their entities are destroyed
|
||||
|
@ -9,6 +9,8 @@
|
||||
This means you can use any custom logic you want to determine whether an entity should be destroyed or not.
|
||||
The callback function is supplied a valid LuaEntity as an argument.
|
||||
A return of true indicates the entity should be kept alive, while false or nil indicate it should be destroyed.
|
||||
This function must be a registered with the Token module and the keep_alive_callback function will take the Token-id as parameter
|
||||
This is to prevent upvalue errors
|
||||
|
||||
Refunds for items that were placed can be toggled on or off via the enable and disable_refund functions
|
||||
|
||||
@ -24,16 +26,18 @@
|
||||
-- The function provided does nothing but return nil
|
||||
-- every entity will be destroyed except those on the allowed list
|
||||
RestrictEntities.add_allowed({'transport-belt'})
|
||||
RestrictEntities.set_keep_alive_callback(function() end)
|
||||
RestrictEntities.set_keep_alive_callback(Token.register(function() end))
|
||||
|
||||
-- Danger ores (a lot of important code omitted for the sake of a brief example)
|
||||
RestrictEntities.add_allowed({belts, power_poles, mining_drills, 'pumpjack'})
|
||||
RestrictEntities.set_keep_alive_callback(
|
||||
function(entity)
|
||||
if entity.surface.count_entities_filtered {area = entity.bounding_box, type = 'resource', limit = 1} == 0 then
|
||||
return true
|
||||
Token.register(
|
||||
function(entity)
|
||||
if entity.surface.count_entities_filtered {area = entity.bounding_box, type = 'resource', limit = 1} == 0 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
)
|
||||
)
|
||||
]]
|
||||
local Event = require 'utils.event'
|
||||
@ -80,7 +84,10 @@ local banned_entities = {}
|
||||
local primitives = {
|
||||
event = nil, -- if the event is registered or not
|
||||
refund = true, -- if we issue a refund or not
|
||||
keep_alive_callback = nil -- the function to process entities through
|
||||
prevent_tile_bp = false, -- prevents players from placing blueprints with tiles
|
||||
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
|
||||
}
|
||||
|
||||
Global.register(
|
||||
@ -98,6 +105,72 @@ Global.register(
|
||||
|
||||
-- Local functions
|
||||
|
||||
--- Spill items stacks
|
||||
-- @param entity <LuaEntity> the entity from which the items should be spilled
|
||||
-- @param item <ItemStackSpecification> 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
|
||||
|
||||
local Task = require 'utils.task'
|
||||
|
||||
--- Cleans the players cursor to prevent from spam replacing entities with inventory
|
||||
-- Somehow required to have a 1 tick delay before cleaning the players cursor
|
||||
local delay_clean_cursor =
|
||||
Token.register(
|
||||
function(param)
|
||||
param.player.clean_cursor()
|
||||
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
|
||||
Task.set_timeout_in_ticks(1, delay_clean_cursor, {player = player})
|
||||
local type = entity.type
|
||||
if type == '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 == 'logistic-container' then
|
||||
entity.surface.create_entity {name = 'steel-chest', position = entity.position, direction = entity.direction, force = entity.force, fast_replace = true, spill = false}
|
||||
if player and player.valid and primitives.refund then -- refunding materials required to make a logistic container minus the "free" steel-chest generated above
|
||||
player.insert({name = 'electronic-circuit', count = 3})
|
||||
player.insert({name = 'advanced-circuit', count = 1})
|
||||
end
|
||||
return true
|
||||
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
|
||||
elseif type == 'ammo-turret' then
|
||||
for item, count in pairs(entity.get_inventory(defines.inventory.turret_ammo).get_contents()) do
|
||||
player.insert({name = item, count = count})
|
||||
end
|
||||
return -- Prevents triggering when autofill is enabled
|
||||
end
|
||||
|
||||
Token.get(primitives.anti_grief_callback)(entity, player)
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--- Token for the on_built event callback, checks if an entity should be destroyed.
|
||||
local on_built_token =
|
||||
Token.register(
|
||||
@ -109,6 +182,9 @@ local on_built_token =
|
||||
|
||||
local name = entity.name
|
||||
if name == 'tile-ghost' then
|
||||
if primitives.prevent_tile_bp and entity.ghost_name ~= 'landfill' then
|
||||
entity.destroy()
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
@ -132,7 +208,7 @@ local on_built_token =
|
||||
-- destroy in these cases:
|
||||
-- all banned ents
|
||||
-- not banned and callback function and not saved by callback
|
||||
if not banned_entities[name] and (not keep_alive_callback or keep_alive_callback(entity)) then
|
||||
if not banned_entities[name] and (not keep_alive_callback or Token.get(keep_alive_callback)(entity)) then
|
||||
return
|
||||
end
|
||||
|
||||
@ -149,14 +225,20 @@ local on_built_token =
|
||||
}
|
||||
)
|
||||
|
||||
local player = game.get_player(index)
|
||||
|
||||
-- Need to revalidate the entity since we sent it to the raised event
|
||||
if entity.valid then
|
||||
entity.destroy()
|
||||
-- Checking if the entity has an inventory and spills the content on the ground to prevent destroying those too
|
||||
if entities_with_inventory(entity, player) then
|
||||
ghost = true -- Cheating to prevent refunds
|
||||
else
|
||||
entity.destroy()
|
||||
end
|
||||
end
|
||||
|
||||
-- Check if we issue a refund: make sure refund is enabled, make sure we're not refunding a ghost,
|
||||
-- and revalidate the stack since we sent it to the raised event
|
||||
local player = game.get_player(index)
|
||||
local item_returned
|
||||
if player and player.valid and primitives.refund and not ghost and stack.valid then
|
||||
player.insert(stack)
|
||||
@ -201,8 +283,8 @@ end
|
||||
-- logic on what entities should and should not be destroyed.
|
||||
-- @param keep_alive_callback <function>
|
||||
function Public.set_keep_alive_callback(keep_alive_callback)
|
||||
if type(keep_alive_callback) ~= 'function' then
|
||||
error('Sending a non-function')
|
||||
if type(keep_alive_callback) ~= 'number' then
|
||||
error('Sending a non-token function')
|
||||
end
|
||||
primitives.keep_alive_callback = keep_alive_callback
|
||||
check_event_status()
|
||||
@ -214,6 +296,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>
|
||||
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 <table> array of string entity names
|
||||
function Public.add_allowed(ents)
|
||||
@ -272,4 +369,24 @@ function Public.set_refund()
|
||||
primitives.refund = false
|
||||
end
|
||||
|
||||
--- Enables the ability to blueprint tiles (Landfill always enabled)
|
||||
function Public.enable_tile_bp()
|
||||
primitives.prevent_tile_bp = false
|
||||
end
|
||||
|
||||
--- 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
|
||||
|
Loading…
x
Reference in New Issue
Block a user