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:
commit
3dad1db67d
@ -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'
|
||||
|
150
map_gen/Diggy/AlienEvolutionProgress.lua
Normal file
150
map_gen/Diggy/AlienEvolutionProgress.lua
Normal 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
246
map_gen/Diggy/Config.lua
Normal 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
121
map_gen/Diggy/Debug.lua
Normal 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
|
58
map_gen/Diggy/Feature/AlienSpawner.lua
Normal file
58
map_gen/Diggy/Feature/AlienSpawner.lua
Normal 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
|
652
map_gen/Diggy/Feature/DiggyCaveCollapse.lua
Normal file
652
map_gen/Diggy/Feature/DiggyCaveCollapse.lua
Normal 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
|
108
map_gen/Diggy/Feature/DiggyHole.lua
Normal file
108
map_gen/Diggy/Feature/DiggyHole.lua
Normal 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
|
263
map_gen/Diggy/Feature/MarketExchange.lua
Normal file
263
map_gen/Diggy/Feature/MarketExchange.lua
Normal 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
|
40
map_gen/Diggy/Feature/RefreshMap.lua
Normal file
40
map_gen/Diggy/Feature/RefreshMap.lua
Normal 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
|
96
map_gen/Diggy/Feature/ScatteredResources.lua
Normal file
96
map_gen/Diggy/Feature/ScatteredResources.lua
Normal 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
|
32
map_gen/Diggy/Feature/SetupPlayer.lua
Normal file
32
map_gen/Diggy/Feature/SetupPlayer.lua
Normal 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
|
118
map_gen/Diggy/Feature/SimpleRoomGenerator.lua
Normal file
118
map_gen/Diggy/Feature/SimpleRoomGenerator.lua
Normal 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
|
83
map_gen/Diggy/Feature/StartingZone.lua
Normal file
83
map_gen/Diggy/Feature/StartingZone.lua
Normal 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
42
map_gen/Diggy/Scanner.lua
Normal 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
|
91
map_gen/Diggy/Scenario.lua
Normal file
91
map_gen/Diggy/Scenario.lua
Normal 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
233
map_gen/Diggy/Template.lua
Normal 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
|
2
map_gen/combined/diggy.lua
Normal file
2
map_gen/combined/diggy.lua
Normal file
@ -0,0 +1,2 @@
|
||||
-- authors Linaori, valansch
|
||||
require 'map_gen.Diggy.Scenario'.register(_DEBUG)
|
@ -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
|
||||
|
@ -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--
|
||||
|
Loading…
Reference in New Issue
Block a user