mirror of
https://github.com/ComfyFactory/ComfyFactorio.git
synced 2025-01-10 00:43:27 +02:00
e91b6a352f
Change global -> storage Rework how rendering works Game prototypes are now stored inside 'prototypes.#' Renamed entity names
547 lines
19 KiB
Lua
547 lines
19 KiB
Lua
--luacheck: ignore
|
|
require 'modules.no_turrets'
|
|
require 'modules.no_acid_puddles'
|
|
local CoreGui = require 'utils.gui'
|
|
require 'maps.biter_hatchery.share_chat'
|
|
local Map_score = require 'utils.gui.map_score'
|
|
local unit_raffle = require 'maps.biter_hatchery.raffle_tables'
|
|
local Terrain = require 'maps.biter_hatchery.terrain'
|
|
local Gui = require 'maps.biter_hatchery.gui'
|
|
local Team = require 'maps.biter_hatchery.team'
|
|
local Unit_health_booster = require 'modules.biter_health_booster'
|
|
local Map = require 'modules.map_info'
|
|
local Global = require 'utils.global'
|
|
local Server = require 'utils.server'
|
|
|
|
local math_random = math.random
|
|
|
|
local hatchery = {}
|
|
Global.register(
|
|
hatchery,
|
|
function (tbl)
|
|
hatchery = tbl
|
|
end
|
|
)
|
|
|
|
local m = 2
|
|
local health_boost_food_values = {
|
|
['automation-science-pack'] = 0.000001 * m,
|
|
['logistic-science-pack'] = 0.000003 * m,
|
|
['military-science-pack'] = 0.00000822 * m,
|
|
['chemical-science-pack'] = 0.00002271 * m,
|
|
['production-science-pack'] = 0.00009786 * m,
|
|
['utility-science-pack'] = 0.00010634 * m,
|
|
['space-science-pack'] = 0.00041828 * m
|
|
}
|
|
|
|
local worm_turret_spawn_radius = 25
|
|
local worm_turret_vectors = {}
|
|
worm_turret_vectors.west = {}
|
|
for x = 0, worm_turret_spawn_radius, 1 do
|
|
for y = worm_turret_spawn_radius * -1, worm_turret_spawn_radius, 1 do
|
|
local d = math.sqrt(x ^ 2 + y ^ 2)
|
|
if d <= worm_turret_spawn_radius and d > 3 then
|
|
table.insert(worm_turret_vectors.west, { x, y })
|
|
end
|
|
end
|
|
end
|
|
worm_turret_vectors.east = {}
|
|
for x = worm_turret_spawn_radius * -1, 0, 1 do
|
|
for y = worm_turret_spawn_radius * -1, worm_turret_spawn_radius, 1 do
|
|
local d = math.sqrt(x ^ 2 + y ^ 2)
|
|
if d <= worm_turret_spawn_radius and d > 3 then
|
|
table.insert(worm_turret_vectors.east, { x, y })
|
|
end
|
|
end
|
|
end
|
|
|
|
local function spawn_worm_turret(surface, force_name)
|
|
local r_max = surface.count_entities_filtered({ type = 'turret', force = force_name }) + 1
|
|
if r_max > 256 then
|
|
return
|
|
end
|
|
if math_random(1, r_max) ~= 1 then
|
|
return
|
|
end
|
|
local vectors = worm_turret_vectors[force_name]
|
|
local vector = vectors[math_random(1, #vectors)]
|
|
local worm = 'small-worm-turret'
|
|
local position = { x = storage.map_forces[force_name].hatchery.position.x, y = storage.map_forces[force_name].hatchery.position.y }
|
|
position.x = position.x + vector[1]
|
|
position.y = position.y + vector[2]
|
|
position = surface.find_non_colliding_position('biter-spawner', position, 16, 1)
|
|
if not position then
|
|
return
|
|
end
|
|
surface.create_entity({ name = worm, position = position, force = force_name })
|
|
surface.create_entity({ name = 'blood-explosion-huge', position = position })
|
|
surface.create_decoratives { check_collision = false, decoratives = { { name = 'enemy-decal', position = position, amount = 1 } } }
|
|
end
|
|
|
|
local function spawn_units(belt, food_item, removed_item_count)
|
|
local count_per_flask = unit_raffle[food_item][2]
|
|
local raffle = unit_raffle[food_item][1]
|
|
local team = storage.map_forces[belt.force.name]
|
|
team.unit_health_boost = team.unit_health_boost + (health_boost_food_values[food_item] * removed_item_count)
|
|
for _ = 1, removed_item_count, 1 do
|
|
for _ = 1, count_per_flask, 1 do
|
|
local name = raffle[math_random(1, #raffle)]
|
|
local unit = belt.surface.create_entity({ name = name, position = belt.position, force = belt.force })
|
|
unit.ai_settings.allow_destroy_when_commands_fail = false
|
|
unit.ai_settings.allow_try_return_to_spawner = false
|
|
Unit_health_booster.add_unit(unit, team.unit_health_boost)
|
|
team.units[unit.unit_number] = unit
|
|
team.unit_count = team.unit_count + 1
|
|
end
|
|
end
|
|
if math_random(1, 8) == 1 then
|
|
spawn_worm_turret(belt.surface, belt.force.name)
|
|
end
|
|
end
|
|
|
|
local function get_belts(spawner)
|
|
local belts =
|
|
spawner.surface.find_entities_filtered(
|
|
{
|
|
type = 'transport-belt',
|
|
area = { { spawner.position.x - 5, spawner.position.y - 3 }, { spawner.position.x + 4, spawner.position.y + 3 } },
|
|
force = spawner.force
|
|
}
|
|
)
|
|
return belts
|
|
end
|
|
|
|
local nom_msg = { 'munch', 'munch', 'yum', 'nom' }
|
|
|
|
local function feed_floaty_text(entity)
|
|
entity.surface.create_entity({ name = 'flying-text', position = entity.position, text = nom_msg[math_random(1, 4)], color = { math_random(50, 100), 0, 255 } })
|
|
local position = { x = entity.position.x - 0.75, y = entity.position.y - 1 }
|
|
local b = 1.35
|
|
for _ = 1, math_random(0, 2), 1 do
|
|
local p = { (position.x + 0.4) + (b * -1 + math_random(0, b * 20) * 0.1), position.y + (b * -1 + math_random(0, b * 20) * 0.1) }
|
|
entity.surface.create_entity({ name = 'flying-text', position = p, text = '♥', color = { math_random(150, 255), 0, 255 } })
|
|
end
|
|
end
|
|
|
|
local function eat_food_from_belt(belt)
|
|
for i = 1, 2, 1 do
|
|
local line = belt.get_transport_line(i)
|
|
for food_item, _ in pairs(unit_raffle) do
|
|
if storage.map_forces[belt.force.name].unit_count > storage.map_forces[belt.force.name].max_unit_count then
|
|
return
|
|
end
|
|
local removed_item_count = line.remove_item({ name = food_item, count = 8 })
|
|
if removed_item_count > 0 then
|
|
feed_floaty_text(belt)
|
|
spawn_units(belt, food_item, removed_item_count)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function nom()
|
|
for _, force in pairs(storage.map_forces) do
|
|
if not force.hatchery then
|
|
return
|
|
end
|
|
force.hatchery.health = force.hatchery.health + 1
|
|
local belts = get_belts(force.hatchery)
|
|
for _, belt in pairs(belts) do
|
|
eat_food_from_belt(belt)
|
|
end
|
|
end
|
|
for _, player in pairs(game.connected_players) do
|
|
Gui.update_health_boost_buttons(player)
|
|
end
|
|
end
|
|
|
|
local function get_units(force_name)
|
|
local units = {}
|
|
local count = 1
|
|
for _, unit in pairs(storage.map_forces[force_name].units) do
|
|
if unit.valid and not unit.unit_group then
|
|
if math_random(1, 3) ~= 1 then
|
|
units[count] = unit
|
|
count = count + 1
|
|
end
|
|
end
|
|
end
|
|
return units
|
|
end
|
|
|
|
local function alert_bubble(force_name, entity)
|
|
if force_name == 'west' then
|
|
force_name = 'east'
|
|
else
|
|
force_name = 'west'
|
|
end
|
|
for _, player in pairs(game.forces[force_name].connected_players) do
|
|
player.add_custom_alert(entity, { type = 'item', name = 'tank' }, 'Incoming enemy units!', true)
|
|
end
|
|
end
|
|
|
|
local function send_unit_groups()
|
|
local surface = game.surfaces.nauvis
|
|
for key, force in pairs(storage.map_forces) do
|
|
local units = get_units(key)
|
|
if #units > 0 then
|
|
alert_bubble(key, units[1])
|
|
local vectors = worm_turret_vectors[key]
|
|
local vector = vectors[math_random(1, #vectors)]
|
|
local position = { x = force.hatchery.position.x + vector[1], y = force.hatchery.position.y + vector[2] }
|
|
local unit_group = surface.create_unit_group({ position = position, force = key })
|
|
for _, unit in pairs(units) do
|
|
unit_group.add_member(unit)
|
|
end
|
|
if not force.target then
|
|
return
|
|
end
|
|
if not force.target.valid then
|
|
return
|
|
end
|
|
unit_group.set_command(
|
|
{
|
|
type = defines.command.compound,
|
|
structure_type = defines.compound_command.return_last,
|
|
commands = {
|
|
{
|
|
type = defines.command.attack_area,
|
|
destination = { x = force.target.position.x, y = force.target.position.y },
|
|
radius = 6,
|
|
distraction = defines.distraction.by_anything
|
|
},
|
|
{
|
|
type = defines.command.attack,
|
|
target = force.target,
|
|
distraction = defines.distraction.by_enemy
|
|
}
|
|
}
|
|
}
|
|
)
|
|
unit_group.start_moving()
|
|
end
|
|
end
|
|
end
|
|
|
|
local border_teleport = {
|
|
['east'] = 1,
|
|
['west'] = -1
|
|
}
|
|
|
|
local function on_player_changed_position(event)
|
|
local player = game.players[event.player_index]
|
|
if not player.character then
|
|
return
|
|
end
|
|
if not player.character.valid then
|
|
return
|
|
end
|
|
if player.position.x > -4 and player.position.x < 4 then
|
|
if not border_teleport[player.force.name] then
|
|
return
|
|
end
|
|
if player.character.driving then
|
|
player.character.driving = false
|
|
end
|
|
player.teleport({ player.position.x + border_teleport[player.force.name], player.position.y }, game.surfaces.nauvis)
|
|
end
|
|
end
|
|
|
|
local function on_entity_died(event)
|
|
local entity = event.entity
|
|
if not entity.valid then
|
|
return
|
|
end
|
|
if storage.game_reset_tick then
|
|
return
|
|
end
|
|
|
|
if entity.type == 'unit' then
|
|
local team = storage.map_forces[entity.force.name]
|
|
team.unit_count = team.unit_count - 1
|
|
team.units[entity.unit_number] = nil
|
|
return
|
|
end
|
|
|
|
if entity.type ~= 'unit-spawner' then
|
|
return
|
|
end
|
|
|
|
if entity.force.name == 'east' then
|
|
game.print('East lost their Hatchery.', { 100, 100, 100 })
|
|
game.forces.east.play_sound { path = 'utility/game_lost', volume_modifier = 0.85 }
|
|
|
|
local message = '>>>> WEST TEAM HAS WON THE GAME!!! <<<<'
|
|
Server.to_discord_bold(table.concat { '*** ', message, ' ***' })
|
|
game.print(message, { 250, 120, 0 })
|
|
|
|
game.forces.west.play_sound { path = 'utility/game_won', volume_modifier = 0.85 }
|
|
|
|
for _, player in pairs(game.forces.west.connected_players) do
|
|
if storage.map_forces.east.player_count > 0 then
|
|
Map_score.set_score(player, Map_score.get_score(player) + 1)
|
|
end
|
|
end
|
|
else
|
|
game.print('West lost their Hatchery.', { 100, 100, 100 })
|
|
game.forces.west.play_sound { path = 'utility/game_lost', volume_modifier = 0.85 }
|
|
|
|
local message = '>>>> EAST TEAM HAS WON THE GAME!!! <<<<'
|
|
Server.to_discord_bold(table.concat { '*** ', message, ' ***' })
|
|
game.print(message, { 250, 120, 0 })
|
|
|
|
game.forces.east.play_sound { path = 'utility/game_won', volume_modifier = 0.85 }
|
|
|
|
for _, player in pairs(game.forces.east.connected_players) do
|
|
if storage.map_forces.west.player_count > 0 then
|
|
Map_score.set_score(player, Map_score.get_score(player) + 1)
|
|
end
|
|
end
|
|
end
|
|
|
|
game.print('Map rerolling in 2 minutes.', { 150, 150, 150 })
|
|
|
|
game.forces.spectator.play_sound { path = 'utility/game_won', volume_modifier = 0.85 }
|
|
|
|
storage.game_reset_tick = game.tick + 7200
|
|
|
|
for _, player in pairs(game.connected_players) do
|
|
for _, child in pairs(player.gui.left.children) do
|
|
child.destroy()
|
|
end
|
|
CoreGui.call_existing_tab(player, 'Map Scores')
|
|
end
|
|
|
|
for _, e in pairs(entity.surface.find_entities_filtered({ type = 'unit' })) do
|
|
e.active = false
|
|
end
|
|
end
|
|
|
|
local function on_player_joined_game(event)
|
|
local player = game.players[event.player_index]
|
|
|
|
Gui.unit_health_buttons(player)
|
|
Gui.spectate_button(player)
|
|
Gui.update_health_boost_buttons(player)
|
|
|
|
if player.force.name == 'player' then
|
|
if player.character and player.character.valid then
|
|
player.character.destroy()
|
|
end
|
|
player.character = nil
|
|
player.spectator = true
|
|
player.set_controller({ type = defines.controllers.spectator })
|
|
if hatchery.gamestate == 'game_in_progress' or hatchery.gamestate == 'rejoin_question' then
|
|
Team.assign_force_to_player(player)
|
|
Team.add_player_to_team(player)
|
|
Team.teleport_player_to_spawn(player)
|
|
end
|
|
end
|
|
end
|
|
|
|
--Construction Robot Restriction
|
|
local robot_build_restriction = {
|
|
['east'] = function (x)
|
|
if x < 0 then
|
|
return true
|
|
end
|
|
end,
|
|
['west'] = function (x)
|
|
if x > 0 then
|
|
return true
|
|
end
|
|
end
|
|
}
|
|
|
|
local function on_robot_built_entity(event)
|
|
if not robot_build_restriction[event.robot.force.name] then
|
|
return
|
|
end
|
|
if not robot_build_restriction[event.robot.force.name](event.created_entity.position.x) then
|
|
return
|
|
end
|
|
local inventory = event.robot.get_inventory(defines.inventory.robot_cargo)
|
|
inventory.insert({ name = event.created_entity.name, count = 1 })
|
|
event.robot.surface.create_entity({ name = 'explosion', position = event.created_entity.position })
|
|
game.print('Team ' .. event.robot.force.name .. "'s construction drone had an accident.", { r = 200, g = 50, b = 100 })
|
|
event.created_entity.destroy()
|
|
end
|
|
|
|
local function on_entity_damaged(event)
|
|
local entity = event.entity
|
|
if not entity.valid then
|
|
return
|
|
end
|
|
if entity.type ~= 'unit-spawner' then
|
|
return
|
|
end
|
|
local cause = event.cause
|
|
if cause then
|
|
if cause.valid then
|
|
if cause.type == 'unit' then
|
|
if math_random(1, 16) == 1 then
|
|
return
|
|
end
|
|
end
|
|
end
|
|
end
|
|
entity.health = entity.health + event.final_damage_amount
|
|
end
|
|
|
|
local function on_player_used_spider_remote(event)
|
|
local vehicle = event.vehicle
|
|
local position = event.position
|
|
local success = event.success
|
|
if not success then
|
|
return
|
|
end
|
|
if vehicle.force.name == 'west' then
|
|
if position.x < -3 then
|
|
return
|
|
end
|
|
else
|
|
if position.x > 3 then
|
|
return
|
|
end
|
|
end
|
|
vehicle.autopilot_destination = nil
|
|
end
|
|
|
|
local function game_in_progress(hatchery)
|
|
local game_tick = game.tick
|
|
if game_tick % 30 ~= 0 then
|
|
return
|
|
end
|
|
if game_tick % 240 == 0 then
|
|
local surface = game.surfaces.nauvis
|
|
local west = game.forces.west
|
|
local east = game.forces.east
|
|
local area = { { -320, -161 }, { 319, 160 } }
|
|
west.chart(surface, area)
|
|
east.chart(surface, area)
|
|
local r = 64
|
|
for _, player in pairs(west.connected_players) do
|
|
east.chart(surface, { { player.position.x - r, player.position.y - r }, { player.position.x + r, player.position.y + r } })
|
|
end
|
|
for _, player in pairs(east.connected_players) do
|
|
west.chart(surface, { { player.position.x - r, player.position.y - r }, { player.position.x + r, player.position.y + r } })
|
|
end
|
|
end
|
|
if storage.game_reset_tick then
|
|
if storage.game_reset_tick < game_tick then
|
|
storage.game_reset_tick = nil
|
|
hatchery.gamestate = 'init'
|
|
end
|
|
return
|
|
end
|
|
if game_tick % 1200 == 0 then
|
|
send_unit_groups()
|
|
end
|
|
nom()
|
|
end
|
|
|
|
local no_mirror_states = {
|
|
['init'] = true,
|
|
['reset_nauvis'] = true,
|
|
['prepare_east'] = true,
|
|
['clear_west'] = true
|
|
}
|
|
|
|
local function on_chunk_generated(event)
|
|
local surface = event.surface
|
|
if event.surface.index ~= 1 then
|
|
return
|
|
end
|
|
|
|
local left_top = event.area.left_top
|
|
|
|
if Terrain.is_out_of_map_chunk(left_top) then
|
|
Terrain.out_of_map(surface, left_top)
|
|
return
|
|
end
|
|
|
|
if left_top.x < 0 and not no_mirror_states[hatchery.gamestate] then
|
|
table.insert(hatchery.mirror_queue, { { left_top.x, left_top.y }, 1 })
|
|
Terrain.out_of_map(surface, left_top)
|
|
return
|
|
end
|
|
|
|
surface.request_to_generate_chunks({ x = ((left_top.x * -1) - 32) + 16, y = left_top.y + 16 }, 0)
|
|
Terrain.out_of_map_area(surface, left_top)
|
|
Terrain.combat_area(event)
|
|
end
|
|
|
|
local gamestates = {
|
|
['init'] = Team.init,
|
|
['reset_nauvis'] = Terrain.reset_nauvis,
|
|
['prepare_east'] = Terrain.prepare_east,
|
|
['clear_west'] = Terrain.clear_west,
|
|
['prepare_west'] = Terrain.prepare_west,
|
|
['draw_team_nests'] = Terrain.draw_team_nests,
|
|
['draw_border_beams'] = Terrain.draw_border_beams,
|
|
['spawn_players'] = Team.spawn_players,
|
|
['rejoin_question'] = Gui.rejoin_question,
|
|
['game_in_progress'] = game_in_progress
|
|
}
|
|
|
|
local function on_tick()
|
|
Terrain.mirror_queue(hatchery)
|
|
gamestates[hatchery.gamestate](hatchery)
|
|
end
|
|
|
|
local function on_init()
|
|
hatchery.gamestate = 'init'
|
|
hatchery.reset_counter = 0
|
|
hatchery.mirror_queue = {}
|
|
|
|
game.permissions.get_group('Default').set_allows_action(defines.input_action.open_blueprint_library_gui, false)
|
|
game.permissions.get_group('Default').set_allows_action(defines.input_action.import_blueprint_string, false)
|
|
|
|
game.difficulty_settings.technology_price_multiplier = 0.5
|
|
game.map_settings.enemy_evolution.destroy_factor = 0
|
|
game.map_settings.enemy_evolution.pollution_factor = 0
|
|
game.map_settings.enemy_evolution.time_factor = 0
|
|
game.map_settings.enemy_expansion.enabled = false
|
|
game.map_settings.pollution.enabled = false
|
|
storage.map_forces = {
|
|
['west'] = {},
|
|
['east'] = {}
|
|
}
|
|
|
|
local T = Map.Pop_info()
|
|
T.main_caption = 'Biter Hatchery'
|
|
T.sub_caption = '*nibble nibble nom nom*'
|
|
T.text =
|
|
table.concat(
|
|
{
|
|
'Defeat the enemy teams nest.\n',
|
|
'Feed your hatchery science flasks to breed biters!\n',
|
|
'They will soon after swarm to the opposing teams nest!\n',
|
|
'\n',
|
|
'Lay transport belts to your hatchery and they will happily nom the science juice off the conveyor.\n',
|
|
'Higher tier flasks will breed stronger biters!\n',
|
|
'\n',
|
|
'Player turrets are disabled.\n',
|
|
'Feeding may spawn friendly worm turrets.\n',
|
|
'The center river may not be crossed.\n',
|
|
'Construction robots may not build over the river.\n'
|
|
}
|
|
)
|
|
T.main_caption_color = { r = 150, g = 0, b = 255 }
|
|
T.sub_caption_color = { r = 0, g = 250, b = 150 }
|
|
|
|
Team.create_forces()
|
|
Team.reset_forces()
|
|
end
|
|
|
|
local Event = require 'utils.event'
|
|
Event.on_init(on_init)
|
|
Event.add(defines.events.on_tick, on_tick)
|
|
Event.add(defines.events.on_player_used_spider_remote, on_player_used_spider_remote)
|
|
Event.add(defines.events.on_robot_built_entity, on_robot_built_entity)
|
|
Event.add(defines.events.on_entity_died, on_entity_died)
|
|
Event.add(defines.events.on_player_joined_game, on_player_joined_game)
|
|
Event.add(defines.events.on_player_changed_position, on_player_changed_position)
|
|
Event.add(defines.events.on_entity_damaged, on_entity_damaged)
|
|
Event.add(defines.events.on_chunk_generated, on_chunk_generated)
|