mirror of
https://github.com/Refactorio/RedMew.git
synced 2025-03-17 21:08:08 +02:00
Update Frontier to V3 (#1425)
* Enemy AI * Change enemy spawn wave logic * Add bard messages * Update changelog * Fox reseed * Fix luachecks
This commit is contained in:
parent
162b3aa0f0
commit
3dabc84ccc
@ -1,3 +1,4 @@
|
|||||||
|
local Color = require 'resources.color_presets'
|
||||||
local table = require 'utils.table'
|
local table = require 'utils.table'
|
||||||
local Event = require 'utils.event'
|
local Event = require 'utils.event'
|
||||||
local Global = require 'utils.global'
|
local Global = require 'utils.global'
|
||||||
@ -27,11 +28,11 @@ function Public.show_start_up(player)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if _DEBUG and game.is_multiplayer() then
|
if _DEBUG and game.is_multiplayer() then
|
||||||
game.print('THIS MULTIPLAYER MAP IS IN DEBUG!!!')
|
game.print('THIS MULTIPLAYER MAP IS IN DEBUG!!!', Color.warning)
|
||||||
elseif _DEBUG then
|
elseif _DEBUG then
|
||||||
game.print("DON'T LAUNCH THIS MAP! DEBUG MODE IS ENABLED!!!")
|
game.print("DON'T LAUNCH THIS MAP! DEBUG MODE IS ENABLED!!!", Color.warning)
|
||||||
elseif not _DEBUG and not game.is_multiplayer() then
|
elseif not _DEBUG and not game.is_multiplayer() then
|
||||||
player.print('To change your name in single-player, open chat and type the following /c game.player.name = "your_name"')
|
player.print('To change your name in single-player, open chat and type the following /c game.player.name = "your_name"', Color.info)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -215,5 +215,5 @@ err_no_armor=[color=blue][Battery recharge][/color] No valid armor to charge was
|
|||||||
err_no_accumulators=[color=blue][Battery recharge][/color] No accumulators nearby.
|
err_no_accumulators=[color=blue][Battery recharge][/color] No accumulators nearby.
|
||||||
|
|
||||||
[clear_corpses]
|
[clear_corpses]
|
||||||
count=[color=blue][Cleaner][/color] __1__ __plural_for_parameter_1_{1=__1__ corpse|rest=__1__ corpses}__ removed.
|
count=[color=blue][Cleaner][/color] __1__ __plural_for_parameter_1_{1=corpse|rest=corpses}__ removed.
|
||||||
clear=[color=blue][Cleaner][/color] already clear.
|
clear=[color=blue][Cleaner][/color] already clear.
|
||||||
|
@ -8,10 +8,12 @@ local math = require 'utils.math'
|
|||||||
local MGSP = require 'resources.map_gen_settings'
|
local MGSP = require 'resources.map_gen_settings'
|
||||||
local Noise = require 'map_gen.shared.simplex_noise'
|
local Noise = require 'map_gen.shared.simplex_noise'
|
||||||
local PriceRaffle = require 'features.price_raffle'
|
local PriceRaffle = require 'features.price_raffle'
|
||||||
|
local Ranks = require 'resources.ranks'
|
||||||
local RS = require 'map_gen.shared.redmew_surface'
|
local RS = require 'map_gen.shared.redmew_surface'
|
||||||
local ScenarioInfo = require 'features.gui.info'
|
local ScenarioInfo = require 'features.gui.info'
|
||||||
local ScoreTracker = require 'utils.score_tracker'
|
local ScoreTracker = require 'utils.score_tracker'
|
||||||
local Sounds = require 'utils.sounds'
|
local Sounds = require 'utils.sounds'
|
||||||
|
local Table = require 'utils.table'
|
||||||
local Toast = require 'features.gui.toast'
|
local Toast = require 'features.gui.toast'
|
||||||
local Token = require 'utils.token'
|
local Token = require 'utils.token'
|
||||||
local Task = require 'utils.task'
|
local Task = require 'utils.task'
|
||||||
@ -28,6 +30,8 @@ local simplex = Noise.d2
|
|||||||
local SECOND = 60
|
local SECOND = 60
|
||||||
local MINUTE = SECOND * 60
|
local MINUTE = SECOND * 60
|
||||||
|
|
||||||
|
local register_on_entity_destroyed = script.register_on_entity_destroyed
|
||||||
|
|
||||||
--[[
|
--[[
|
||||||
Scenario info: Frontier
|
Scenario info: Frontier
|
||||||
From 'Frontier Extended' mod: https://mods.factorio.com/mod/Frontier-Extended
|
From 'Frontier Extended' mod: https://mods.factorio.com/mod/Frontier-Extended
|
||||||
@ -58,6 +62,9 @@ Your mission, should you choose to accept it, is to journey through this ribbon
|
|||||||
In [font=default-bold]Frontier[/font], your wits will be tested as you evolve from a mere survivor to an engineering genius capable of taming the land and launching your final escape. Build a thriving factory, and prepare to conquer both nature and the relentless horde in a race against time. But remember, the frontier waits for no one. Will you make your mark on this alien world or become another lost tale in the void of space?
|
In [font=default-bold]Frontier[/font], your wits will be tested as you evolve from a mere survivor to an engineering genius capable of taming the land and launching your final escape. Build a thriving factory, and prepare to conquer both nature and the relentless horde in a race against time. But remember, the frontier waits for no one. Will you make your mark on this alien world or become another lost tale in the void of space?
|
||||||
]])
|
]])
|
||||||
ScenarioInfo.set_new_info([[
|
ScenarioInfo.set_new_info([[
|
||||||
|
2024-08-15:
|
||||||
|
- Fixed desyncs
|
||||||
|
- Fixed biter waves
|
||||||
2024-08-10:
|
2024-08-10:
|
||||||
- Added enemy turrets
|
- Added enemy turrets
|
||||||
- Added soft reset
|
- Added soft reset
|
||||||
@ -121,8 +128,16 @@ local this = {
|
|||||||
min_step = 500, -- minimum tiles to move
|
min_step = 500, -- minimum tiles to move
|
||||||
max_distance = 100000, -- maximum x distance of rocket silo
|
max_distance = 100000, -- maximum x distance of rocket silo
|
||||||
|
|
||||||
-- Revived enemies
|
-- Enemy data
|
||||||
invincible = {}
|
invincible = {},
|
||||||
|
target_entities = {},
|
||||||
|
unit_groups = {},
|
||||||
|
|
||||||
|
-- Lobby
|
||||||
|
lobby_enabled = false,
|
||||||
|
|
||||||
|
-- Debug
|
||||||
|
_DEBUG_AI = false,
|
||||||
}
|
}
|
||||||
|
|
||||||
Global.register(this, function(tbl) this = tbl end)
|
Global.register(this, function(tbl) this = tbl end)
|
||||||
@ -148,11 +163,32 @@ ScoreTracker.register(rocket_launches_name, {'frontier.rockets_to_launch'}, '[im
|
|||||||
|
|
||||||
local escape_player = false
|
local escape_player = false
|
||||||
|
|
||||||
|
-- == DEBUG ===================================================================
|
||||||
|
|
||||||
|
local Debug = {}
|
||||||
|
|
||||||
|
function Debug.print_admins(msg, color)
|
||||||
|
for _, p in pairs(game.connected_players) do
|
||||||
|
if p.admin then
|
||||||
|
p.print(msg, color)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Debug.print(msg, color)
|
||||||
|
for _, p in pairs(game.connected_players) do
|
||||||
|
p.print(msg, color)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Debug.log(data)
|
||||||
|
log(serpent.block(data))
|
||||||
|
end
|
||||||
|
|
||||||
-- == LOBBY ===================================================================
|
-- == LOBBY ===================================================================
|
||||||
|
|
||||||
local Lobby = {}
|
local Lobby = {}
|
||||||
|
|
||||||
Lobby.enabled = false
|
|
||||||
Lobby.name = 'nauvis'
|
Lobby.name = 'nauvis'
|
||||||
Lobby.mgs = {
|
Lobby.mgs = {
|
||||||
water = 0,
|
water = 0,
|
||||||
@ -403,7 +439,7 @@ function Terrain.create_wall(x, w)
|
|||||||
end
|
end
|
||||||
|
|
||||||
for y = -this.height * 16, this.height * 16 do
|
for y = -this.height * 16, this.height * 16 do
|
||||||
for j = 0, w do
|
for j = 0, w - 1 do
|
||||||
local e = surface.create_entity {
|
local e = surface.create_entity {
|
||||||
name = 'stone-wall',
|
name = 'stone-wall',
|
||||||
position = { x + j, y },
|
position = { x + j, y },
|
||||||
@ -413,36 +449,207 @@ function Terrain.create_wall(x, w)
|
|||||||
e.destructible = false
|
e.destructible = false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local tiles = {}
|
||||||
|
for j = -4, w - 1 + 4 do
|
||||||
|
for y = -this.height * 16, this.height * 16 do
|
||||||
|
tiles[#tiles +1] = { name = 'hazard-concrete-left', position = { x = x + j, y = y }}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for j = -1, w do
|
||||||
|
for y = -this.height * 16, this.height * 16 do
|
||||||
|
tiles[#tiles +1] = { name = 'concrete', position = { x = x + j, y = y }}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
surface.set_tiles(tiles, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- == MAIN ====================================================================
|
-- == Enemy ===================================================================
|
||||||
|
|
||||||
function Main.nuclear_explosion(entity)
|
local Enemy = {}
|
||||||
local surface = entity.surface
|
|
||||||
local center_position = entity.position
|
Enemy.target_entity_types = {
|
||||||
local force = entity.force
|
['accumulator'] = true,
|
||||||
surface.create_entity {
|
['assembling-machine'] = true,
|
||||||
name = 'atomic-rocket',
|
['beacon'] = true,
|
||||||
position = center_position,
|
['boiler'] = true,
|
||||||
force = force,
|
['furnace'] = true,
|
||||||
source = center_position,
|
['generator'] = true,
|
||||||
target = center_position,
|
['heat-interface'] = true,
|
||||||
max_range = 1,
|
['lab'] = true,
|
||||||
speed = 0.1
|
['mining-drill'] = true,
|
||||||
|
['offshore-pump'] = true,
|
||||||
|
['reactor'] = true,
|
||||||
|
['roboport'] = true,
|
||||||
|
['solar-panel'] = true,
|
||||||
|
}
|
||||||
|
|
||||||
|
Enemy.commands = {
|
||||||
|
move = function(unit_group, position)
|
||||||
|
local data = Enemy.ai_take_control(unit_group)
|
||||||
|
if not position then
|
||||||
|
Enemy.ai_processor(unit_group)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
data.position = position
|
||||||
|
data.stage = Enemy.stages.move
|
||||||
|
unit_group.set_command {
|
||||||
|
type = defines.command.go_to_location,
|
||||||
|
destination = position,
|
||||||
|
radius = 3,
|
||||||
|
distraction = defines.distraction.by_enemy
|
||||||
}
|
}
|
||||||
|
unit_group.start_moving()
|
||||||
|
if this._DEBUG_AI then
|
||||||
|
Debug.print_admins(string.format('AI [id=%d] | cmd: MOVE [gps=%.2f,%.2f,%s]', unit_group.group_number, position.x, position.y, unit_group.surface.name), Color.dark_gray)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
scout = function(unit_group, position)
|
||||||
|
local data = Enemy.ai_take_control(unit_group)
|
||||||
|
if not position then
|
||||||
|
Enemy.ai_processor(unit_group)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
data.position = position
|
||||||
|
data.stage = Enemy.stages.scout
|
||||||
|
unit_group.set_command {
|
||||||
|
type = defines.command.attack_area,
|
||||||
|
destination = position,
|
||||||
|
radius = 15,
|
||||||
|
distraction = defines.distraction.by_enemy
|
||||||
|
}
|
||||||
|
unit_group.start_moving()
|
||||||
|
if this._DEBUG_AI then
|
||||||
|
Debug.print_admins(string.format('AI [id=%d] | cmd: SCOUT [gps=%.2f,%.2f,%s]', unit_group.group_number, position.x, position.y, unit_group.surface.name), Color.dark_gray)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
attack = function(unit_group, target)
|
||||||
|
local data = Enemy.ai_take_control(unit_group)
|
||||||
|
if not (target and target.valid) then
|
||||||
|
Enemy.ai_processor(unit_group)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
data.target = target
|
||||||
|
data.stage = Enemy.stages.attack
|
||||||
|
unit_group.set_command {
|
||||||
|
type = defines.command.attack,
|
||||||
|
target = target,
|
||||||
|
distraction = defines.distraction.by_damage
|
||||||
|
}
|
||||||
|
if this._DEBUG_AI then
|
||||||
|
Debug.print_admins(string.format('AI [id=%d] | cmd: ATTACK [gps=%.2f,%.2f,%s] (type = %s)', unit_group.group_number, target.position.x, target.position.y, unit_group.surface.name, target.type), Color.dark_gray)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
Enemy.stages = {
|
||||||
|
pending = 1,
|
||||||
|
move = 2,
|
||||||
|
scout = 3,
|
||||||
|
attack = 4,
|
||||||
|
fail = 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
function Enemy.ai_take_control(unit_group)
|
||||||
|
if not this.unit_groups[unit_group.group_number] then
|
||||||
|
this.unit_groups[unit_group.group_number] = {
|
||||||
|
unit_group = unit_group
|
||||||
|
}
|
||||||
|
end
|
||||||
|
return this.unit_groups[unit_group.group_number]
|
||||||
end
|
end
|
||||||
|
|
||||||
function Main.spawn_enemy_wave(position)
|
function Enemy.ai_stage_by_distance(posA, posB)
|
||||||
|
local x_axis = posA.x - posB.x
|
||||||
|
local y_axis = posA.y - posB.y
|
||||||
|
local distance = math_sqrt(x_axis * x_axis + y_axis * y_axis)
|
||||||
|
if distance <= 15 then
|
||||||
|
return Enemy.stages.attack
|
||||||
|
elseif distance <= 32 then
|
||||||
|
return Enemy.stages.scout
|
||||||
|
else
|
||||||
|
return Enemy.stages.move
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Enemy.ai_processor(unit_group, result)
|
||||||
|
if not (unit_group and unit_group.valid) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local data = this.unit_groups[unit_group.group_number]
|
||||||
|
if not data then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if data.failed_attempts and data.failed_attempts >= 3 then
|
||||||
|
this.unit_groups[unit_group.group_number] = nil
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if not result or result == defines.behavior_result.fail or result == defines.behavior_result.deleted then
|
||||||
|
data.stage = Enemy.stages.pending
|
||||||
|
end
|
||||||
|
if result == defines.behavior_result.success and (data.stage and data.stage == Enemy.stages.attack) then
|
||||||
|
data.stage = Enemy.stages.pending
|
||||||
|
end
|
||||||
|
data.stage = data.stage or Enemy.stages.pending
|
||||||
|
|
||||||
|
if data.stage == Enemy.stages.pending then
|
||||||
|
local surface = unit_group.surface
|
||||||
|
data.target = surface.find_nearest_enemy_entity_with_owner {
|
||||||
|
position = unit_group.position,
|
||||||
|
max_distance = this.rocket_step * 4,
|
||||||
|
force = 'enemy',
|
||||||
|
}
|
||||||
|
if not (data.target and data.target.valid) then
|
||||||
|
this.unit_groups[unit_group.group_number] = nil
|
||||||
|
return
|
||||||
|
end
|
||||||
|
data.position = data.target.position
|
||||||
|
data.stage = Enemy.ai_stage_by_distance(data.position, unit_group.position)
|
||||||
|
else
|
||||||
|
data.stage = data.stage + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if this._DEBUG_AI then
|
||||||
|
Debug.print_admins(string.format('AI [id=%d] | status: %d', unit_group.group_number, data.stage), Color.dark_gray)
|
||||||
|
end
|
||||||
|
|
||||||
|
if data.stage == Enemy.stages.move then
|
||||||
|
Enemy.commands.move(unit_group, data.target)
|
||||||
|
elseif data.stage == Enemy.stages.scout then
|
||||||
|
Enemy.commands.scout(unit_group, data.target)
|
||||||
|
elseif data.stage == Enemy.stages.attack then
|
||||||
|
Enemy.commands.attack(unit_group, data.target)
|
||||||
|
else
|
||||||
|
data.failed_attempts = (data.failed_attempts or 0) + 1
|
||||||
|
if this._DEBUG_AI then
|
||||||
|
Debug.print_admins(string.format('AI [id=%d] | FAIL | stage: %d | attempts: %d', unit_group.group_number, data.stage, data.failed_attempts), Color.dark_gray)
|
||||||
|
end
|
||||||
|
data.stage, data.position, data.target = nil, nil, nil
|
||||||
|
Enemy.ai_processor(unit_group, nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Enemy.spawn_enemy_wave(position)
|
||||||
local surface = RS.get_surface()
|
local surface = RS.get_surface()
|
||||||
local find_position = surface.find_non_colliding_position
|
local find_position = surface.find_non_colliding_position
|
||||||
local spawn = surface.create_entity
|
local spawn = surface.create_entity
|
||||||
local current_tick = game.tick
|
local current_tick = game.tick
|
||||||
|
|
||||||
|
local unit_group = surface.create_unit_group { position = position, force = 'enemy' }
|
||||||
|
|
||||||
local max_time = math_max(MINUTE, MINUTE * math_ceil(0.5 * (this.rockets_launched ^ 0.5)))
|
local max_time = math_max(MINUTE, MINUTE * math_ceil(0.5 * (this.rockets_launched ^ 0.5)))
|
||||||
|
|
||||||
local radius = 20
|
local radius = 20
|
||||||
for _ = 1, 24 do
|
for _ = 1, 12 do
|
||||||
local name = math_random() > 0.15 and 'behemoth-worm-turret' or 'big-worm-turret'
|
local name
|
||||||
|
if this.rockets_launched < 3 then
|
||||||
|
name = math_random() > 0.15 and 'big-worm-turret' or 'medium-worm-turret'
|
||||||
|
else
|
||||||
|
name = math_random() > 0.15 and 'behemoth-worm-turret' or 'big-worm-turret'
|
||||||
|
end
|
||||||
local about = find_position(name, { x = position.x + math_random(), y = position.y + math_random() }, radius, 0.2)
|
local about = find_position(name, { x = position.x + math_random(), y = position.y + math_random() }, radius, 0.2)
|
||||||
if about then
|
if about then
|
||||||
local worm = spawn { name = name, position = about, force = 'enemy', move_stuck_players = true }
|
local worm = spawn { name = name, position = about, force = 'enemy', move_stuck_players = true }
|
||||||
@ -454,20 +661,97 @@ function Main.spawn_enemy_wave(position)
|
|||||||
|
|
||||||
radius = 32
|
radius = 32
|
||||||
for _ = 1, 20 do
|
for _ = 1, 20 do
|
||||||
local name = math_random() > 0.3 and 'behemoth-biter' or 'behemoth-spitter'
|
local name
|
||||||
|
if this.rockets_launched < 3 then
|
||||||
|
name = math_random() > 0.3 and 'big-biter' or 'big-spitter'
|
||||||
|
else
|
||||||
|
name = math_random() > 0.3 and 'behemoth-biter' or 'behemoth-spitter'
|
||||||
|
end
|
||||||
local about = find_position(name, { x = position.x + math_random(), y = position.y + math_random() }, radius, 0.6)
|
local about = find_position(name, { x = position.x + math_random(), y = position.y + math_random() }, radius, 0.6)
|
||||||
if about then
|
if about then
|
||||||
local unit = spawn { name = name, position = about, force = 'enemy', move_stuck_players = true }
|
local unit = spawn { name = name, position = about, force = 'enemy', move_stuck_players = true }
|
||||||
this.invincible[unit.unit_number] = {
|
this.invincible[unit.unit_number] = {
|
||||||
time_to_live = current_tick + math_random(MINUTE, max_time)
|
time_to_live = current_tick + math_random(MINUTE, max_time)
|
||||||
}
|
}
|
||||||
|
unit_group.add_member(unit)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if unit_group.valid then
|
||||||
|
Enemy.ai_take_control(unit_group)
|
||||||
|
Enemy.ai_processor(unit_group)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
Enemy.spawn_enemy_wave_token = Token.register(Enemy.spawn_enemy_wave)
|
||||||
|
|
||||||
|
function Enemy.on_enemy_died(entity)
|
||||||
|
local uid = entity.unit_number
|
||||||
|
local data = this.invincible[uid]
|
||||||
|
if not data then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if game.tick > data.time_to_live then
|
||||||
|
this.invincible[uid] = nil
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local new_entity = entity.surface.create_entity {
|
||||||
|
name = entity.name,
|
||||||
|
position = entity.position,
|
||||||
|
force = entity.force,
|
||||||
|
}
|
||||||
|
|
||||||
|
this.invincible[new_entity.unit_number] = {
|
||||||
|
time_to_live = data.time_to_live,
|
||||||
|
}
|
||||||
|
this.invincible[uid] = nil
|
||||||
|
|
||||||
|
if new_entity.type == 'unit' then
|
||||||
|
new_entity.set_command(entity.command)
|
||||||
|
if entity.unit_group then
|
||||||
|
entity.unit_group.add_member(new_entity)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
Main.spawn_enemy_wave_token = Token.register(Main.spawn_enemy_wave)
|
|
||||||
|
|
||||||
function Main.spawn_turret_outpost(position)
|
function Enemy.on_spawner_died(event)
|
||||||
if position.x < this.right_boundary + this.wall_width then
|
local entity = event.entity
|
||||||
|
local chance = math_random()
|
||||||
|
if chance > this.loot_chance then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local budget = this.loot_budget + entity.position.x * 2.75
|
||||||
|
budget = budget * math_random(25, 175) * 0.01
|
||||||
|
|
||||||
|
local player = false
|
||||||
|
if event.cause and event.cause.type == 'character' then
|
||||||
|
player = event.cause.player
|
||||||
|
end
|
||||||
|
if player and player.valid then
|
||||||
|
budget = budget + (this.death_contributions[player.name] or 0) * 80
|
||||||
|
end
|
||||||
|
|
||||||
|
if math_random(1, 128) == 1 then budget = budget * 4 end
|
||||||
|
if math_random(1, 256) == 1 then budget = budget * 4 end
|
||||||
|
budget = budget * this.loot_richness
|
||||||
|
|
||||||
|
local chest = entity.surface.create_entity { name = 'steel-chest', position = entity.position, force = 'player', move_stuck_players = true }
|
||||||
|
chest.destructible = false
|
||||||
|
for i = 1, 3 do
|
||||||
|
local item_stacks = PriceRaffle.roll(math_floor(budget / 3 ) + 1, 48)
|
||||||
|
for _, item_stack in pairs(item_stacks) do
|
||||||
|
chest.insert(item_stack)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if player then
|
||||||
|
Toast.toast_player(player, nil, {'frontier.loot_chest'})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Enemy.spawn_turret_outpost(position)
|
||||||
|
if position.x < this.right_boundary * 32 + this.wall_width then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -518,6 +802,136 @@ function Main.spawn_turret_outpost(position)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Enemy.start_tracking(entity)
|
||||||
|
if not Enemy.target_entity_types[entity.type] then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if entity.force.name == 'enemy' or entity.force.name == 'neutral' then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
register_on_entity_destroyed(entity)
|
||||||
|
this.target_entities[entity.unit_number] = entity
|
||||||
|
end
|
||||||
|
|
||||||
|
function Enemy.stop_tracking(entity)
|
||||||
|
this.target_entities[entity.unit_number] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function Enemy.get_target()
|
||||||
|
return Table.get_random_dictionary_entry(this.target_entities, false)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Enemy.nuclear_explosion(entity)
|
||||||
|
local surface = entity.surface
|
||||||
|
local center_position = entity.position
|
||||||
|
surface.create_entity {
|
||||||
|
name = 'atomic-rocket',
|
||||||
|
position = center_position,
|
||||||
|
force = 'enemy',
|
||||||
|
source = center_position,
|
||||||
|
target = center_position,
|
||||||
|
max_range = 1,
|
||||||
|
speed = 0.1
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function Enemy.artillery_explosion(data)
|
||||||
|
local surface = game.get_surface(data.surface_name)
|
||||||
|
local position = data.position
|
||||||
|
local r = 20
|
||||||
|
surface.create_entity {
|
||||||
|
name = 'artillery-projectile',
|
||||||
|
position = position,
|
||||||
|
force = 'enemy',
|
||||||
|
source = position,
|
||||||
|
target = { x = position.x + math_random(-r, r) + math_random(), y = position.y + math_random(-r, r) + math_random() },
|
||||||
|
max_range = 1,
|
||||||
|
speed = 0.1
|
||||||
|
}
|
||||||
|
end
|
||||||
|
Enemy.artillery_explosion_token = Token.register(Enemy.artillery_explosion)
|
||||||
|
|
||||||
|
-- == MAIN ====================================================================
|
||||||
|
|
||||||
|
local bard_messages_1 = {
|
||||||
|
[1] = {
|
||||||
|
[[The rocket has successfully launched! The Kraken has accepted your offering... for now.]],
|
||||||
|
[[A distant rumble echoes through the air. The Kraken stirs in the depths.]],
|
||||||
|
[[You can almost feel the waters shifting. What will the Kraken do with your gift?]],
|
||||||
|
[[The sky darkens as the rocket ascends. Is the Kraken pleased or plotting revenge?]],
|
||||||
|
[[You have awakened something ancient. Expect the unknown in the next moments.]],
|
||||||
|
[[A whisper echoes in your mind: 'You dare disturb my slumber?']],
|
||||||
|
[[The Kraken watches from below, its tendrils coiling in anticipation.]],
|
||||||
|
[[A chilling wind sweeps across your factory—a sign the Kraken is not to be trifled with.]],
|
||||||
|
[[The ground trembles as the rocket disappears into the sky... what price will you pay?]],
|
||||||
|
[[An ominous shadow looms beneath the waves. The Kraken has taken notice.]],
|
||||||
|
},
|
||||||
|
[2] = {
|
||||||
|
[[As the rocket pierces the sky, dark waters tremble in anticipation... something stirs.]],
|
||||||
|
[[A whispering gale caresses the land; the Kraken's essence begins to awaken.]],
|
||||||
|
[[Shadows flicker at the water's edge. The depths conceal secrets you cannot fathom.]],
|
||||||
|
[[Eyes unblinking watch from the abyss; your offering has been noted with curiosity... or contempt.]],
|
||||||
|
[[The air grows thick with foreboding. An ancient power rouses from its slumber.]],
|
||||||
|
[[From the deep, a voice resonates: 'What price have you paid for your hubris?']],
|
||||||
|
[[The ocean churns as if agitated. The Kraken's mood is as unpredictable as the tempest.]],
|
||||||
|
[[Unseen tendrils drift closer to your shores. What has been awakened cannot be unmade.]],
|
||||||
|
[[A shiver runs through the ground, as if the earth itself fears the Kraken's gaze.]],
|
||||||
|
[[With each second that passes, the Kraken's presence suffocates the air around you.]],
|
||||||
|
},
|
||||||
|
[3] = {
|
||||||
|
[[Hark! The rocket soars to the heavens, yet below, the Kraken stirs in its slumber deep, its ancient wrath looms ever near!]],
|
||||||
|
[[Lo, the winds whisper secrets of the abyss; the Kraken watches, its tendrils twitching in delight or dread—can you tell which it shall be?]],
|
||||||
|
[[By the light of the fading suns, shadows dance upon the waves. A gift offered, but at what terrible cost? Beware the storm that brews!]],
|
||||||
|
[[Listen well, dear traveler! For the depths grow restless, and the Kraken, master of the abyss, awakens to claim its due!]],
|
||||||
|
[[Oh, fear the echo of the deep! A creature of legend stirs, its gaze upon your fortress—wreathed in shadows, it feasts on your hubris!]],
|
||||||
|
[[Beware the churning sea, where the ancient beast stirs; your paid price may be your eternal plight—what horrors shall it unleash?]],
|
||||||
|
[[From depths unknown, an unsettling murmur rises, 'You dared disturb me, foolish one! Know now the depths of my disdain!']],
|
||||||
|
[[As the rocket ascends, the sky darkens and trembles, for the Kraken's heart beats wildly—can you sense its lurking fury?]],
|
||||||
|
[[Oremus, oh heed my words! For beneath the surface lies a horror awakened—a vengeful force hungering for the taste of calamity!]],
|
||||||
|
[[An eternal shadow looms, beckoned by your ambition! What horrors have you invited to dance upon your very threshold?]],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
local bard_messages_2 = {
|
||||||
|
[1] = {
|
||||||
|
[[The surface of the water begins to churn ominously... something awakens.]],
|
||||||
|
[[An unsettling roar reverberates through the land. The Kraken's wrath is near.]],
|
||||||
|
[[A dark cloud forms above, casting a shadow over your factory. The Kraken is displeased.]],
|
||||||
|
[[Tentacles rise from the deep, a harbinger of chaos approaching your base.]],
|
||||||
|
[[The Kraken demands retribution! Prepare for the onslaught!]],
|
||||||
|
[[A storm brews on the horizon; the Kraken lashes out in fury.]],
|
||||||
|
[[The air grows thick with tension as a monstrous wave approaches your shores.]],
|
||||||
|
[[All around you, the atmosphere shifts—something is very wrong.]],
|
||||||
|
[[The Kraken's vengeance is upon you! Brace yourself for the inevitable.]],
|
||||||
|
[[In its rage, the Kraken unleashes its fury! The biter swarm descends!]],
|
||||||
|
},
|
||||||
|
[2] = {
|
||||||
|
[[The surface roils ominously, dark waters boiling as wrath takes form.]],
|
||||||
|
[[A haunting cry echoes across the landscape—an ancient beast calls for retribution.]],
|
||||||
|
[[Dark clouds gather like a shroud, heralding calamity born of the abyss.]],
|
||||||
|
[[Tendrils of shadow writhe beneath the waves—a prelude to the storm of vengeance.]],
|
||||||
|
[[The Kraken's disdain unfurls like a tempest, a dark promise of chaos and destruction.]],
|
||||||
|
[[An unnatural stillness settles, broken only by the distant crash of furious waves.]],
|
||||||
|
[[The deep stirs with malice. Can you hear the heartbeat of your impending doom?]],
|
||||||
|
[[In the twilight, the Kraken's fury eclipses all hope, a symphony of despair draws near.]],
|
||||||
|
[[As specters rise from the depths, their intent is clear: retribution is swift and merciless.]],
|
||||||
|
[[Your fate is entwined with the Kraken's ire—prepare for the inexorable tide of darkness.]],
|
||||||
|
},
|
||||||
|
[3] = {
|
||||||
|
[[Attend! A tempest brews upon darkened waters, rage unfurling like a ravenous beast—your time is nigh!]],
|
||||||
|
[[The Kraken's call resounds, echoing through the night; from the abyss it comes, cloaked in shadows and dread!]],
|
||||||
|
[[A shudder passes through the land, and ominous clouds converge—gaze now upon the darkening sky, for doom draws near!]],
|
||||||
|
[[Dread whisperings of the deep herald the coming tempest; the Kraken rises, eager to reclaim what is owed with swift malice!]],
|
||||||
|
[[Foul winds carry the scent of vengeance. The Kraken's ire is unbound, and soon your fortress shall feel its dark embrace!]],
|
||||||
|
[[In the twilight haze, a cacophony of doom stirs—behold, the tide of destruction approaches with unholy intent!]],
|
||||||
|
[[Tremble now, for the Kraken awakens! A chorus of despair sings forth, heralding the swarm that comes, hungry and relentless!]],
|
||||||
|
[[The ancient beast unleashes fury upon your path—a storm of chaos born from the depths, bringing forth a wretched tide!]],
|
||||||
|
[[Beware! The Kraken's wrath is a specter unshackled, and every heartbeat draws nearer to the end of your peace!]],
|
||||||
|
[[Thus, from beneath the waves, chaos and slaughter arise—oh, brave souls, face the horrors your hubris has conjured!]],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
function Main.win()
|
function Main.win()
|
||||||
this.scenario_finished = true
|
this.scenario_finished = true
|
||||||
game.set_game_state { game_finished = true, player_won = true, can_continue = true, victorious_force = 'player' }
|
game.set_game_state { game_finished = true, player_won = true, can_continue = true, victorious_force = 'player' }
|
||||||
@ -531,69 +945,6 @@ function Main.win()
|
|||||||
Task.set_timeout(92, Main.restart_game_token)
|
Task.set_timeout(92, Main.restart_game_token)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Main.on_spawner_died(event)
|
|
||||||
local entity = event.entity
|
|
||||||
local chance = math_random()
|
|
||||||
if chance > this.loot_chance then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local budget = this.loot_budget + entity.position.x * 2.75
|
|
||||||
budget = budget * math_random(25, 175) * 0.01
|
|
||||||
|
|
||||||
local player = false
|
|
||||||
if event.cause and event.cause.type == 'character' then
|
|
||||||
player = event.cause.player
|
|
||||||
end
|
|
||||||
if player and player.valid then
|
|
||||||
budget = budget + (this.death_contributions[player.name] or 0) * 80
|
|
||||||
end
|
|
||||||
|
|
||||||
if math_random(1, 128) == 1 then budget = budget * 4 end
|
|
||||||
if math_random(1, 256) == 1 then budget = budget * 4 end
|
|
||||||
budget = budget * this.loot_richness
|
|
||||||
|
|
||||||
local chest = entity.surface.create_entity { name = 'steel-chest', position = entity.position, force = 'player', move_stuck_players = true }
|
|
||||||
chest.destructible = false
|
|
||||||
for i = 1, 3 do
|
|
||||||
local item_stacks = PriceRaffle.roll(math_floor(budget / 3 ) + 1, 48)
|
|
||||||
for _, item_stack in pairs(item_stacks) do
|
|
||||||
chest.insert(item_stack)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if player then
|
|
||||||
Toast.toast_player(player, nil, {'frontier.loot_chest'})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Main.on_enemy_died(entity)
|
|
||||||
local uid = entity.unit_number
|
|
||||||
local data = this.invincible[uid]
|
|
||||||
if not data then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if game.tick > data.time_to_live then
|
|
||||||
this.invincible[uid] = nil
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local new_entity = entity.surface.create_entity {
|
|
||||||
name = entity.name,
|
|
||||||
position = entity.position,
|
|
||||||
force = entity.force,
|
|
||||||
}
|
|
||||||
|
|
||||||
this.invincible[new_entity.unit_number] = {
|
|
||||||
time_to_live = data.time_to_live,
|
|
||||||
}
|
|
||||||
this.invincible[uid] = nil
|
|
||||||
|
|
||||||
if new_entity.type == 'unit' then
|
|
||||||
new_entity.set_command(entity.command)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
Main.play_sound_token = Token.register(Sounds.notify_all)
|
Main.play_sound_token = Token.register(Sounds.notify_all)
|
||||||
|
|
||||||
Main.restart_message_token = Token.register(function(seconds)
|
Main.restart_message_token = Token.register(function(seconds)
|
||||||
@ -645,8 +996,18 @@ function Main.move_silo(position)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
game.print({'frontier.empty_rocket'})
|
game.print({'frontier.empty_rocket'})
|
||||||
Main.nuclear_explosion(chest)
|
Enemy.nuclear_explosion(chest)
|
||||||
Task.set_timeout(5, Main.spawn_enemy_wave_token, old_position)
|
|
||||||
|
for _ = 1, 3 do
|
||||||
|
local spawn_target = Enemy.get_target()
|
||||||
|
if spawn_target and spawn_target.valid then
|
||||||
|
for _ = 1, 12 do
|
||||||
|
Task.set_timeout_in_ticks(math_random(30, 4 * 60), Enemy.artillery_explosion_token, { surface_name = surface.name, position = spawn_target.position })
|
||||||
|
end
|
||||||
|
Task.set_timeout(6, Enemy.spawn_enemy_wave_token, spawn_target.position)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
game.forces.enemy.reset_evolution()
|
game.forces.enemy.reset_evolution()
|
||||||
local enemy_evolution = game.map_settings.enemy_evolution
|
local enemy_evolution = game.map_settings.enemy_evolution
|
||||||
@ -748,6 +1109,8 @@ function Main.on_game_started()
|
|||||||
this.rocket_silo = nil
|
this.rocket_silo = nil
|
||||||
this.move_buffer = 0
|
this.move_buffer = 0
|
||||||
this.invincible = {}
|
this.invincible = {}
|
||||||
|
this.target_entities = {}
|
||||||
|
this.unit_groups = {}
|
||||||
|
|
||||||
if _DEBUG then
|
if _DEBUG then
|
||||||
this.silo_starting_x = 30
|
this.silo_starting_x = 30
|
||||||
@ -772,18 +1135,25 @@ Main.restart_game_token = Token.register(function()
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
function Main.on_game_finished()
|
function Main.on_game_finished()
|
||||||
Lobby.enabled = true
|
this.lobby_enabled = true
|
||||||
Lobby.teleport_all_to()
|
Lobby.teleport_all_to()
|
||||||
|
|
||||||
local surface = RS.get_surface()
|
local surface = RS.get_surface()
|
||||||
surface.clear(true)
|
surface.clear(true)
|
||||||
surface.map_gen_settings.seed = surface.map_gen_settings.seed + 1
|
local mgs = table.deepcopy(surface.map_gen_settings)
|
||||||
|
mgs.seed = mgs.seed + 1e4
|
||||||
|
surface.map_gen_settings = mgs
|
||||||
end
|
end
|
||||||
|
|
||||||
Main.end_game_token = Token.register(function()
|
Main.end_game_token = Token.register(function()
|
||||||
script.raise_event(Main.events.on_game_finished, {})
|
script.raise_event(Main.events.on_game_finished, {})
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
function Main.bard_message(list)
|
||||||
|
game.print('[color=orange][Bard][/color] ' .. list[math_random(#list)], { sound_path = 'utility/axe_fighting', color = Color.brown })
|
||||||
|
end
|
||||||
|
Main.bard_message_token = Token.register(Main.bard_message)
|
||||||
|
|
||||||
-- == EVENTS ==================================================================
|
-- == EVENTS ==================================================================
|
||||||
|
|
||||||
local function on_init()
|
local function on_init()
|
||||||
@ -791,7 +1161,7 @@ local function on_init()
|
|||||||
Main.on_game_started()
|
Main.on_game_started()
|
||||||
Main.reveal_spawn_area()
|
Main.reveal_spawn_area()
|
||||||
|
|
||||||
Lobby.enabled = false
|
this.lobby_enabled = false
|
||||||
Lobby.teleport_all_from()
|
Lobby.teleport_all_from()
|
||||||
end
|
end
|
||||||
Event.on_init(on_init)
|
Event.on_init(on_init)
|
||||||
@ -800,7 +1170,7 @@ local function on_game_started()
|
|||||||
Main.on_game_started()
|
Main.on_game_started()
|
||||||
Main.reveal_spawn_area()
|
Main.reveal_spawn_area()
|
||||||
|
|
||||||
Lobby.enabled = false
|
this.lobby_enabled = false
|
||||||
Lobby.teleport_all_from()
|
Lobby.teleport_all_from()
|
||||||
end
|
end
|
||||||
Event.add(Main.events.on_game_started, on_game_started)
|
Event.add(Main.events.on_game_started, on_game_started)
|
||||||
@ -816,7 +1186,7 @@ local function on_player_created(event)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if Lobby.enabled then
|
if this.lobby_enabled then
|
||||||
Lobby.teleport_to(player)
|
Lobby.teleport_to(player)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -855,12 +1225,14 @@ local function on_entity_died(event)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local entity_type = entity.type
|
local entity_type = entity.type
|
||||||
if entity_type == 'unit-spawner' then
|
|
||||||
Main.on_spawner_died(event)
|
|
||||||
elseif entity_type == 'unit' or entity.type == 'turret' then
|
|
||||||
if entity.force.name == 'enemy' then
|
if entity.force.name == 'enemy' then
|
||||||
Main.on_enemy_died(entity)
|
if entity_type == 'unit-spawner' then
|
||||||
|
Enemy.on_spawner_died(event)
|
||||||
|
elseif entity_type == 'unit' or entity_type == 'turret' then
|
||||||
|
Enemy.on_enemy_died(entity)
|
||||||
end
|
end
|
||||||
|
elseif entity_type == 'simple-entity' then
|
||||||
|
Enemy.spawn_turret_outpost(entity.position)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
Event.add(defines.events.on_entity_died, on_entity_died)
|
Event.add(defines.events.on_entity_died, on_entity_died)
|
||||||
@ -894,7 +1266,7 @@ local function on_player_died(event)
|
|||||||
end
|
end
|
||||||
|
|
||||||
this.rockets_to_win = this.rockets_to_win + this.rockets_per_death
|
this.rockets_to_win = this.rockets_to_win + this.rockets_per_death
|
||||||
ScoreTracker.set_for_global(rocket_launches_name, this.rockets_to_win - this.rocket_launched)
|
ScoreTracker.set_for_global(rocket_launches_name, this.rockets_to_win - this.rockets_launched)
|
||||||
|
|
||||||
game.print({'frontier.add_rocket', this.rockets_per_death, player_name, (this.rockets_to_win - this.rockets_launched)})
|
game.print({'frontier.add_rocket', this.rockets_per_death, player_name, (this.rockets_to_win - this.rockets_launched)})
|
||||||
end
|
end
|
||||||
@ -931,14 +1303,14 @@ local function on_rocket_launched(event)
|
|||||||
end
|
end
|
||||||
|
|
||||||
this.rockets_launched = this.rockets_launched + 1
|
this.rockets_launched = this.rockets_launched + 1
|
||||||
|
ScoreTracker.set_for_global(rocket_launches_name, (this.rockets_to_win - this.rockets_launched))
|
||||||
if this.rockets_launched >= this.rockets_to_win then
|
if this.rockets_launched >= this.rockets_to_win then
|
||||||
Main.win()
|
Main.win()
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
game.print({'frontier.rocket_launched', this.rockets_launched, (this.rockets_to_win - this.rockets_launched) })
|
game.print({'frontier.rocket_launched', this.rockets_launched, (this.rockets_to_win - this.rockets_launched) })
|
||||||
ScoreTracker.set_for_global(rocket_launches_name, (this.rockets_to_win - this.rockets_launched))
|
Main.compute_silo_coordinates(this.rocket_step + math_random(200))
|
||||||
Main.compute_silo_coordinates(500)
|
|
||||||
|
|
||||||
local ticks = 60
|
local ticks = 60
|
||||||
for _, delay in pairs{60, 40, 20} do
|
for _, delay in pairs{60, 40, 20} do
|
||||||
@ -947,6 +1319,8 @@ local function on_rocket_launched(event)
|
|||||||
Task.set_timeout_in_ticks(ticks, Main.play_sound_token, 'utility/alert_destroyed')
|
Task.set_timeout_in_ticks(ticks, Main.play_sound_token, 'utility/alert_destroyed')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Task.set_timeout( 5, Main.bard_message_token, bard_messages_1[3])
|
||||||
|
Task.set_timeout(25, Main.bard_message_token, bard_messages_2[3])
|
||||||
Task.set_timeout_in_ticks(ticks + 30, Main.move_silo_token)
|
Task.set_timeout_in_ticks(ticks + 30, Main.move_silo_token)
|
||||||
local silo = event.rocket_silo
|
local silo = event.rocket_silo
|
||||||
if silo then silo.active = false end
|
if silo then silo.active = false end
|
||||||
@ -960,12 +1334,44 @@ local function on_entity_mined(event)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if entity.type == 'simple-entity' then
|
if entity.type == 'simple-entity' then
|
||||||
Main.spawn_turret_outpost(entity.position)
|
Enemy.spawn_turret_outpost(entity.position)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
Event.add(defines.events.on_robot_mined_entity, on_entity_mined)
|
Event.add(defines.events.on_robot_mined_entity, on_entity_mined)
|
||||||
Event.add(defines.events.on_player_mined_entity, on_entity_mined)
|
Event.add(defines.events.on_player_mined_entity, on_entity_mined)
|
||||||
|
|
||||||
|
local function on_built_entity(event)
|
||||||
|
local entity = event.created_entity
|
||||||
|
if not (entity and entity.valid) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if entity.name == 'entity-ghost' then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
Enemy.start_tracking(entity)
|
||||||
|
end
|
||||||
|
Event.add(defines.events.on_built_entity, on_built_entity)
|
||||||
|
Event.add(defines.events.on_robot_built_entity, on_built_entity)
|
||||||
|
|
||||||
|
local function on_entity_destroyed(event)
|
||||||
|
local unit_number = event.unit_number
|
||||||
|
--local registration_number = event.registration_number
|
||||||
|
|
||||||
|
Enemy.stop_tracking({ unit_number = unit_number })
|
||||||
|
end
|
||||||
|
Event.add(defines.events.on_entity_destroyed, on_entity_destroyed)
|
||||||
|
|
||||||
|
local function on_ai_command_completed(event)
|
||||||
|
if not event.was_distracted then
|
||||||
|
local data = this.unit_groups[event.unit_number]
|
||||||
|
if data and data.unit_group and data.unit_group.valid then
|
||||||
|
Enemy.ai_processor(data.unit_group, event.result)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
Event.add(defines.events.on_ai_command_completed, on_ai_command_completed)
|
||||||
|
|
||||||
-- == COMMANDS ================================================================
|
-- == COMMANDS ================================================================
|
||||||
|
|
||||||
@ -989,6 +1395,39 @@ Command.add('ping-silo',
|
|||||||
end
|
end
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Command.add('toggle-debug-ai',
|
||||||
|
{
|
||||||
|
description = 'Toggle ON/OFF AI debug mode',
|
||||||
|
allowed_by_server = true,
|
||||||
|
required_rank = Ranks.admin,
|
||||||
|
},
|
||||||
|
function()
|
||||||
|
this._DEBUG_AI = not this._DEBUG_AI
|
||||||
|
end
|
||||||
|
)
|
||||||
|
|
||||||
|
Command.add('print-global',
|
||||||
|
{
|
||||||
|
description = 'Prints the global table',
|
||||||
|
allowed_by_server = false,
|
||||||
|
required_rank = Ranks.admin,
|
||||||
|
},
|
||||||
|
function(_, player)
|
||||||
|
player.print(serpent.line(this))
|
||||||
|
end
|
||||||
|
)
|
||||||
|
|
||||||
|
Command.add('log-global',
|
||||||
|
{
|
||||||
|
description = 'Logs the global table',
|
||||||
|
allowed_by_server = true,
|
||||||
|
required_rank = Ranks.admin,
|
||||||
|
},
|
||||||
|
function()
|
||||||
|
Debug.log(this)
|
||||||
|
end
|
||||||
|
)
|
||||||
|
|
||||||
-- ============================================================================
|
-- ============================================================================
|
||||||
|
|
||||||
return map
|
return map
|
||||||
|
Loading…
x
Reference in New Issue
Block a user