1
0
mirror of https://github.com/Refactorio/RedMew.git synced 2024-12-14 10:13:13 +02:00

Merge pull request #221 from iltar/scenario/diggy

Initial setup for Diggy
This commit is contained in:
Valansch 2018-10-15 12:08:51 +02:00 committed by GitHub
commit 3dad1db67d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 2338 additions and 2 deletions

View File

@ -14,7 +14,7 @@ require 'follow'
require 'autodeconstruct'
require 'corpse_util'
--require 'infinite_storage_chest'
require 'fish_market'
--require 'fish_market'
require 'reactor_meltdown'
require 'train_saviour'
require 'map_gen.shared.perlin_noise'

View File

@ -0,0 +1,150 @@
--[[-- info
Original (javascript) version: https://hastebin.com/udakacavap.js
Can be tested against: https://wiki.factorio.com/Enemies#Spawn_chances_by_evolution_factor
]]
-- dependencies
local Global = require 'utils.global'
local random = math.random
-- this
local AlienEvolutionProgress = {}
local alien_cache = {
biters = {},
spitters = {},
}
Global.register({
alien_cache = alien_cache,
}, function(tbl)
alien_cache = tbl.alien_cache
end)
-- values are in the form {evolution, weight}
local biters = {
{'small-biter', {{0.0, 0.3}, {0.6, 0.0}}},
{'medium-biter', {{0.2, 0.0}, {0.6, 0.3}, {0.7, 0.1}}},
{'big-biter', {{0.5, 0.0}, {1.0, 0.4}}},
{'behemoth-biter', {{0.9, 0.0}, {1.0, 0.3}}},
}
local spitters = {
{'small-biter', {{0.0, 0.3}, {0.35, 0.0}}},
{'small-spitter', {{0.25, 0.0}, {0.5, 0.3}, {0.7, 0.0}}},
{'medium-spitter', {{0.4, 0.0}, {0.7, 0.3}, {0.9, 0.1}}},
{'big-spitter', {{0.5, 0.0}, {1.0, 0.4}}},
{'behemoth-spitter', {{0.9, 0.0}, {1.0, 0.3}}},
}
local function lerp(low, high, pos)
local s = high[1] - low[1];
local l = (pos - low[1]) / s;
return (low[2] * (1 - l)) + (high[2] * l)
end
local function get_values(map, evo)
local result = {}
local sum = 0
for _, data in pairs(map) do
local list = data[2];
local low = list[1];
local high = list[#list];
for _, val in pairs(list) do
if(val[1] <= evo and val[1] > low[1]) then
low = val;
end
if(val[1] >= evo and val[1] < high[1]) then
high = val
end
end
local val
if (evo <= low[1]) then
val = low[2]
elseif (evo >= high[1]) then
val = high[2];
else
val = lerp(low, high, evo)
end
sum = sum + val;
result[data[1]] = val;
end
for index, _ in pairs(result) do
result[index] = result[index] / sum
end
return result;
end
local function get_name_by_random(collection)
local pre_calculated = random()
local current = 0
for name, probability in pairs(collection) do
current = current + probability
if (current >= pre_calculated) then
return name
end
end
Debug.print('AlienEvolutionProgress.get_name_by_random: Current \'' .. current .. '\' should be higher or equal to random \'' .. pre_calculated .. '\'')
end
function AlienEvolutionProgress.getBiterValues(evolution)
local evolution_cache_key = evolution * 100
if (nil == alien_cache.biters[evolution_cache_key]) then
alien_cache.biters[evolution_cache_key] = get_values(biters, evolution)
end
return alien_cache.biters[evolution_cache_key]
end
function AlienEvolutionProgress.getSpitterValues(evolution)
local evolution_cache_key = evolution * 100
if (nil == alien_cache.spitters[evolution_cache_key]) then
alien_cache.spitters[evolution_cache_key] = get_values(spitters, evolution)
end
return alien_cache.spitters[evolution_cache_key]
end
function AlienEvolutionProgress.getBitersByEvolution(total_biters, evolution)
local biters_calculated = {}
local map = AlienEvolutionProgress.getBiterValues(evolution)
for i = 1, total_biters do
local name = get_name_by_random(map)
if (nil == biters_calculated[name]) then
biters_calculated[name] = 1
else
biters_calculated[name] = biters_calculated[name] + 1
end
end
return biters_calculated
end
function AlienEvolutionProgress.getSpittersByEvolution(total_spitters, evolution)
local spitters_calculated = {}
local map = AlienEvolutionProgress.getSpitterValues(evolution)
for i = 1, total_spitters do
local name = get_name_by_random(map)
if (nil == spitters_calculated[name]) then
spitters_calculated[name] = 1
else
spitters_calculated[name] = spitters_calculated[name] + 1
end
end
return spitters_calculated
end
return AlienEvolutionProgress

246
map_gen/Diggy/Config.lua Normal file
View File

@ -0,0 +1,246 @@
-- dependencies
-- this
local Config = {
-- enable debug mode, shows extra messages
debug = false,
-- allow cheats. Example: by default the player will have X mining speed
cheats = false,
-- a list of features to register and enable
-- to disable a feature, change the flag
features = {
StartingZone = {
enabled = true,
-- initial starting position size, values higher than 30 might break
starting_size = 8,
},
SetupPlayer = {
enabled = true,
starting_items = {
{name = 'iron-axe', count = 1},
{name = 'stone-wall', count = 10},
},
cheats = {
manual_mining_speed_modifier = 1000,
},
},
DiggyHole = {
enabled = true,
},
DiggyCaveCollapse = {
enabled = true,
-- adds per tile what the current stress is
enable_stress_grid = false,
-- shows the mask on spawn
enable_mask_debug = false,
--the size of the mask used
mask_size = 9,
--how much the mask will effect tiles in the different rings of the mask
mask_relative_ring_weights = {2, 3, 4},
-- delay in seconds before the cave collapses
collapse_delay = 2.5,
-- the threshold that will be applied to all neighbors on a collapse via a mask
collapse_threshold_total_strength = 16,
support_beam_entities = {
['market'] = 10,
['stone-wall'] = 3.3,
['sand-rock-big'] = 2.2,
['out-of-map'] = 1.1,
['stone-brick'] = 0.055,
['stone-path'] = 0.055,
['concrete'] = 0.33,
['hazard-concrete-left'] = 0.33,
['hazard-concrete-right'] = 0.33,
['refined-concrete'] = 0.77,
['refined-hazard-concrete-left'] = 0.77,
['refined-hazard-concrete-right'] = 0.77,
},
cracking_sounds = {
'CRACK',
'KRRRR',
}
},
RefreshMap = {
enabled = true,
},
SimpleRoomGenerator = {
enabled = true,
-- value between 0 and 1, higher value means stronger variance between coordinates
noise_variance = 0.066,
-- adds per tile what the current noise is
enable_noise_grid = false,
-- minimum distance and noise range required for water to spawn
room_noise_minimum_distance = 9,
room_noise_ranges = {
{name = 'water', min = 0.54, max = 1},
{name = 'dirt', min = 0.39, max = 0.53},
},
},
ScatteredResources = {
enabled = true,
-- percentage of resource added to the sum. 100 tiles means
-- 10% more resources with a distance_richness_modifier of 10
-- 20% more resources with a distance_richness_modifier of 5
distance_richness_modifier = 5,
-- defines the increased chance of spawning resources
-- calculated_probability = resource_probability + ((distance / distance_probability_modifier) / 100)
distance_probability_modifier = 2,
-- increases the amount of oil * oil_value_modifier
oil_value_modifier = 650,
-- percentage of chance that resources will spawn after mining
resource_probability = 0.15,
-- max chance of spawning resources based on resource_probability + calculated distance_probability_modifier
max_resource_probability = 0.45,
-- chances per resource of spawning, sum must be 1.00
resource_chances = {
['coal'] = 0.21,
['copper-ore'] = 0.30,
['iron-ore'] = 0.26,
['stone'] = 0.20,
['uranium-ore'] = 0.02,
['crude-oil'] = 0.01,
},
-- minimum distance from the spawn point required before it spawns
minimum_resource_distance = {
['coal'] = 16,
['copper-ore'] = 18,
['iron-ore'] = 18,
['stone'] = 15,
['uranium-ore'] = 86,
['crude-oil'] = 57,
},
-- defines the chance of which resource_richness_value to spawn, sum must be 1.00
resource_richness_probability = {
['scarce'] = 0.40,
['low'] = 0.28,
['sufficient'] = 0.16,
['good'] = 0.10,
['plenty'] = 0.04,
['jackpot'] = 0.02,
},
-- defines the min and max range of ores to spawn
resource_richness_values = {
['scarce'] = {1, 200},
['low'] = {201, 400},
['sufficient'] = {401, 750},
['good'] = {751, 1200},
['plenty'] = {1201, 2000},
['jackpot'] = {2001, 5000},
},
},
AlienSpawner = {
enabled = false,
-- minimum distance from spawn before aliens can spawn
alien_minimum_distance = 35,
-- chance of spawning aliens when mining
alien_probability = 0.07,
},
MarketExchange = {
enabled = true,
-- percentage * mining productivity level gets added to mining speed
mining_speed_productivity_multiplier = 10,
-- market config
market_spawn_position = {x = 0, y = 4},
stone_to_surface_amount = 50,
currency_item = 'stone',
unlockables = {
{stone = 50, type = 'buff', prototype = {name = 'mining_speed', value = 10}},
{stone = 50, type = 'buff', prototype = {name = 'inventory_slot', value = 3}},
{stone = 50, type = 'market', prototype = {price = 50, name = 'raw-fish'}},
{stone = 50, type = 'market', prototype = {price = 175, name = 'steel-axe'}},
{stone = 250, type = 'buff', prototype = {name = 'mining_speed', value = 5}},
{stone = 250, type = 'buff', prototype = {name = 'inventory_slot', value = 2}},
{stone = 250, type = 'market', prototype = {price = 50, name = 'small-electric-pole'}},
{stone = 250, type = 'market', prototype = {price = 50, name = 'small-lamp'}},
{stone = 250, type = 'market', prototype = {price = 25, name = 'stone-brick'}},
{stone = 250, type = 'market', prototype = {price = 125, name = 'stone-wall'}},
{stone = 450, type = 'buff', prototype = {name = 'mining_speed', value = 5}},
{stone = 450, type = 'buff', prototype = {name = 'inventory_slot', value = 2}},
{stone = 450, type = 'market', prototype = {price = 850, name = 'submachine-gun'}},
{stone = 450, type = 'market', prototype = {price = 50, name = 'firearm-magazine'}},
{stone = 450, type = 'market', prototype = {price = 500, name = 'light-armor'}},
{stone = 750, type = 'buff', prototype = {name = 'mining_speed', value = 5}},
{stone = 750, type = 'buff', prototype = {name = 'inventory_slot', value = 1}},
{stone = 1250, type = 'buff', prototype = {name = 'mining_speed', value = 5}},
{stone = 1250, type = 'buff', prototype = {name = 'inventory_slot', value = 1}},
{stone = 1750, type = 'buff', prototype = {name = 'mining_speed', value = 5}},
{stone = 1750, type = 'buff', prototype = {name = 'inventory_slot', value = 1}},
{stone = 2500, type = 'buff', prototype = {name = 'mining_speed', value = 5}},
{stone = 2500, type = 'buff', prototype = {name = 'inventory_slot', value = 1}},
{stone = 4000, type = 'buff', prototype = {name = 'mining_speed', value = 5}},
{stone = 4000, type = 'buff', prototype = {name = 'inventory_slot', value = 1}},
{stone = 6500, type = 'buff', prototype = {name = 'mining_speed', value = 5}},
{stone = 6500, type = 'buff', prototype = {name = 'inventory_slot', value = 1}},
{stone = 8000, type = 'buff', prototype = {name = 'mining_speed', value = 5}},
{stone = 8000, type = 'buff', prototype = {name = 'inventory_slot', value = 1}},
{stone = 10000, type = 'buff', prototype = {name = 'mining_speed', value = 5}},
{stone = 10000, type = 'buff', prototype = {name = 'inventory_slot', value = 1}},
{stone = 10000, type = 'market', prototype = {price = 750, name = 'heavy-armor'}},
{stone = 15000, type = 'buff', prototype = {name = 'mining_speed', value = 2}},
{stone = 15000, type = 'buff', prototype = {name = 'inventory_slot', value = 1}},
{stone = 25000, type = 'buff', prototype = {name = 'mining_speed', value = 2}},
{stone = 25000, type = 'buff', prototype = {name = 'inventory_slot', value = 1}},
{stone = 35000, type = 'buff', prototype = {name = 'mining_speed', value = 2}},
{stone = 35000, type = 'buff', prototype = {name = 'inventory_slot', value = 1}},
{stone = 35000, type = 'market', prototype = {price = 100, name = 'piercing-rounds-magazine'}},
{stone = 35000, type = 'market', prototype = {price = 1500, name = 'modular-armor'}},
{stone = 50000, type = 'buff', prototype = {name = 'mining_speed', value = 2}},
{stone = 50000, type = 'buff', prototype = {name = 'inventory_slot', value = 1}},
{stone = 75000, type = 'buff', prototype = {name = 'mining_speed', value = 2}},
{stone = 75000, type = 'buff', prototype = {name = 'inventory_slot', value = 1}},
{stone = 100000, type = 'buff', prototype = {name = 'mining_speed', value = 2}},
{stone = 100000, type = 'buff', prototype = {name = 'inventory_slot', value = 1}},
{stone = 125000, type = 'buff', prototype = {name = 'mining_speed', value = 2}},
{stone = 150000, type = 'buff', prototype = {name = 'mining_speed', value = 2}},
{stone = 175000, type = 'buff', prototype = {name = 'mining_speed', value = 2}},
{stone = 200000, type = 'buff', prototype = {name = 'mining_speed', value = 2}},
{stone = 225000, type = 'buff', prototype = {name = 'mining_speed', value = 2}},
{stone = 250000, type = 'buff', prototype = {name = 'mining_speed', value = 2}},
{stone = 275000, type = 'buff', prototype = {name = 'mining_speed', value = 2}},
{stone = 300000, type = 'buff', prototype = {name = 'mining_speed', value = 2}},
{stone = 350000, type = 'buff', prototype = {name = 'mining_speed', value = 2}},
{stone = 400000, type = 'buff', prototype = {name = 'mining_speed', value = 2}},
{stone = 500000, type = 'buff', prototype = {name = 'mining_speed', value = 2}},
},
},
},
}
return Config

121
map_gen/Diggy/Debug.lua Normal file
View File

@ -0,0 +1,121 @@
-- dependencies
local min = math.min
local max = math.max
local floor = math.floor
local abs = math.abs
-- this
local Debug = {}
-- private state
local debug = false
local cheats = false
function Debug.enable_debug()
debug = true
end
function Debug.disable_debug()
debug = false
end
function Debug.enable_cheats()
cheats = true
end
function Debug.disable_cheats()
cheats = true
end
global.message_count = 0
--[[--
Shows the given message if _DEBUG == true.
@param message string
]]
function Debug.print(message)
if type(message) ~= 'string' and type(message) ~= 'number' and type(message) ~= 'boolean' then message = type(message) end
global.message_count = global.message_count + 1
if (debug) then
game.print('[' .. global.message_count .. '] ' .. tostring(message))
log('[' .. global.message_count .. '] ' .. tostring(message))
end
end
--[[--
Shows the given message if _DEBUG == true for a given position.
@param x number
@param y number
@param message string
]]
function Debug.printPosition(position, message)
message = message or ''
if type(message) ~= 'string' and type(message) ~= 'number' and type(message) ~= 'boolean' then message = type(message) end
global.message_count = global.message_count + 1
if (debug) then
game.print('[' .. global.message_count .. '] {x=' .. position.x .. ', y=' .. position.y .. '} ' .. tostring(message))
end
end
--[[--
Executes the given callback if _DIGGY_CHEATS == true.
@param callback function
]]
function Debug.cheat(callback)
if (cheats) then
callback()
end
end
--[[--
Prints a colored value on a location.
@param value between -1 and 1
@param surface LuaSurface
@param position Position {x, y}
]]
function Debug.print_grid_value(value, surface, position)
local r = max(1, value)
local g = 1 - abs(value)
local b = min(1, value)
if (r > 0) then
r = 0
end
if (b < 0) then
b = 0
end
r = abs(r)
local color = { r = r, g = g, b = b}
-- round at precision of 2
local text = floor(100 * value) / 100
if (0 == text) then
text = '0.00'
end
local text_entity = surface.find_entity('flying-text', position)
if text_entity then
text_entity.text = text
text_entity.color = color
return
end
surface.create_entity{
name = 'flying-text',
color = color,
text = text,
position = position
}.active = false
end
return Debug

View File

@ -0,0 +1,58 @@
--[[-- info
Provides the ability to spawn aliens.
]]
-- dependencies
local Event = require 'utils.event'
local AlienEvolutionProgress = require 'map_gen.Diggy.AlienEvolutionProgress'
local Debug = require 'map_gen.Diggy.Debug'
local Template = require 'map_gen.Diggy.Template'
local insert = table.insert
local random = math.random
-- this
local AlienSpawner = {}
local function spawn_alien(surface, x, y)
local enemy_force = game.forces.enemy
local enemy_force_evolution = enemy_force.evolution_factor
local position = {x = x, y = y}
local biters = AlienEvolutionProgress.getBitersByEvolution(random(1, 2), enemy_force_evolution)
local spitters = AlienEvolutionProgress.getSpittersByEvolution(random(1, 2), enemy_force_evolution)
local units = {}
for name, amount in pairs(biters) do
insert(units, {name = name, position = position, force = enemy_force, amount = amount})
end
for name, amount in pairs(spitters) do
insert(units, {name = name, position = position, force = enemy_force, amount = amount})
end
Template.units(surface, units, 3)
end
--[[--
Registers all event handlers.
]]
function AlienSpawner.register(config)
local alien_minimum_distance_square = config.alien_minimum_distance ^ 2
Event.add(Template.events.on_void_removed, function(event)
local x = event.old_tile.position.x
local y = event.old_tile.position.y
if (x^2 + y^2 < alien_minimum_distance_square or config.alien_probability < random()) then
return
end
spawn_alien(event.surface, x, y)
end)
end
function AlienSpawner.get_extra_map_info(config)
return [[Alien Spawner, aliens might spawn when mining!
Spawn chance: ]] .. (config.alien_probability * 100) .. [[%
Minimum spawn distance: ]] .. config.alien_minimum_distance .. ' tiles'
end
return AlienSpawner

View File

@ -0,0 +1,652 @@
--[[-- info
Provides the ability to collapse caves when digging.
]]
-- dependencies
require 'utils.list_utils'
local Event = require 'utils.event'
local Template = require 'map_gen.Diggy.Template'
local Debug = require 'map_gen.Diggy.Debug'
local Task = require 'utils.Task'
local Token = require 'utils.global_token'
local Global = require 'utils.global'
local insert = table.insert
local random = math.random
local floor = math.floor
local abs = math.abs
-- this
local DiggyCaveCollapse = {}
local config = {}
local n = 9
local radius = 0
local radius_sq = 0
local center_radius_sq = 0
local disc_radius_sq = 0
local center_weight
local disc_weight
local ring_weight
local disc_blur_sum = 0
local center_value = 0
local disc_value = 0
local ring_value = 0
local enable_stress_grid = 0
local stress_map_blur_add
local mask_disc_blur
local stress_map_check_stress_in_threshold
local support_beam_entities
local on_surface_created
local stress_threshold_causing_collapse = 1
local deconstruction_alert_message_shown = {}
local stress_map_storage = {}
local new_tile_map = {}
local collapse_positions_storage = {}
local cave_collapse_disabled = nil
Global.register({
new_tile_map = new_tile_map,
stress_map_storage = stress_map_storage,
deconstruction_alert_message_shown = deconstruction_alert_message_shown,
collapse_positions_storage = collapse_positions_storage,
cave_collapse_disabled = cave_collapse_disabled,
}, function(tbl)
new_tile_map = tbl.new_tile_map
stress_map_storage = tbl.stress_map_storage
deconstruction_alert_message_shown = tbl.deconstruction_alert_message_shown
collapse_positions_storage = tbl.collapse_positions_storage
cave_collapse_disabled = tbl.cave_collapse_disabled
end)
local defaultValue = 0
DiggyCaveCollapse.events = {
--[[--
When stress at certain position is above the collapse threshold
- position LuaPosition
- surface LuaSurface
]]
on_collapse_triggered = script.generate_event_name()
}
local function create_collapse_template(positions, surface)
local entities = {}
local tiles = {}
local map = {}
for _, position in pairs(positions) do
local x = position.x
local y = position.y
map[x] = map[x] or {}
map[x][y] = map[x][y] or true
insert(tiles, {position = {x = x, y = y}, name = 'out-of-map'})
end
for x, y_tbl in pairs(map) do
for y, _ in pairs(y_tbl) do
if not map[x] or not map[x][y - 1] then
insert(entities, {position = {x = x, y = y - 1}, name = 'sand-rock-big'})
end
if not map[x] or not map[x][y + 1] then
insert(entities, {position = {x = x, y = y + 1}, name = 'sand-rock-big'})
end
if not map[x - 1] or not map[x - 1][y] then
insert(entities, {position = {x = x - 1, y = y}, name = 'sand-rock-big'})
end
if not map[x + 1] or not map[x + 1][y] then
insert(entities, {position = {x = x + 1, y = y}, name = 'sand-rock-big'})
end
end
end
local find_entities_filtered = surface.find_entities_filtered
for _, new_spawn in pairs({entities, tiles}) do
for _, tile in pairs(new_spawn) do
for _, entity in pairs(find_entities_filtered({position = tile.position})) do
pcall(function()
local strength = support_beam_entities[entity.name]
local position = entity.position
entity.die()
if strength then
stress_map_blur_add(surface, position, strength)
end
end)
end
end
end
return tiles, entities
end
local function collapse(args)
local position = args.position
local surface = args.surface
local positions = {}
local tiles = {}
local entities
local strength = config.collapse_threshold_total_strength
mask_disc_blur(
position.x, position.y,
strength,
function(x, y, value)
stress_map_check_stress_in_threshold(
surface,
{x = x, y = y},
value,
function(_, position)
insert(positions, position)
end
)
end
)
tiles, entities = create_collapse_template(positions, surface)
Template.insert(surface, tiles, entities)
end
local on_collapse_timeout_finished = Token.register(collapse)
local function spawn_cracking_sound_text(surface, position)
local text = config.cracking_sounds[random(1, #config.cracking_sounds)]
local color = {
r = 1,
g = random(1, 100) / 100,
b = 0
}
for i = 1, #text do
local x_offset = (i - #text / 2 - 1) / 3
local char = text:sub(i, i)
surface.create_entity {
name = 'flying-text',
color = color,
text = char,
position = {x = position.x + x_offset, y = position.y - ((i + 1) % 2) / 4}
}.active = true
end
end
local function on_collapse_triggered(event)
if cave_collapse_disabled then return end --kill switch
local surface = event.surface
local position = event.position
local x = position.x
local y = position.y
local x_t = new_tile_map[x]
if x_t and x_t[y] then
Template.insert(surface, {}, {{position = position, name = 'sand-rock-big'}})
return
end
spawn_cracking_sound_text(surface, position)
Task.set_timeout(
config.collapse_delay,
on_collapse_timeout_finished,
{surface = surface, position = position}
)
end
local function on_built_tile(surface, new_tile, tiles)
local new_tile_strength = support_beam_entities[new_tile.name]
for _, tile in pairs(tiles) do
if new_tile_strength then
stress_map_blur_add(surface, tile.position, -1 * new_tile_strength)
end
local old_tile_strength = support_beam_entities[tile.old_tile.name]
if (old_tile_strength) then
stress_map_blur_add(surface, tile.position, old_tile_strength)
end
end
end
local function on_robot_mined_tile(event)
local surface
for _, tile in pairs(event.tiles) do
local strength = support_beam_entities[tile.old_tile.name]
if strength then
surface = surface or event.robot.surface
stress_map_blur_add(surface, tile.position, strength)
end
end
end
local function on_player_mined_tile(event)
local surface = game.surfaces[event.surface_index]
for _, tile in pairs(event.tiles) do
local strength = support_beam_entities[tile.old_tile.name]
if strength then
stress_map_blur_add(surface, tile.position, strength)
end
end
end
local function on_mined_entity(event)
local entity = event.entity
local strength = support_beam_entities[entity.name]
if strength then
stress_map_blur_add(entity.surface, entity.position, strength)
end
end
local function on_built_entity(event)
local entity = event.created_entity
local strength = support_beam_entities[entity.name]
if strength then
stress_map_blur_add(entity.surface, entity.position, -1 * strength)
end
end
local function on_placed_entity(event)
local strength = support_beam_entities[event.entity.name]
if strength then
stress_map_blur_add(event.entity.surface, event.entity.position, -1 * strength)
end
end
local on_new_tile_timeout_finished = Token.register(function(args)
local x_t = new_tile_map[args.x]
if x_t then
x_t[args.y] = nil --reset new tile status. This tile can cause a chain collapse now
end
end)
local function on_void_removed(event)
local strength = support_beam_entities['out-of-map']
local position = event.old_tile.position
if strength then
stress_map_blur_add(event.surface, position, strength)
end
local x = position.x
local y = position.y
--To avoid room collapse:
local x_t = new_tile_map[x]
if x_t then
x_t[y] = true
else
x_t = {
[y] = true
}
new_tile_map[x] = x_t
end
Task.set_timeout(3, on_new_tile_timeout_finished, {x = x, y = y})
end
local function on_void_added(event)
local strength = support_beam_entities['out-of-map']
if strength then
stress_map_blur_add(event.surface, event.old_tile.position, -1 * strength)
end
end
--[[--
Registers all event handlers.]
@param global_config Table {@see Diggy.Config}.
]]
function DiggyCaveCollapse.register(cfg)
config = cfg
support_beam_entities = config.support_beam_entities
Event.add(DiggyCaveCollapse.events.on_collapse_triggered, on_collapse_triggered)
Event.add(defines.events.on_robot_built_entity, on_built_entity)
Event.add(defines.events.on_robot_built_tile, function (event)
on_built_tile(event.robot.surface, event.item, event.tiles)
end)
Event.add(defines.events.on_player_built_tile, function (event)
on_built_tile(game.surfaces[event.surface_index], event.item, event.tiles)
end)
Event.add(defines.events.on_robot_mined_tile, on_robot_mined_tile)
Event.add(defines.events.on_player_mined_tile, on_player_mined_tile)
Event.add(defines.events.on_robot_mined_entity, on_mined_entity)
Event.add(defines.events.on_built_entity, on_built_entity)
Event.add(Template.events.on_placed_entity, on_placed_entity)
Event.add(defines.events.on_entity_died, on_mined_entity)
Event.add(defines.events.on_player_mined_entity, on_mined_entity)
Event.add(Template.events.on_void_removed, on_void_removed)
Event.add(Template.events.on_void_added, on_void_added)
Event.add(defines.events.on_surface_created, on_surface_created)
Event.add(defines.events.on_marked_for_deconstruction, function (event)
if (nil ~= support_beam_entities[event.entity.name]) then
event.entity.cancel_deconstruction(game.players[event.player_index].force)
end
end)
Event.add(defines.events.on_pre_player_mined_item, function(event)
if (nil ~= deconstruction_alert_message_shown[event.player_index]) then
return
end
if (nil ~= support_beam_entities[event.entity.name]) then
require 'popup'.player(
game.players[event.player_index],[[
Mining entities such as walls, stone paths, concrete
and rocks, can cause a cave-in, be careful miner!
Foreman's advice: Place a wall every 4th tile to
prevent a cave-in. Use stone paths and concrete
to reinforce it further.
]]
)
deconstruction_alert_message_shown[event.player_index] = true
end
end)
enable_stress_grid = config.enable_stress_grid
on_surface_created({surface_index = 1})
mask_init(config)
if (config.enable_mask_debug) then
local surface = game.surfaces.nauvis
mask_disc_blur(0, 0, 10, function(x, y, fraction)
Debug.print_grid_value(fraction, surface, {x = x, y = y})
end)
end
commands.add_command('toggle-cave-collapse', 'Toggles cave collapse (admins only).', function()
pcall(function() --better safe than sorry
if not game.player or game.player.admin then
cave_collapse_disabled = not cave_collapse_disabled
if cave_collapse_disabled then
game.print("Cave collapse: Disabled.")
else
game.print("Cave collapse: Enabled.")
end
end
end)
end)
end
--
--STRESS MAP
--
--[[--
Adds a fraction to a given location on the stress_map. Returns the new
fraction value of that position.
@param stress_map Table of {x,y}
@param position Table with x and y
@param number fraction
@return number sum of old fraction + new fraction
]]
function add_fraction(stress_map, x, y, fraction)
local quadrant = 1
if x < 0 then
quadrant = quadrant + 1
x = -x
end
if y < 0 then
quadrant = quadrant + 2
y = -y
end
local quad_t = stress_map[quadrant]
local x_t = quad_t[x]
if not x_t then
x_t = {}
quad_t[x] = x_t
end
local value = x_t[y]
if not value then
value = defaultValue
end
value = value + fraction
x_t[y] = value
if (fraction > 0 and value > stress_threshold_causing_collapse) then
if quadrant > 2 then
y = -y
end
if quadrant % 2 == 0 then
x = -x
end
script.raise_event(
DiggyCaveCollapse.events.on_collapse_triggered,
{surface = game.surfaces[stress_map.surface_index], position = {x = x, y = y}}
)
end
if (enable_stress_grid) then
local surface = game.surfaces[stress_map.surface_index]
if quadrant > 2 then
y = -y
end
if quadrant % 2 == 0 then
x = -x
end
Debug.print_grid_value(value, surface, {x = x, y = y})
end
return value
end
function add_fraction_by_quadrant(stress_map, x, y, fraction, quadrant)
local x_t = quadrant[x]
if not x_t then
x_t = {}
quadrant[x] = x_t
end
local value = x_t[y]
if not value then
value = defaultValue
end
value = value + fraction
x_t[y] = value
if (fraction > 0 and value > stress_threshold_causing_collapse) then
local index = quadrant.index
if index > 2 then
y = -y
end
if index % 2 == 0 then
x = -x
end
script.raise_event(
DiggyCaveCollapse.events.on_collapse_triggered,
{surface = game.surfaces[stress_map.surface_index], position = {x = x, y = y}}
)
end
if (enable_stress_grid) then
local surface = game.surfaces[stress_map.surface_index]
local index = quadrant.index
if index > 2 then
y = -y
end
if index % 2 == 0 then
x = -x
end
Debug.print_grid_value(value, surface, {x = x, y = y})
end
return value
end
on_surface_created = function(event)
stress_map_storage[event.surface_index] = {}
local map = stress_map_storage[event.surface_index]
map['surface_index'] = event.surface_index
map[1] = {index = 1}
map[2] = {index = 2}
map[3] = {index = 3}
map[4] = {index = 4}
end
--[[--
Checks whether a tile's pressure is within a given threshold and calls the handler if not.
@param surface LuaSurface
@param position Position with x and y
@param number threshold
@param callback
]]
stress_map_check_stress_in_threshold = function(surface, position, threshold, callback)
local stress_map = stress_map_storage[surface.index]
local value = add_fraction(stress_map, position.x, position.y, 0)
if (value >= stress_threshold_causing_collapse - threshold) then
callback(surface, position)
end
end
stress_map_blur_add = function(surface, position, factor)
local x_start = floor(position.x)
local y_start = floor(position.y)
local stress_map = stress_map_storage[surface.index]
if not stress_map then
return
end
if radius > abs(x_start) or radius > abs(y_start) then
for x = -radius, radius do
for y = -radius, radius do
local value = 0
local distance_sq = x * x + y * y
if distance_sq <= center_radius_sq then
value = center_value
elseif distance_sq <= disc_radius_sq then
value = disc_value
elseif distance_sq <= radius_sq then
value = ring_value
end
if abs(value) > 0.001 then
add_fraction(stress_map, x + x_start, y + y_start, value * factor)
end
end
end
else
local quadrant_n = 1
if x_start < 0 then
quadrant_n = quadrant_n + 1
x_start = -x_start
end
if y_start < 0 then
quadrant_n = quadrant_n + 2
y_start = -y_start
end
local quadrant = stress_map[quadrant_n]
for x = -radius, radius do
for y = -radius, radius do
local value = 0
local distance_sq = x * x + y * y
if distance_sq <= center_radius_sq then
value = center_value
elseif distance_sq <= disc_radius_sq then
value = disc_value
elseif distance_sq <= radius_sq then
value = ring_value
end
if abs(value) > 0.001 then
add_fraction_by_quadrant(stress_map, x + x_start, y + y_start, value * factor, quadrant)
end
end
end
end
end
DiggyCaveCollapse.stress_map_blur_add = stress_map_blur_add
--
-- MASK
--
function mask_init(config)
n = config.mask_size
ring_weight = config.mask_relative_ring_weights[1]
disc_weight = config.mask_relative_ring_weights[2]
center_weight = config.mask_relative_ring_weights[3]
radius = floor(n / 2)
radius_sq = (radius + 0.2) * (radius + 0.2)
center_radius_sq = radius_sq / 9
disc_radius_sq = radius_sq * 4 / 9
for x = -radius, radius do
for y = -radius, radius do
local distance_sq = x * x + y * y
if distance_sq <= center_radius_sq then
disc_blur_sum = disc_blur_sum + center_weight
elseif distance_sq <= disc_radius_sq then
disc_blur_sum = disc_blur_sum + disc_weight
elseif distance_sq <= radius_sq then
disc_blur_sum = disc_blur_sum + ring_weight
end
end
end
center_value = center_weight / disc_blur_sum
disc_value = disc_weight / disc_blur_sum
ring_value = ring_weight / disc_blur_sum
end
--[[--
Applies a blur
Applies the disc in 3 discs: center, (middle) disc and (outer) ring.
The relative weights for tiles in a disc are:
center: 3/3
disc: 2/3
ring: 1/3
The sum of all values is 1
@param x_start number center point
@param y_start number center point
@param factor the factor to multiply the cell value with (value = cell_value * factor)
@param callback function to execute on each tile within the mask callback(x, y, value)
]]
mask_disc_blur = function(x_start, y_start, factor, callback)
x_start = floor(x_start)
y_start = floor(y_start)
for x = -radius, radius do
for y = -radius, radius do
local value = 0
local distance_sq = x * x + y * y
if distance_sq <= center_radius_sq then
value = center_value
elseif distance_sq <= disc_radius_sq then
value = disc_value
elseif distance_sq <= radius_sq then
value = ring_value
end
if abs(value) > 0.001 then
callback(x_start + x, y_start + y, value * factor)
end
end
end
end
function DiggyCaveCollapse.get_extra_map_info(config)
return [[Alien Spawner, aliens might spawn when mining!
Place stone walls, stone paths and (refined) concrete to reinforce the mine. If you see cracks appear, run!]]
end
return DiggyCaveCollapse

View File

@ -0,0 +1,108 @@
--[[-- info
Provides the ability to "mine" through out-of-map tiles by destroying or
mining rocks next to it.
]]
-- dependencies
local Event = require 'utils.event'
local Scanner = require 'map_gen.Diggy.Scanner'
local Template = require 'map_gen.Diggy.Template'
local Debug = require 'map_gen.Diggy.Debug'
local insert = table.insert
local random = math.random
-- this
local DiggyHole = {}
--[[--
Triggers a diggy diggy hole for a given sand-rock-big.
Will return true even if the tile behind it is immune.
@param entity LuaEntity
]]
local function diggy_hole(entity)
if (entity.name ~= 'sand-rock-big') then
return
end
local tiles = {}
local rocks = {}
local surface = entity.surface
local out_of_map_found = Scanner.scan_around_position(surface, entity.position, 'out-of-map');
for _, position in pairs(out_of_map_found) do
insert(tiles, {name = 'dirt-' .. random(1, 7), position = position})
insert(rocks, {name = 'sand-rock-big', position = position})
end
Template.insert(surface, tiles, rocks)
end
local artificial_tiles = {
['stone-brick'] = true,
['stone-path'] = true,
['concrete'] = true,
['hazard-concrete-left'] = true,
['hazard-concrete-right'] = true,
['refined-concrete'] = true,
['refined-hazard-concrete-left'] = true,
['refined-hazard-concrete-right'] = true,
}
local function on_mined_tile(surface, tiles)
local new_tiles = {}
for _, tile in pairs(tiles) do
if (artificial_tiles[tile.old_tile.name]) then
insert(new_tiles, { name = 'dirt-' .. random(1, 7), position = tile.position})
end
end
Template.insert(surface, new_tiles, {})
end
local function on_built_tile(surface, item, old_tile_and_positions)
if ('landfill' ~= item.name) then
return
end
local tiles = {}
for _, tile in pairs(old_tile_and_positions) do
insert(tiles, {name = 'dirt-' .. random(1, 7), position = tile.position})
end
Template.insert(surface, tiles)
end
--[[--
Registers all event handlers.
]]
function DiggyHole.register(config)
Event.add(defines.events.on_entity_died, function (event)
diggy_hole(event.entity)
end)
Event.add(defines.events.on_player_mined_entity, function (event)
diggy_hole(event.entity)
end)
Event.add(defines.events.on_robot_mined_tile, function(event)
on_mined_tile(event.robot.surface, event.tiles)
end)
Event.add(defines.events.on_player_mined_tile, function(event)
on_mined_tile(game.surfaces[event.surface_index], event.tiles)
end)
Event.add(defines.events.on_robot_built_tile, function (event)
on_built_tile(event.robot.surface, item, tiles)
end)
Event.add(defines.events.on_player_built_tile, function (event)
on_built_tile(game.surfaces[event.surface_index], event.item, event.tiles)
end)
end
return DiggyHole

View File

@ -0,0 +1,263 @@
--[[-- info
Provides the ability to purchase items from the market.
]]
-- dependencies
local Event = require 'utils.event'
local Token = require 'utils.global_token'
local Task = require 'utils.Task'
local Gui = require 'utils.gui'
local Debug = require 'map_gen.Diggy.Debug'
local Template = require 'map_gen.Diggy.Template'
local Global = require 'utils.global'
-- this
local MarketExchange = {}
local config = {}
local stone_tracker = {
first_time_market_item = nil,
stone_sent_to_surface = 0,
previous_stone_sent_to_surface = 0,
}
local mining_efficiency = {
active_modifier = 0,
research_modifier = 0,
market_modifier = 0,
}
local inventory_slots = {
active_modifier = 0,
research_modifier = 0,
market_modifier = 0,
}
Global.register({
stone_tracker = stone_tracker,
mining_efficiency = mining_efficiency,
inventory_slots = inventory_slots,
}, function(tbl)
stone_tracker = tbl.stone_tracker
mining_efficiency = tbl.mining_efficiency
inventory_slots = tbl.inventory_slots
end)
local on_market_timeout_finished = Token.register(function(params)
Template.market(params.surface, params.position, params.player_force, params.currency_item, {})
end)
local function update_mining_speed(force)
-- remove the current buff
local old_modifier = force.manual_mining_speed_modifier - mining_efficiency.active_modifier
-- update the active modifier
mining_efficiency.active_modifier = mining_efficiency.research_modifier + mining_efficiency.market_modifier
-- add the new active modifier to the non-buffed modifier
force.manual_mining_speed_modifier = old_modifier + mining_efficiency.active_modifier
end
local function update_inventory_slots(force)
-- remove the current buff
local old_modifier = force.character_inventory_slots_bonus - inventory_slots.active_modifier
-- update the active modifier
inventory_slots.active_modifier = inventory_slots.research_modifier + inventory_slots.market_modifier
-- add the new active modifier to the non-buffed modifier
force.character_inventory_slots_bonus = old_modifier + inventory_slots.active_modifier
end
local function update_market_contents(market)
local should_update_mining_speed = false
local should_update_inventory_slots = false
if (nil ~= stone_tracker.first_time_market_item) then
market.add_market_item(stone_tracker.first_time_market_item)
stone_tracker.first_time_market_item = nil
end
for _, unlockable in pairs(config.unlockables) do
local is_in_range = unlockable.stone > stone_tracker.previous_stone_sent_to_surface and unlockable.stone <= stone_tracker.stone_sent_to_surface
-- only add the item to the market if it's between the old and new stone range
if (is_in_range and unlockable.type == 'market') then
market.add_market_item({
price = {{config.currency_item, unlockable.prototype.price}},
offer = {type = 'give-item', item = unlockable.prototype.name, count = 1}
})
elseif (is_in_range and unlockable.type == 'buff' and unlockable.prototype.name == 'mining_speed') then
should_update_mining_speed = true
mining_efficiency.market_modifier = mining_efficiency.market_modifier + (unlockable.prototype.value / 100)
elseif (is_in_range and unlockable.type == 'buff' and unlockable.prototype.name == 'inventory_slot') then
should_update_inventory_slots = true
inventory_slots.market_modifier = inventory_slots.market_modifier + unlockable.prototype.value
end
end
local force
if (should_update_mining_speed) then
force = force or game.forces.player
update_mining_speed(force)
end
if (should_update_inventory_slots) then
force = force or game.forces.player
update_inventory_slots(force)
end
end
local function on_research_finished(event)
local force = game.forces.player
local current_modifier = mining_efficiency.research_modifier
local new_modifier = force.mining_drill_productivity_bonus * config.mining_speed_productivity_multiplier / 2
if (current_modifier == new_modifier) then
-- something else was researched
return
end
mining_efficiency.research_modifier = new_modifier
inventory_slots.research_modifier = (force.mining_drill_productivity_bonus / 2) * 100
update_inventory_slots(force)
update_mining_speed(force)
end
local function redraw_title(data)
data.frame.caption = stone_tracker.stone_sent_to_surface .. ' stone sent to the surface'
end
local function redraw_list(data)
local market_scroll_pane = data.market_scroll_pane
Gui.clear(market_scroll_pane)
for _, unlockable in pairs(config.unlockables) do
local is_unlocked = unlockable.stone <= stone_tracker.stone_sent_to_surface
local message
-- only add the item to the market if it's between the old and new stone range
if (unlockable.type == 'market') then
message = 'Market item: ' .. unlockable.prototype.name
elseif (unlockable.type == 'buff' and unlockable.prototype.name == 'mining_speed') then
message = 'Manual mining speed: +' .. unlockable.prototype.value .. '%'
elseif (unlockable.type == 'buff' and unlockable.prototype.name == 'inventory_slot') then
message = 'Inventory slot: +' .. unlockable.prototype.value
else
Debug.print('failed getting a message for: ' .. serpent.line(unlockable))
end
message = unlockable.stone .. ' stone: ' .. message
local label = market_scroll_pane.add({type = 'label', caption = message})
if (is_unlocked) then
label.style.font_color = {r = 1, g = 1, b = 1}
else
label.style.font_color = {r = 0.5, g = 0.5, b = 0.5}
end
end
end
local function on_market_item_purchased(event)
if (1 ~= event.offer_index) then
return
end
stone_tracker.previous_stone_sent_to_surface = stone_tracker.stone_sent_to_surface
stone_tracker.stone_sent_to_surface = stone_tracker.stone_sent_to_surface + (config.stone_to_surface_amount * event.count)
update_market_contents(event.market)
local frame = game.players[event.player_index].gui.center['Diggy.MarketExchange.Frame']
if frame and frame.valid then
local data = Gui.get_data(frame)
redraw_title(data)
redraw_list(data)
end
end
local function on_placed_entity(event)
if ('market' ~= event.entity.name) then
return
end
update_market_contents(event.entity)
end
function MarketExchange.get_extra_map_info(config)
return 'Market Exchange, trade your stone or send it to the surface'
end
local function toggle(event)
local player = event.player
local center = player.gui.center
local frame = center['Diggy.MarketExchange.Frame']
if (frame) then
Gui.destroy(frame)
return
end
frame = center.add({name = 'Diggy.MarketExchange.Frame', type = 'frame', direction = 'vertical'})
local market_scroll_pane = frame.add({type = 'scroll-pane'})
market_scroll_pane.style.maximal_height = 400
frame.add({ type = 'button', name = 'Diggy.MarketExchange.Button', caption = 'Close'})
local data = {
frame = frame,
market_scroll_pane = market_scroll_pane,
}
redraw_title(data)
redraw_list(data)
Gui.set_data(frame, data)
player.opened = frame
end
local function on_player_created(event)
game.players[event.player_index].gui.top.add({
name = 'Diggy.MarketExchange.Button',
type = 'sprite-button',
sprite = 'item/stone',
})
end
Gui.on_click('Diggy.MarketExchange.Button', toggle)
Gui.on_custom_close('Diggy.MarketExchange.Frame', function (event)
event.element.destroy()
end)
function MarketExchange.on_init()
Task.set_timeout_in_ticks(50, on_market_timeout_finished, {
surface = game.surfaces.nauvis,
position = config.market_spawn_position,
player_force = game.forces.player,
currency_item = config.currency_item,
})
update_mining_speed(game.forces.player)
end
--[[--
Registers all event handlers.
]]
function MarketExchange.register(cfg)
config = cfg
stone_tracker.first_time_market_item = {
price = {{config.currency_item, 50}},
offer = {type = 'nothing', effect_description = 'Send ' .. config.stone_to_surface_amount .. ' stone to the surface'}
}
Event.add(defines.events.on_research_finished, on_research_finished)
Event.add(defines.events.on_market_item_purchased, on_market_item_purchased)
Event.add(Template.events.on_placed_entity, on_placed_entity)
Event.add(defines.events.on_player_created, on_player_created)
end
return MarketExchange

View File

@ -0,0 +1,40 @@
--[[-- info
Provides the ability to refresh the map and generate darkness.
]]
-- dependencies
local Event = require 'utils.event'
local insert = table.insert
-- this
local RefreshMap = {}
--[[--
Registers all event handlers.
]]
function RefreshMap.register(config)
Event.add(defines.events.on_chunk_generated, function (event)
local tiles = {}
for x = 0, 31, 1 do
for y = 0, 31, 1 do
local target_x = event.area.left_top.x + x
local target_y = event.area.left_top.y + y
local tile = 'out-of-map'
if (target_x < 1 and target_y < 1 and target_x > -2 and target_y > -2) then
tile = 'lab-dark-1'
end
insert(tiles, {
name = tile,
position = {x = target_x, y = target_y}
})
end
end
event.surface.set_tiles(tiles)
end)
end
return RefreshMap

View File

@ -0,0 +1,96 @@
--[[-- info
Provides the ability to spawn random ores all over the place.
]]
-- dependencies
local Event = require 'utils.event'
local Debug = require 'map_gen.Diggy.Debug'
local Template = require 'map_gen.Diggy.Template'
local random = math.random
local sqrt = math.sqrt
local ceil = math.ceil
local floor = math.floor
-- this
local ScatteredResources = {}
local function get_name_by_random(collection)
local pre_calculated = random()
local current = 0
for name, probability in pairs(collection) do
current = current + probability
if (current >= pre_calculated) then
return name
end
end
Debug.print('Current \'' .. current .. '\' should be higher or equal to random \'' .. pre_calculated .. '\'')
end
local function spawn_resource(config, surface, x, y, distance)
local resource_name = get_name_by_random(config.resource_chances)
if (config.minimum_resource_distance[resource_name] > distance) then
return
end
local min_max = config.resource_richness_values[get_name_by_random(config.resource_richness_probability)]
local amount = ceil(random(min_max[1], min_max[2]) * (1 + ((distance / config.distance_richness_modifier) / 100)))
if ('crude-oil' == resource_name) then
amount = amount * config.oil_value_modifier
end
local position = {x = x, y = y}
Template.resources(surface, {{name = resource_name, position = position, amount = amount}})
end
--[[--
Registers all event handlers.
]]
function ScatteredResources.register(config)
function sum(t)
local sum = 0
for _, v in pairs(t) do
sum = sum + v
end
return sum
end
local resource_sum = sum(config.resource_chances)
if (1 ~= resource_sum) then
error('Expected a sum of 1.00, got \'' .. resource_sum .. '\' for config.feature.ScatteredResources.resource_chances.')
end
local richness_sum = sum(config.resource_richness_probability)
if (1 ~= richness_sum) then
error('Expected a sum of 1.00, got \'' .. richness_sum .. '\' for config.feature.ScatteredResources.resource_richness_probability.')
end
Event.add(Template.events.on_void_removed, function(event)
local x = event.old_tile.position.x
local y = event.old_tile.position.y
local distance = floor(sqrt(x^2 + y^2))
local calculated_probability = config.resource_probability + ((distance / config.distance_probability_modifier) / 100)
local probability = 0.7
if (calculated_probability < probability) then
probability = calculated_probability
end
if (probability > random()) then
spawn_resource(config, event.surface, x, y, distance)
end
end)
end
function ScatteredResources.get_extra_map_info(config)
return [[Scattered Resources, resources are everywhere!
Scans of the mine have shown greater amounts of resources to be deeper in the mine]]
end
return ScatteredResources

View File

@ -0,0 +1,32 @@
--[[-- info
Provides the ability to setup a player when first joined.
]]
-- dependencies
local Event = require 'utils.event'
local Debug = require 'map_gen.Diggy.Debug'
local math_random = math.random
-- this
local SetupPlayer = {}
--[[--
Registers all event handlers.
]]
function SetupPlayer.register(config)
Event.add(defines.events.on_player_created, function (event)
local player = game.players[event.player_index]
for _, item in pairs(config.starting_items) do
player.insert(item)
end
player.teleport({x = math_random(-4, 4) / 10, y = math_random(-4, 4) / 10})
Debug.cheat(function()
player.force.manual_mining_speed_modifier = config.cheats.manual_mining_speed_modifier
end)
end)
end
return SetupPlayer

View File

@ -0,0 +1,118 @@
--[[-- info
Provides the ability to make a simple room with contents
]]
-- dependencies
local Template = require 'map_gen.Diggy.Template'
local Perlin = require 'map_gen.shared.perlin_noise'
local Event = require 'utils.event'
local Debug = require'map_gen.Diggy.Debug'
local Task = require 'utils.Task'
local Token = require 'utils.global_token'
local Global = require 'utils.global'
-- this
local SimpleRoomGenerator = {}
local noise_used_map = {}
Global.register({
noise_used_map = noise_used_map,
}, function(tbl)
noise_used_map = tbl.noise_used_map
end)
local do_spawn_tile = Token.register(function(params)
Template.insert(params.surface, {params.tile}, {})
end)
local do_mine = Token.register(function(params)
local sand_rocks = params.surface.find_entities_filtered({position = params.position, name = 'sand-rock-big'})
if (0 == #sand_rocks) then
Debug.printPosition(params.position, 'missing rock when trying to mine.')
return
end
for _, rock in pairs(sand_rocks) do
rock.die()
end
end)
local function handle_noise(name, surface, position)
Task.set_timeout_in_ticks(1, do_mine, {surface = surface, position = position})
if ('water' == name) then
-- water is slower because for some odd reason it doesn't always want to mine it properly
Task.set_timeout_in_ticks(4, do_spawn_tile, { surface = surface, tile = { name = 'deepwater-green', position = position}})
return
end
if ('dirt' == name) then
return
end
error('No noise handled for type \'' .. name .. '\'')
end
--[[--
Registers all event handlers.
]]
function SimpleRoomGenerator.register(config)
local room_noise_minimum_distance_sq = config.room_noise_minimum_distance * config.room_noise_minimum_distance
local function get_noise(surface, x, y)
local seed = surface.map_gen_settings.seed + surface.index
return Perlin.noise(x * config.noise_variance, y * config.noise_variance, seed)
end
Event.add(Template.events.on_void_removed, function (event)
local position = event.old_tile.position
local x = position.x
local y = position.y
if (nil == noise_used_map[x]) then
noise_used_map[x] = {y = true}
elseif (nil == noise_used_map[x][y]) then
noise_used_map[x][y] = true
else
-- already used up noise at that point
return
end
local distance_sq = position.x^2 + position.y^2
if (distance_sq <= room_noise_minimum_distance_sq) then
return
end
local surface = event.surface
local noise = get_noise(surface, position.x, position.y)
for _, noise_range in pairs(config.room_noise_ranges) do
if (noise >= noise_range.min and noise <= noise_range.max) then
handle_noise(noise_range.name, surface, position)
end
end
end)
if (config.enable_noise_grid) then
Event.add(defines.events.on_chunk_generated, function (event)
local surface = event.surface
local area = event.area
for x = area.left_top.x, area.left_top.x + 31 do
for y = area.left_top.y, area.left_top.y + 31 do
Debug.print_grid_value(get_noise(surface, x, y), surface, {x = x, y = y})
end
end
end)
end
end
function SimpleRoomGenerator.get_extra_map_info(config)
return 'Simple Room Generator, digging around might open rooms!'
end
return SimpleRoomGenerator

View File

@ -0,0 +1,83 @@
--[[-- info
Provides the ability to create a pre-configured starting zone.
]]
-- dependencies
local Event = require 'utils.event'
local Token = require 'utils.global_token'
local Template = require 'map_gen.Diggy.Template'
local Debug = require 'map_gen.Diggy.Debug'
local DiggyCaveCollapse = require 'map_gen.Diggy.Feature.DiggyCaveCollapse'
local insert = table.insert
local random = math.random
local sqrt = math.sqrt
local floor = math.floor
-- this
local StartingZone = {}
--[[--
Registers all event handlers.
]]
function StartingZone.register(config)
local callback_token
local starting_zone_size = config.starting_size
local function on_chunk_generated(event)
local start_point_area = {{-0.9, -0.9}, {0.9, 0.9}}
local surface = event.surface
-- hack to figure out whether the important chunks are generated via Diggy.Feature.RefreshMap.
if (4 ~= surface.count_tiles_filtered({start_point_area, name = 'lab-dark-1'})) then
return
end
-- ensure a clean starting point
for _, entity in pairs(surface.find_entities_filtered({area = start_point_area, type = 'resource'})) do
entity.destroy()
end
local tiles = {}
local rocks = {}
for x = -starting_zone_size, starting_zone_size do
for y = -starting_zone_size, starting_zone_size do
local distance = floor(sqrt(x * x + y * y))
if (distance < starting_zone_size) then
if (distance > floor(starting_zone_size / 2)) then
insert(tiles, {name = 'dirt-' .. random(1, 7), position = {x = x, y = y}})
else
insert(tiles, {name = 'stone-path', position = {x = x, y = y}})
end
if (distance > starting_zone_size - 2) then
insert(rocks, {name = 'sand-rock-big', position = {x = x, y = y}})
end
-- hack to avoid starting area from collapsing
if (distance > floor(starting_zone_size / 10)) then
DiggyCaveCollapse.stress_map_blur_add(surface, {x = x, y = y}, -0.3)
end
end
end
end
Template.insert(event.surface, tiles, rocks)
Event.remove_removable(defines.events.on_chunk_generated, callback_token)
end
callback_token = Token.register(on_chunk_generated)
Event.add_removable(defines.events.on_chunk_generated, callback_token)
end
function StartingZone.on_init()
local surface = game.surfaces.nauvis
surface.daytime = 0.5
surface.freeze_daytime = 1
end
return StartingZone

42
map_gen/Diggy/Scanner.lua Normal file
View File

@ -0,0 +1,42 @@
-- dependencies
local insert = table.insert
-- this
local Scanner = {}
--[[--
returns a list with all direct positions that contain tile_search.
@param surface LuaSurface
@param position Position
@param tile_search string name of the tile to search for
@return table with 0~4 directions of which have the tile searched for adjacent
]]
function Scanner.scan_around_position(surface, position, tile_search)
local tile_found = {}
local get_tile = surface.get_tile
-- north
if (tile_search == get_tile(position.x, position.y - 1).name) then
insert(tile_found, {x = position.x, y = position.y - 1})
end
-- east
if (tile_search == get_tile(position.x + 1, position.y).name) then
insert(tile_found, {x = position.x + 1, y = position.y})
end
-- south
if (tile_search == get_tile(position.x, position.y + 1).name) then
insert(tile_found, {x = position.x, y = position.y + 1})
end
-- west
if (tile_search == get_tile(position.x - 1, position.y).name) then
insert(tile_found, {x = position.x - 1, y = position.y})
end
return tile_found;
end
return Scanner

View File

@ -0,0 +1,91 @@
-- dependencies
local Config = require 'map_gen.Diggy.Config'
local Debug = require 'map_gen.Diggy.Debug'
local ScenarioInfo = require 'info'
local Event = require 'utils.event'
require 'utils.list_utils'
require 'utils.utils'
-- this
local Scenario = {}
global.diggy_scenario_registered = false
--[[--
Allows calling a callback for each enabled feature.
Signature: callback(feature_name, Table feature_data) from {@see Config.features}.
@param if_enabled function to be called if enabled
]]
local function each_enabled_feature(if_enabled)
local type = type(if_enabled)
if ('function' ~= type) then
error('each_enabled_feature expects callback to be a function, given type: ' .. type)
end
for current_name, feature_data in pairs(Config.features) do
if (nil == feature_data.enabled) then
error('Feature ' .. current_name .. ' did not define the enabled property.')
end
if (feature_data.enabled) then
if_enabled(current_name, feature_data)
end
end
end
--[[--
Register the events required to initialize the scenario.
]]
function Scenario.register(debug)
if global.diggy_scenario_registered then
error('Cannot register the Diggy scenario multiple times.')
return
end
global.scenario.config.player_list.enable_coin_col = false
global.scenario.config.fish_market.enable = false
if ('boolean' == type(debug)) then
Config.Debug = debug
end
if (Config.debug) then
Debug.enable_debug()
end
if (Config.cheats) then
Debug.enable_cheats()
end
local extra_map_info = ''
each_enabled_feature(
function(feature_name, feature_config)
local feature = require ('map_gen.Diggy.Feature.' .. feature_name)
if ('function' ~= type(feature.register)) then
error('Feature ' .. feature_name .. ' did not define a register function.')
end
feature.register(feature_config)
if ('function' == type(feature.get_extra_map_info)) then
extra_map_info = extra_map_info .. feature.get_extra_map_info(feature_config) .. '\n\n'
end
if ('function' == type(feature.on_init)) then
Event.on_init(feature.on_init)
end
end
)
ScenarioInfo.set_map_name('Diggy')
ScenarioInfo.set_map_description('Dig your way through!')
ScenarioInfo.set_map_extra_info(extra_map_info)
global.diggy_scenario_registered = true
end
return Scenario

233
map_gen/Diggy/Template.lua Normal file
View File

@ -0,0 +1,233 @@
-- dependencies
local Task = require 'utils.Task'
local Token = require 'utils.global_token'
local Debug = require 'map_gen.Diggy.Debug'
local insert = table.insert
local min = math.min
local ceil = math.ceil
local raise_event = script.raise_event
-- this
local Template = {}
local tiles_per_call = 5 --how many tiles are inserted with each call of insert_action
local entities_per_call = 5 --how many entities are inserted with each call of insert_action
Template.events = {
--[[--
When an entity is placed via the template function.
- event.entity LuaEntity
]]
on_placed_entity = script.generate_event_name(),
--[[--
Triggers when an 'out-of-map' tile is placed on something else.
{surface, old_tile={name, position={x, y}}}
]]
on_void_added = script.generate_event_name(),
--[[--
Triggers when an 'out-of-map' tile is replaced by something else.
{surface, old_tile={name, position={x, y}}}
]]
on_void_removed = script.generate_event_name(),
}
local function insert_next_tiles(data)
local void_removed = {}
local void_added = {}
local surface = data.surface
local get_tile = surface.get_tile
local tiles = {}
pcall(
function()
--use pcall to assure tile_iterator is always incremented, to avoid endless loops
for i = data.tile_iterator, min(data.tile_iterator + tiles_per_call - 1, data.tiles_n) do
local new_tile = data.tiles[i]
insert(tiles, new_tile)
local current_tile = get_tile(new_tile.position.x, new_tile.position.y)
local current_is_void = current_tile.name == 'out-of-map'
local new_is_void = new_tile.name == 'out-of-map'
if (current_is_void and not new_is_void) then
insert(
void_removed,
{surface = surface, old_tile = {name = current_tile.name, position = current_tile.position}}
)
end
if (new_is_void and not current_is_void) then
insert(
void_added,
{surface = surface, old_tile = {name = current_tile.name, position = current_tile.position}}
)
end
end
end
)
data.tile_iterator = data.tile_iterator + tiles_per_call
surface.set_tiles(tiles)
for _, event in pairs(void_removed) do
raise_event(Template.events.on_void_removed, event)
end
for _, event in pairs(void_added) do
raise_event(Template.events.on_void_added, event)
end
end
local function insert_next_entities(data)
local created_entities = {}
local surface = data.surface
local create_entity = surface.create_entity
pcall(
function()
--use pcall to assure tile_iterator is always incremented, to avoid endless loops
for i = data.entity_iterator, min(data.entity_iterator + entities_per_call - 1, data.entities_n) do
local entity = data.entities[i]
local created_entity = create_entity(entity)
if (nil == created_entity) then
error('Failed creating entity ' .. entity.name .. ' on surface.')
end
insert(created_entities, created_entity)
end
end
)
data.entity_iterator = data.entity_iterator + entities_per_call
for _, entity in pairs(created_entities) do
raise_event(Template.events.on_placed_entity, {entity = entity})
end
return data.entity_iterator <= data.entities_n
end
local function insert_action(data)
if data.tile_iterator <= data.tiles_n then
insert_next_tiles(data)
return true
end
return insert_next_entities(data)
end
local insert_token = Token.register(insert_action)
--[[--
Inserts a batch of tiles and then entities.
@see LuaSurface.set_tiles
@see LuaSurface.entity
@param surface LuaSurface to put the tiles and entities on
@param tiles table of tiles as required by set_tiles
@param entities table of entities as required by create_entity
]]
function Template.insert(surface, tiles, entities)
tiles = tiles or {}
entities = entities or {}
local tiles_n = #tiles
local entities_n = #entities
local total_calls = ceil(tiles_n / tiles_per_call) + (entities_n / entities_per_call)
local data = {
tiles_n = tiles_n,
tile_iterator = 1,
entities_n = entities_n,
entity_iterator = 1,
surface = surface,
tiles = tiles,
entities = entities
}
local continue = true
for i = 1, 4 do
continue = insert_action(data)
if not continue then
return
end
end
if continue then
Task.queue_task(insert_token, data, total_calls - 4)
end
end
--[[--
Designed to spawn aliens, uses find_non_colliding_position.
@see LuaSurface.entity
@param surface LuaSurface to put the tiles and entities on
@param units table of entities as required by create_entity
@param non_colliding_distance int amount of tiles to scan around original position in case it's already taken
]]
function Template.units(surface, units, non_colliding_distance)
non_colliding_distance = non_colliding_distance or 1
local create_entity = surface.create_entity
local find_non_colliding_position = surface.find_non_colliding_position
for _, entity in pairs(units) do
local position = find_non_colliding_position(entity.name, entity.position, non_colliding_distance, 1)
if (nil ~= position) then
entity.position = position
create_entity(entity)
else
Debug.printPosition(entity.position, "Failed to spawn '" .. entity.name .. "'")
end
end
end
--[[--
Designed to spawn resources.
@see LuaSurface.entity
@param surface LuaSurface to put the tiles and entities on
@param resources table of entities as required by create_entity
]]
function Template.resources(surface, resources)
local create_entity = surface.create_entity
for _, entity in pairs(resources) do
create_entity(entity)
end
end
--[[--
Designed to spawn a market.
@param surface LuaSurface
@param position Position
@param force LuaForce
@param currency_item string
@param market_items Table
]]
function Template.market(surface, position, force, currency_item, market_inventory)
local market = surface.create_entity({name = 'market', position = position})
local add_market_item = market.add_market_item
market.destructible = false
for _, item in ipairs(market_inventory) do
add_market_item(item)
end
force.add_chart_tag(surface, {
icon = {type = 'item', name = currency_item},
text = ' Market',
position = position,
})
raise_event(Template.events.on_placed_entity, {entity = market})
end
return Template

View File

@ -0,0 +1,2 @@
-- authors Linaori, valansch
require 'map_gen.Diggy.Scenario'.register(_DEBUG)

View File

@ -57,7 +57,7 @@ function Perlin.noise(x, y, z)
y = y or 0
z = z or 0
-- This prevents integer inputs returning 0, which casues 'straight line' artifacts.
-- This prevents integer inputs returning 0, which causes 'straight line' artifacts.
x = x - 0.55077056353912
y = y - 0.131357755512
z = z - 0.20474238274619

View File

@ -20,6 +20,7 @@ local tiles_per_tick = 32
--require "map_gen.combined.dagobah_swamp"
--require "map_gen.combined.meteor_strike" --unfinished
--require 'map_gen.combined.cave_miner.cave_miner'
--require "map_gen.combined.diggy"
--presets--