1
0
mirror of https://github.com/ComfyFactory/ComfyFactorio.git synced 2024-12-28 23:06:38 +02:00
ComfyFactorio/maps/mountain_fortress_v3/generate.lua

638 lines
18 KiB
Lua
Raw Normal View History

2020-05-23 21:18:18 +02:00
local Market = require 'maps.mountain_fortress_v3.basic_markets'
local WPT = require 'maps.mountain_fortress_v3.table'
2020-05-17 12:23:55 +02:00
local Loot = require 'maps.mountain_fortress_v3.loot'
local Task = require 'utils.task'
local Token = require 'utils.token'
local Event = require 'utils.event'
local Terrain = require 'maps.mountain_fortress_v3.terrain'
local WD = require 'modules.wave_defense.table'
local BiterHealthBooster = require 'modules.biter_health_booster_v2'
2020-05-17 12:23:55 +02:00
2020-08-09 20:22:33 +02:00
local Public = {}
local random = math.random
local abs = math.abs
local ceil = math.ceil
2021-12-06 17:22:25 +02:00
local round = math.round
2020-07-25 22:22:21 +02:00
local queue_task = Task.queue_task
2020-06-07 13:33:24 +02:00
local tiles_per_call = 8
2020-08-09 20:22:33 +02:00
local total_calls = ceil(1024 / tiles_per_call)
2020-05-20 09:09:39 +02:00
local regen_decoratives = false
local generate_map = Terrain.heavy_functions
2022-04-07 00:17:41 +02:00
local winter_mode = false
2020-12-20 20:56:26 +02:00
local wintery_type = {
['simple-entity'] = true,
['tree'] = true,
['fish'] = true,
2020-12-20 21:40:12 +02:00
['market'] = true,
2020-12-20 20:56:26 +02:00
['locomotive'] = true,
['cargo-wagon'] = true
}
2020-05-17 12:23:55 +02:00
-- Set to false by modules that want to control the on_chunk_generated event themselves.
Public.enable_register_events = true
-- Simple "loop" that is UPS friendly.
local function get_position(data)
data.yv = data.yv + 1
if data.yv == 32 then
if data.xv == 32 then
data.xv = 0
end
if data.yv == 32 then
data.yv = 0
end
data.xv = data.xv + 1
end
data.position = {x = data.top_x + data.xv, y = data.top_y + data.yv}
end
2020-05-17 12:23:55 +02:00
local function do_tile_inner(tiles, tile, pos)
if type(tile) == 'string' then
2020-06-07 13:33:24 +02:00
tiles[#tiles + 1] = {name = tile, position = pos}
2020-05-17 12:23:55 +02:00
end
end
local function do_tile(x, y, data, shape)
2020-05-17 12:23:55 +02:00
local pos = {x, y}
-- local coords need to be 'centered' to allow for correct rotation and scaling.
local tile = shape(data)
2020-05-17 12:23:55 +02:00
if type(tile) == 'table' then
do_tile_inner(data.tiles, tile.tile, pos)
2020-08-04 12:10:15 +02:00
local hidden_tile = tile.hidden_tile
if hidden_tile then
data.hidden_tiles[#data.hidden_tiles + 1] = {tile = hidden_tile, position = pos}
end
2020-05-17 12:23:55 +02:00
local entities = tile.entities
if entities then
2020-08-04 12:10:15 +02:00
for _, entity in ipairs(entities) do
2020-05-17 12:23:55 +02:00
if not entity.position then
entity.position = pos
end
2020-06-07 13:33:24 +02:00
data.entities[#data.entities + 1] = entity
2020-05-17 12:23:55 +02:00
end
end
2020-06-25 17:59:16 +02:00
local buildings = tile.buildings
if buildings then
2020-08-04 12:10:15 +02:00
for _, entity in ipairs(buildings) do
2020-06-25 17:59:16 +02:00
if not entity.position then
entity.position = pos
end
data.buildings[#data.buildings + 1] = entity
end
end
2020-05-17 12:23:55 +02:00
local decoratives = tile.decoratives
if decoratives then
2020-08-04 12:10:15 +02:00
for _, decorative in ipairs(decoratives) do
2020-06-07 13:33:24 +02:00
data.decoratives[#data.decoratives + 1] = decorative
2020-05-17 12:23:55 +02:00
end
end
local markets = tile.markets
if markets then
2020-08-04 12:10:15 +02:00
for _, t in ipairs(markets) do
2020-05-17 12:23:55 +02:00
if not t.position then
t.position = pos
end
2020-06-07 13:33:24 +02:00
data.markets[#data.markets + 1] = t
2020-05-17 12:23:55 +02:00
end
end
local treasure = tile.treasure
if treasure then
2020-08-04 12:10:15 +02:00
for _, t in ipairs(treasure) do
2020-05-17 12:23:55 +02:00
if not t.position then
t.position = pos
end
2020-06-07 13:33:24 +02:00
data.treasure[#data.treasure + 1] = t
2020-05-17 12:23:55 +02:00
end
end
else
do_tile_inner(data.tiles, tile, pos)
end
end
local function do_row(row, data, shape)
local y = data.top_y + row
local top_x = data.top_x
local tiles = data.tiles
data.y = y
for x = top_x, top_x + 31 do
data.x = x
local pos = {data.x, data.y}
get_position(data)
2020-05-17 12:23:55 +02:00
-- local coords need to be 'centered' to allow for correct rotation and scaling.
local tile = shape(data)
2020-05-17 12:23:55 +02:00
if type(tile) == 'table' then
do_tile_inner(tiles, tile.tile, pos)
2020-08-04 12:10:15 +02:00
local hidden_tile = tile.hidden_tile
if hidden_tile then
data.hidden_tiles[#data.hidden_tiles + 1] = {tile = hidden_tile, position = pos}
end
2020-05-17 12:23:55 +02:00
local entities = tile.entities
if entities then
2020-08-04 12:10:15 +02:00
for _, entity in ipairs(entities) do
2020-05-17 12:23:55 +02:00
if not entity.position then
entity.position = pos
end
2020-06-07 13:33:24 +02:00
data.entities[#data.entities + 1] = entity
2020-05-17 12:23:55 +02:00
end
end
2020-06-25 17:59:16 +02:00
local buildings = tile.buildings
if buildings then
2020-08-04 12:10:15 +02:00
for _, entity in ipairs(buildings) do
2020-06-25 17:59:16 +02:00
if not entity.position then
entity.position = pos
end
data.buildings[#data.buildings + 1] = entity
end
end
2020-05-17 12:23:55 +02:00
local decoratives = tile.decoratives
if decoratives then
2020-08-04 12:10:15 +02:00
for _, decorative in ipairs(decoratives) do
2020-05-17 12:23:55 +02:00
if not decorative.position then
decorative.position = pos
end
2020-06-07 13:33:24 +02:00
data.decoratives[#data.decoratives + 1] = decorative
2020-05-17 12:23:55 +02:00
end
end
local markets = tile.markets
if markets then
2020-08-04 12:10:15 +02:00
for _, t in ipairs(markets) do
2020-05-17 12:23:55 +02:00
if not t.position then
t.position = pos
end
2020-06-07 13:33:24 +02:00
data.markets[#data.markets + 1] = t
2020-05-17 12:23:55 +02:00
end
end
local treasure = tile.treasure
if treasure then
2020-08-04 12:10:15 +02:00
for _, t in ipairs(treasure) do
2020-05-17 12:23:55 +02:00
if not t.position then
t.position = pos
end
2020-06-07 13:33:24 +02:00
data.treasure[#data.treasure + 1] = t
2020-05-17 12:23:55 +02:00
end
end
else
do_tile_inner(tiles, tile, pos)
end
end
end
local function do_place_treasure(data)
local surface = data.surface
local treasure = data.treasure
if #treasure == 0 then
return
end
2020-09-25 11:08:15 +02:00
2020-10-21 23:17:17 +02:00
for _, e in ipairs(data.treasure) do
if random(1, 6) == 1 then
e.chest = 'iron-chest'
2020-05-17 12:23:55 +02:00
end
2020-10-21 23:17:17 +02:00
Loot.add(surface, e.position, e.chest)
end
2020-05-17 12:23:55 +02:00
end
local function do_place_markets(data)
local markets = data.markets
local surface = data.surface
if #markets == 0 then
return
end
2020-10-21 23:17:17 +02:00
local pos = markets[random(1, #markets)]
if
surface.count_entities_filtered {
area = {{pos.x - 96, pos.y - 96}, {pos.x + 96, pos.y + 96}},
name = 'market',
limit = 1
} == 0
then
local market = Market.mountain_market(surface, pos, abs(pos.y) * 0.004)
market.destructible = false
end
2020-05-17 12:23:55 +02:00
end
local function do_place_tiles(data)
2020-08-04 12:10:15 +02:00
local surface = data.surface
2020-10-21 23:17:17 +02:00
surface.set_tiles(data.tiles, true)
2020-08-04 12:10:15 +02:00
end
local function do_place_hidden_tiles(data)
local surface = data.surface
2020-10-21 23:17:17 +02:00
surface.set_tiles(data.hidden_tiles, true)
2020-05-17 12:23:55 +02:00
end
local function do_place_decoratives(data)
2020-07-25 22:22:21 +02:00
local surface = data.surface
2020-10-21 23:17:17 +02:00
if regen_decoratives then
surface.regenerate_decorative(nil, {{data.top_x / 32, data.top_y / 32}})
end
2020-05-17 12:23:55 +02:00
2020-10-21 23:17:17 +02:00
local dec = data.decoratives
if #dec > 0 then
surface.create_decoratives({check_collision = true, decoratives = dec})
end
2020-05-17 12:23:55 +02:00
end
2020-06-25 17:59:16 +02:00
local function do_place_buildings(data)
local surface = data.surface
local entity
local callback
2020-10-21 23:17:17 +02:00
for _, e in ipairs(data.buildings) do
if e.e_type then
local p = e.position
if
surface.count_entities_filtered {
area = {{p.x - 32, p.y - 32}, {p.x + 32, p.y + 32}},
type = e.e_type,
limit = 1
} == 0
then
entity = surface.create_entity(e)
if entity and entity.valid then
if e.direction then
entity.direction = e.direction
end
if e.force then
entity.force = e.force
2020-06-25 17:59:16 +02:00
end
if e.callback then
local c = e.callback.callback
if c then
local d = {callback_data = e.callback.data}
if not d then
callback = Token.get(c)
callback(entity)
else
callback = Token.get(c)
callback(entity, d)
end
end
2020-10-21 23:17:17 +02:00
end
2020-06-25 17:59:16 +02:00
end
end
end
2020-10-21 23:17:17 +02:00
end
2020-06-25 17:59:16 +02:00
end
2020-12-20 20:56:26 +02:00
local function wintery(ent, extra_lights)
if not winter_mode then
return false
end
local colors = {{255, 0, 0}, {0, 255, 0}, {0, 0, 255}}
local function add_light(e)
local color = colors[math.random(1, 3)]
local scale = extra_lights or 1
rendering.draw_light(
{
sprite = 'utility/light_small',
orientation = 1,
scale = scale,
intensity = 1,
minimum_darkness = 0,
oriented = false,
color = color,
target = e,
target_offset = {0, -0.5},
surface = e.surface
}
)
end
if not (ent and ent.valid) then
return
end
if wintery_type[ent.type] then
if ent.type == 'simple-entity' then
2021-11-28 22:20:23 +02:00
if random(1, 64) == 1 then
return add_light(ent)
end
else
if random(1, 4) == 1 then
return add_light(ent)
2020-12-20 20:56:26 +02:00
end
end
end
return true
end
2020-05-17 12:23:55 +02:00
local function do_place_entities(data)
local surface = data.surface
local entity
2020-05-21 23:08:23 +02:00
local callback
2020-10-21 23:17:17 +02:00
for _, e in ipairs(data.entities) do
if e.collision then
if surface.can_place_entity(e) then
entity = surface.create_entity(e)
if entity then
2021-12-06 17:22:25 +02:00
if e.note then -- flamethrower-turret and artillery-turret are at default health, only gun-turret is modified
local modified_unit_health = WD.get('modified_unit_health')
2021-12-06 17:22:25 +02:00
local final_health = round(modified_unit_health.current_value * 0.5, 3)
if final_health < 1 then
final_health = 1
end
BiterHealthBooster.add_unit(entity, final_health)
end
wintery(entity)
if e.direction then
entity.direction = e.direction
end
if e.force then
entity.force = e.force
end
if e.amount then
entity.amount = e.amount
end
if e.callback then
local c = e.callback.callback
if not c then
return
end
local d = {callback_data = e.callback.data}
if not d then
callback = Token.get(c)
callback(entity)
else
callback = Token.get(c)
callback(entity, d)
end
end
end
end
else
entity = surface.create_entity(e)
if entity then
2021-12-06 17:22:25 +02:00
if e.note then -- small-worm-turret, medium-worm-turret, big-worm-turret, behemoth-worm-turret
local modified_unit_health = WD.get('modified_unit_health')
2021-12-06 17:22:25 +02:00
local worm_unit_settings = WD.get('worm_unit_settings')
local final_health = round(modified_unit_health.current_value * worm_unit_settings.scale_units_by_health[entity.name], 3)
if final_health < 1 then
final_health = 1
end
BiterHealthBooster.add_unit(entity, final_health)
end
2020-12-20 20:56:26 +02:00
wintery(entity)
if e.direction then
2020-10-21 23:17:17 +02:00
entity.direction = e.direction
end
if e.force then
2020-10-21 23:17:17 +02:00
entity.force = e.force
end
if e.amount then
entity.amount = e.amount
end
if e.callback then
2020-10-21 23:17:17 +02:00
local c = e.callback.callback
if c then
local d = {callback_data = e.callback.data}
if not d then
callback = Token.get(c)
callback(entity)
else
callback = Token.get(c)
callback(entity, d)
end
2020-07-25 22:22:21 +02:00
end
2020-10-21 23:17:17 +02:00
end
end
2020-05-17 12:23:55 +02:00
end
2020-10-21 23:17:17 +02:00
end
2020-05-17 12:23:55 +02:00
end
local function run_chart_update(data)
local x = data.top_x / 32
local y = data.top_y / 32
2020-07-25 22:22:21 +02:00
local surface = data.surface
if not surface or not surface.valid then
return
end
2020-07-25 22:22:21 +02:00
if game.forces.player.is_chunk_charted(surface, {x, y}) then
2020-05-17 12:23:55 +02:00
-- Don't use full area, otherwise adjacent chunks get charted
game.forces.player.chart(
2020-07-25 22:22:21 +02:00
surface,
2020-05-17 12:23:55 +02:00
{
{data.top_x, data.top_y},
{data.top_x + 1, data.top_y + 1}
}
)
end
end
local function map_gen_action(data)
local state = data.y
if state < 32 then
local shape = generate_map
2020-05-17 12:23:55 +02:00
if shape == nil then
return false
end
2020-06-07 13:33:24 +02:00
if not data.surface.valid then
return
end
local count = tiles_per_call
2020-05-17 12:23:55 +02:00
local y = state + data.top_y
local x = data.x
local max_x = data.top_x + 32
data.y = y
repeat
count = count - 1
get_position(data)
do_tile(x, y, data, shape)
2020-05-17 12:23:55 +02:00
x = x + 1
2020-05-21 23:08:23 +02:00
2020-05-17 12:23:55 +02:00
if x == max_x then
y = y + 1
if y == data.top_y + 32 then
break
end
x = data.top_x
data.y = y
end
data.x = x
until count == 0
data.y = y - data.top_y
return true
elseif state == 32 then
do_place_tiles(data)
data.y = 33
return true
elseif state == 33 then
2020-08-04 12:10:15 +02:00
do_place_hidden_tiles(data)
2020-05-17 12:23:55 +02:00
data.y = 34
return true
elseif state == 34 then
2020-08-04 12:10:15 +02:00
do_place_entities(data)
2020-05-17 12:23:55 +02:00
data.y = 35
return true
elseif state == 35 then
2020-08-04 12:10:15 +02:00
do_place_buildings(data)
2020-05-17 12:23:55 +02:00
data.y = 36
return true
elseif state == 36 then
2020-08-04 12:10:15 +02:00
do_place_markets(data)
2020-05-17 12:23:55 +02:00
data.y = 37
return true
elseif state == 37 then
2020-08-04 12:10:15 +02:00
do_place_treasure(data)
2020-06-25 17:59:16 +02:00
data.y = 38
return true
elseif state == 38 then
2020-08-04 12:10:15 +02:00
do_place_decoratives(data)
data.y = 39
return true
elseif state == 39 then
2020-05-17 12:23:55 +02:00
run_chart_update(data)
return false
end
end
local map_gen_action_token = Token.register(map_gen_action)
--- Adds generation of a Chunk of the map to the queue
-- @param event <table> the event table from on_chunk_generated
function Public.schedule_chunk(event)
local surface = event.surface
local shape = generate_map
2020-05-17 12:23:55 +02:00
2020-06-07 13:33:24 +02:00
if event.tick < 1 then
return
end
2020-05-17 12:23:55 +02:00
if not surface.valid then
return
end
if not shape then
return
end
local area = event.area
local data = {
yv = -0,
2020-05-23 21:18:18 +02:00
xv = 0,
2020-05-17 12:23:55 +02:00
y = 0,
x = area.left_top.x,
area = area,
top_x = area.left_top.x,
top_y = area.left_top.y,
surface = surface,
tiles = {},
2020-08-04 12:10:15 +02:00
hidden_tiles = {},
2020-05-17 12:23:55 +02:00
entities = {},
2020-06-25 17:59:16 +02:00
buildings = {},
2020-05-17 12:23:55 +02:00
decoratives = {},
markets = {},
treasure = {}
}
2020-07-25 22:22:21 +02:00
if not data.surface or not data.surface.valid then
2020-05-17 12:23:55 +02:00
return
end
2020-07-25 22:22:21 +02:00
queue_task(map_gen_action_token, data, total_calls)
2020-05-17 12:23:55 +02:00
end
--- Generates a Chunk of map when called
-- @param event <table> the event table from on_chunk_generated
function Public.do_chunk(event)
local surface = event.surface
local shape = generate_map
2020-05-17 12:23:55 +02:00
if not surface.valid then
return
end
if not shape then
return
end
local area = event.area
local data = {
2020-06-05 23:53:58 +02:00
yv = -0,
xv = 0,
2020-05-17 12:23:55 +02:00
area = area,
top_x = area.left_top.x,
top_y = area.left_top.y,
surface = surface,
tiles = {},
2020-08-04 12:10:15 +02:00
hidden_tiles = {},
2020-05-17 12:23:55 +02:00
entities = {},
2020-06-25 17:59:16 +02:00
buildings = {},
2020-05-17 12:23:55 +02:00
decoratives = {},
markets = {},
treasure = {}
}
if not data.surface.valid then
return
end
for row = 0, 31 do
do_row(row, data, shape)
end
do_place_tiles(data)
2020-08-04 12:10:15 +02:00
do_place_hidden_tiles(data)
2020-05-17 12:23:55 +02:00
do_place_entities(data)
2020-06-25 17:59:16 +02:00
do_place_buildings(data)
2020-05-17 12:23:55 +02:00
do_place_decoratives(data)
do_place_markets(data)
do_place_treasure(data)
end
local do_chunk = Public.do_chunk
local schedule_chunk = Public.schedule_chunk
local function on_chunk(event)
local force_chunk = WPT.get('force_chunk')
local stop_chunk = WPT.get('stop_chunk')
if stop_chunk then
return
end
2020-05-20 09:09:39 +02:00
if force_chunk then
2020-05-17 12:23:55 +02:00
do_chunk(event)
else
schedule_chunk(event)
end
end
2020-05-20 09:09:39 +02:00
Event.add(defines.events.on_chunk_generated, on_chunk)
2020-05-17 12:23:55 +02:00
2020-12-20 20:56:26 +02:00
Public.wintery = wintery
2020-05-17 12:23:55 +02:00
return Public