1
0
mirror of https://github.com/Refactorio/RedMew.git synced 2024-12-14 10:13:13 +02:00
RedMew/map_gen/maps/diggy/feature/alien_spawner.lua
2020-07-31 11:07:09 -04:00

210 lines
7.2 KiB
Lua

--[[-- info
Provides the ability to spawn aliens.
]]
-- dependencies
require 'utils.table'
local Event = require 'utils.event'
local Global = require 'utils.global'
local Token = require 'utils.token'
local Task = require 'utils.task'
local AlienEvolutionProgress = require 'utils.alien_evolution_progress'
local Debug = require 'map_gen.maps.diggy.debug'
local Template = require 'map_gen.maps.diggy.template'
local CreateParticles = require 'features.create_particles'
local format_number = require 'util'.format_number
local random = math.random
local floor = math.floor
local ceil = math.ceil
local size = table.size
local pairs = pairs
local raise_event = script.raise_event
local get_aliens = AlienEvolutionProgress.get_aliens
local create_spawner_request = AlienEvolutionProgress.create_spawner_request
local set_timeout_in_ticks = Task.set_timeout_in_ticks
local destroy_rock = CreateParticles.destroy_rock
-- this
local AlienSpawner = {}
local config
local memory = {
alien_collision_boxes = {},
}
local locations_to_scan = {
{x = 0, y = -1.5}, -- up
{x = 1.5, y = 0}, -- right
{x = 0, y = 1.5}, -- bottom
{x = -1.5, y = 0}, -- left
}
Global.register_init({
memory = memory,
}, function(tbl)
for name, prototype in pairs(game.entity_prototypes) do
if prototype.type == 'unit' and prototype.subgroup.name == 'enemies' then
tbl.memory.alien_collision_boxes[name] = prototype.collision_box
end
end
end, function(tbl)
memory = tbl.memory
end)
local rocks_to_find = Template.diggy_rocks
---Triggers mining at the collision_box of the alien, to free it
local do_alien_mining = Token.register(function(params)
local surface = params.surface
local create_entity = surface.create_entity
local create_particle = surface.create_particle
local find_non_colliding_position = surface.find_non_colliding_position
local rocks = surface.find_entities_filtered({area = params.clear_area, name = rocks_to_find})
local rock_count = #rocks
if rock_count > 0 then
-- with multiple rocks opening at once, it will spawn less particles in total per rock
local particle_count
if rock_count == 1 then
particle_count = 15
elseif rock_count == 2 then
particle_count = 10
else
particle_count = 5
end
for rock_index = rock_count, 1, -1 do
local rock = rocks[rock_index]
raise_event(defines.events.script_raised_destroy, {entity = rock, cause = "alien_emerges"})
destroy_rock(create_particle, particle_count, rock.position)
rock.destroy()
end
end
local spawn_location = params.spawn_location
-- amount is not used for aliens prototypes, it just carries along in the params
local amount = spawn_location.amount
while amount > 0 do
spawn_location.position = find_non_colliding_position(spawn_location.name, spawn_location.position, 2, 0.4) or spawn_location.position
create_entity(spawn_location)
amount = amount - 1
end
end)
---Spawns aliens given the parameters.
---@param aliens table index is the name, value is the amount of biters to spawn
---@param force LuaForce of the biters
---@param surface LuaSurface to spawn on
---@param x number
---@param y number
local function spawn_aliens(aliens, force, surface, x, y)
local position = {x = x, y = y}
local count_tiles_filtered = surface.count_tiles_filtered
local spawn_count = 0
local alien_collision_boxes = memory.alien_collision_boxes
for name, amount in pairs(aliens) do
local collision_box = alien_collision_boxes[name]
if not collision_box then
Debug.print_position(position, 'Unable to find prototype data for ' .. name)
break
end
local left_top = collision_box.left_top
local right_bottom = collision_box.right_bottom
local left_top_x = left_top.x * 1.6
local left_top_y = left_top.y * 1.6
local right_bottom_x = right_bottom.x * 1.6
local right_bottom_y = right_bottom.y * 1.6
for i = #locations_to_scan, 1, -1 do
local direction = locations_to_scan[i]
local x_center = direction.x + x
local y_center = direction.y + y
-- *_center indicates the offset center relative to the location where it should spawn
-- the area is composed of the bounding_box of the alien with a bigger size so it has space to move
local offset_area = {
left_top = {
x = floor(x_center + left_top_x),
y = floor(y_center + left_top_y),
},
right_bottom = {
x = ceil(x_center + right_bottom_x),
y = ceil(y_center + right_bottom_y),
},
}
-- can't spawn properly if void is present
if count_tiles_filtered({area = offset_area, name = 'out-of-map'}) == 0 then
spawn_count = spawn_count + 1
set_timeout_in_ticks(spawn_count, do_alien_mining, {
surface = surface,
clear_area = offset_area,
spawn_location = {
name = name,
position = {x = x_center, y = y_center},
force = force,
amount = amount
},
})
break
end
end
end
end
--[[--
Registers all event handlers.
]]
function AlienSpawner.register(cfg)
config = cfg
local alien_minimum_distance_square = cfg.alien_minimum_distance ^ 2
local alien_probability = cfg.alien_probability
local hail_hydra = cfg.hail_hydra
local evolution_per_void_removed = cfg.evolution_per_void_removed
if size(hail_hydra) > 0 then
global.config.hail_hydra.enabled = true
global.config.hail_hydra.hydras = hail_hydra
end
Event.add(Template.events.on_void_removed, function (event)
local force = game.forces.enemy
local evolution_factor = force.evolution_factor
force.evolution_factor = evolution_factor + evolution_per_void_removed
local position = event.position
local x = position.x
local y = position.y
if (x * x + y * y < alien_minimum_distance_square or alien_probability < random()) then
return
end
spawn_aliens(get_aliens(create_spawner_request(2), force.evolution_factor), force, event.surface, x, y)
end)
end
function AlienSpawner.get_extra_map_info(cfg)
local multiplier = 10000
return [[Alien Spawner, aliens might spawn when mining!
Spawn chance: ]] .. (cfg.alien_probability * 100) .. [[%
Minimum spawn distance: ]] .. cfg.alien_minimum_distance .. [[ tiles
Evolution is increased by ]] ..(multiplier * cfg.evolution_per_void_removed * 100) .. '% per ' .. format_number(multiplier, true) .. [[ mine size
]]
end
function AlienSpawner.on_init()
if config.evolution_over_time_factor then
game.map_settings.enemy_evolution.time_factor = config.evolution_over_time_factor
end
game.forces.enemy.evolution_factor = config.initial_evolution * 0.01
game.map_settings.pollution.enabled = false
end
return AlienSpawner