2018-11-18 18:12:00 +02:00
|
|
|
--[[-- info
|
|
|
|
Provides the ability to spawn aliens.
|
|
|
|
]]
|
|
|
|
|
|
|
|
-- dependencies
|
2018-12-01 18:32:54 +02:00
|
|
|
require 'utils.table'
|
2018-11-18 18:12:00 +02:00
|
|
|
local Event = require 'utils.event'
|
2018-11-21 16:26:04 +02:00
|
|
|
local Global = require 'utils.global'
|
2018-11-26 03:07:03 +02:00
|
|
|
local Token = require 'utils.token'
|
2018-11-27 09:06:02 +02:00
|
|
|
local Task = require 'utils.Task'
|
2018-12-09 20:10:16 +02:00
|
|
|
local AlienEvolutionProgress = require 'utils.alien_evolution_progress'
|
2018-11-18 18:12:00 +02:00
|
|
|
local Debug = require 'map_gen.Diggy.Debug'
|
|
|
|
local Template = require 'map_gen.Diggy.Template'
|
2018-11-24 14:53:06 +02:00
|
|
|
local CreateParticles = require 'features.create_particles'
|
2018-11-18 18:12:00 +02:00
|
|
|
local random = math.random
|
2018-11-21 16:26:04 +02:00
|
|
|
local floor = math.floor
|
|
|
|
local ceil = math.ceil
|
2018-12-01 18:32:54 +02:00
|
|
|
local size = table.size
|
2018-12-09 20:15:58 +02:00
|
|
|
local pairs = pairs
|
2018-11-21 16:26:04 +02:00
|
|
|
local raise_event = script.raise_event
|
2018-11-18 18:12:00 +02:00
|
|
|
|
|
|
|
-- this
|
|
|
|
local AlienSpawner = {}
|
|
|
|
|
2018-12-09 20:15:58 +02:00
|
|
|
local memory = {
|
|
|
|
alien_collision_boxes = {},
|
|
|
|
}
|
2018-11-26 22:37:41 +02:00
|
|
|
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
|
|
|
|
}
|
2018-11-21 16:26:04 +02:00
|
|
|
|
|
|
|
Global.register_init({
|
2018-12-09 20:15:58 +02:00
|
|
|
memory = memory,
|
2018-11-21 16:26:04 +02:00
|
|
|
}, function(tbl)
|
|
|
|
for name, prototype in pairs(game.entity_prototypes) do
|
|
|
|
if prototype.type == 'unit' and prototype.subgroup.name == 'enemies' then
|
2018-12-09 20:15:58 +02:00
|
|
|
tbl.memory.alien_collision_boxes[name] = prototype.collision_box
|
2018-11-21 16:26:04 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end, function(tbl)
|
2018-12-09 20:15:58 +02:00
|
|
|
memory = tbl.memory
|
2018-11-21 16:26:04 +02:00
|
|
|
end)
|
|
|
|
|
2018-12-01 18:32:54 +02:00
|
|
|
local rocks_to_find = Template.diggy_rocks
|
|
|
|
|
|
|
|
local function create_attack_command(position, target)
|
|
|
|
local command = {type = defines.command.attack_area, destination = position, radius = 10}
|
|
|
|
if target then
|
|
|
|
command = {
|
|
|
|
type = defines.command.compound,
|
|
|
|
structure_type = defines.compound_command.logical_or,
|
|
|
|
commands = {
|
|
|
|
{type = defines.command.attack, target = target},
|
|
|
|
command,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
return command
|
|
|
|
end
|
2018-11-26 22:37:41 +02:00
|
|
|
|
2018-11-21 16:26:04 +02:00
|
|
|
---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 find_non_colliding_position = surface.find_non_colliding_position
|
|
|
|
|
2018-11-26 22:37:41 +02:00
|
|
|
local rocks = surface.find_entities_filtered({area = params.clear_area, name = rocks_to_find})
|
2018-11-18 18:12:00 +02:00
|
|
|
|
2018-11-26 22:37:41 +02:00
|
|
|
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
|
2018-11-21 16:26:04 +02:00
|
|
|
end
|
|
|
|
|
2018-11-26 22:37:41 +02:00
|
|
|
for rock_index = rock_count, 1, -1 do
|
|
|
|
local rock = rocks[rock_index]
|
2018-11-21 16:26:04 +02:00
|
|
|
raise_event(defines.events.on_entity_died, {entity = rock})
|
2018-11-23 23:04:55 +02:00
|
|
|
CreateParticles.destroy_rock(create_entity, particle_count, rock.position)
|
2018-11-21 16:26:04 +02:00
|
|
|
rock.destroy()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2018-11-26 22:37:41 +02:00
|
|
|
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
|
2018-11-18 18:12:00 +02:00
|
|
|
end
|
2018-11-21 16:26:04 +02:00
|
|
|
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
|
|
|
|
|
2018-11-26 22:37:41 +02:00
|
|
|
local spawn_count = 0
|
2018-11-21 16:26:04 +02:00
|
|
|
for name, amount in pairs(aliens) do
|
2018-12-09 20:15:58 +02:00
|
|
|
local collision_box = memory.alien_collision_boxes[name]
|
|
|
|
if not collision_box then
|
2018-11-21 16:26:04 +02:00
|
|
|
Debug.print_position(position, 'Unable to find prototype data for ' .. name)
|
|
|
|
break
|
|
|
|
end
|
|
|
|
|
2018-12-09 20:15:58 +02:00
|
|
|
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
|
2018-11-21 16:26:04 +02:00
|
|
|
|
2018-11-26 22:37:41 +02:00
|
|
|
for i = #locations_to_scan, 1, -1 do
|
|
|
|
local direction = locations_to_scan[i]
|
2018-11-21 16:26:04 +02:00
|
|
|
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
|
2018-11-26 22:37:41 +02:00
|
|
|
spawn_count = spawn_count + 1
|
|
|
|
Task.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
|
|
|
|
},
|
|
|
|
})
|
2018-11-21 16:26:04 +02:00
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
2018-11-18 18:12:00 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
--[[--
|
|
|
|
Registers all event handlers.
|
|
|
|
]]
|
|
|
|
function AlienSpawner.register(config)
|
|
|
|
local alien_minimum_distance_square = config.alien_minimum_distance ^ 2
|
2018-11-21 16:26:04 +02:00
|
|
|
local alien_probability = config.alien_probability
|
|
|
|
local hail_hydra = config.hail_hydra
|
|
|
|
|
2018-12-01 18:32:54 +02:00
|
|
|
if size(hail_hydra) > 0 then
|
2018-11-21 16:26:04 +02:00
|
|
|
Event.add(defines.events.on_entity_died, function (event)
|
|
|
|
local entity = event.entity
|
|
|
|
local name = entity.name
|
|
|
|
|
2018-12-01 18:32:54 +02:00
|
|
|
local hydras = hail_hydra[name]
|
|
|
|
if not hydras then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
local position = entity.position
|
|
|
|
local force = entity.force
|
|
|
|
local evolution_factor = force.evolution_factor
|
|
|
|
local cause = event.cause
|
|
|
|
|
|
|
|
local surface = entity.surface
|
|
|
|
local create_entity = surface.create_entity
|
|
|
|
local find_non_colliding_position = surface.find_non_colliding_position
|
|
|
|
|
|
|
|
local command = create_attack_command(position, cause)
|
|
|
|
|
|
|
|
for hydra_spawn, amount in pairs(hydras) do
|
|
|
|
amount = amount + evolution_factor
|
|
|
|
local extra_chance = amount % 1
|
|
|
|
if extra_chance > 0 then
|
|
|
|
if random() <= extra_chance then
|
|
|
|
amount = ceil(amount)
|
|
|
|
else
|
|
|
|
amount = floor(amount)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
local particle_count
|
|
|
|
|
|
|
|
if amount > 4 then
|
|
|
|
particle_count = 60
|
|
|
|
else
|
|
|
|
particle_count = amount * 15
|
|
|
|
end
|
|
|
|
|
|
|
|
CreateParticles.blood_explosion(create_entity, particle_count, position)
|
|
|
|
|
|
|
|
for _ = amount, 1, -1 do
|
|
|
|
position = find_non_colliding_position(hydra_spawn, position, 2, 0.4) or position
|
|
|
|
local spawned = create_entity({name = hydra_spawn, force = force, position = position})
|
|
|
|
if spawned and spawned.type == 'unit' then
|
|
|
|
spawned.set_command(command)
|
|
|
|
elseif spawned and cause then
|
|
|
|
spawned.shooting_target = cause
|
2018-11-21 16:26:04 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end)
|
|
|
|
end
|
2018-11-18 18:12:00 +02:00
|
|
|
|
|
|
|
Event.add(Template.events.on_void_removed, function (event)
|
2018-11-21 16:26:04 +02:00
|
|
|
local force = game.forces.enemy
|
|
|
|
local evolution_factor = force.evolution_factor
|
2018-11-29 21:16:23 +02:00
|
|
|
force.evolution_factor = evolution_factor + 0.0000024
|
2018-11-18 18:12:00 +02:00
|
|
|
|
|
|
|
local position = event.position
|
|
|
|
local x = position.x
|
|
|
|
local y = position.y
|
|
|
|
|
2018-11-21 16:26:04 +02:00
|
|
|
if (x * x + y * y < alien_minimum_distance_square or alien_probability < random()) then
|
2018-11-18 18:12:00 +02:00
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2018-12-09 20:10:16 +02:00
|
|
|
spawn_aliens(
|
|
|
|
AlienEvolutionProgress.get_aliens(AlienEvolutionProgress.create_spawner_request(3), force.evolution_factor),
|
|
|
|
force,
|
|
|
|
event.surface,
|
|
|
|
x,
|
|
|
|
y
|
|
|
|
)
|
2018-11-18 18:12:00 +02:00
|
|
|
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
|
|
|
|
|
|
|
|
function AlienSpawner.on_init()
|
2018-11-29 21:16:23 +02:00
|
|
|
-- base factorio = time_factor = 0.000004
|
|
|
|
game.map_settings.enemy_evolution.time_factor = 0.000008
|
|
|
|
game.forces.enemy.evolution_factor = 0.1
|
|
|
|
game.map_settings.pollution.enabled = false
|
2018-11-18 18:12:00 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
return AlienSpawner
|