1
0
mirror of https://github.com/ComfyFactory/ComfyFactorio.git synced 2025-01-10 00:43:27 +02:00
ComfyFactorio/maps/biter_hatchery/main.lua
2021-03-24 18:22:45 +01:00

549 lines
18 KiB
Lua

--luacheck: ignore
require 'modules.no_turrets'
require 'modules.no_acid_puddles'
local Tabs = require 'comfy_panel.main'
local Map_score = require 'comfy_panel.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'
require 'maps.biter_hatchery.share_chat'
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 = global.map_forces[force_name].hatchery.position.x, y = global.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 = global.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, food_item)
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 a = 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, raffle in pairs(unit_raffle) do
if global.map_forces[belt.force.name].unit_count > global.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()
local surface = game.surfaces.nauvis
for key, force in pairs(global.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(global.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(global.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 global.game_reset_tick then
return
end
if entity.type == 'unit' then
local team = global.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 global.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 global.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}
global.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
Tabs.comfy_panel_call_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]
local surface = game.surfaces.nauvis
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 global.game_reset_tick then
if global.game_reset_tick < game_tick then
global.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
global.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)