299 lines
15 KiB
Lua
299 lines
15 KiB
Lua
local base = require("base")
|
|
local drop_zone = require("drop_zone")
|
|
local setup = {}
|
|
|
|
local PLANETS = {"nauvis", "vulcanus", "fulgora", "gleba"}
|
|
local HUB_SURFACE_NAME = "planet-pvp-hub"
|
|
local HUB_MIN = -50
|
|
local HUB_MAX = 49
|
|
local HUB_VOID_MIN = -80
|
|
local HUB_VOID_MAX = 79
|
|
local HUB_LAYOUT_VERSION = 2
|
|
local LOADOUTS = {
|
|
nauvis = {{name = "burner-mining-drill", count = 1}, {name = "stone-furnace", count = 1}, {name = "iron-plate", count = 8}},
|
|
vulcanus = {{name = "burner-mining-drill", count = 1}, {name = "stone-furnace", count = 1}, {name = "iron-plate", count = 8}},
|
|
fulgora = {{name = "burner-mining-drill", count = 1}, {name = "stone-furnace", count = 1}, {name = "iron-plate", count = 8}},
|
|
gleba = {{name = "burner-mining-drill", count = 1}, {name = "stone-furnace", count = 1}, {name = "iron-plate", count = 8}},
|
|
}
|
|
local UNIVERSAL = { ["automation-science-pack"] = true, ["logistic-science-pack"] = true, ["military-science-pack"] = true, ["chemical-science-pack"] = true, ["production-science-pack"] = true, ["utility-science-pack"] = true, ["space-science-pack"] = true }
|
|
local TRIGGERS = {
|
|
["planet-discovery-nauvis"] = "nauvis", ["planet-discovery-vulcanus"] = "vulcanus", ["planet-discovery-fulgora"] = "fulgora", ["planet-discovery-gleba"] = "gleba", ["planet-discovery-aquilo"] = "aquilo",
|
|
["uranium-mining"] = "nauvis", ["bitter-egg-handling"] = "nauvis", ["recycling"] = "fulgora", ["holmium-processing"] = "fulgora", ["electromagnetic-plant"] = "fulgora", ["electromagnetic-science-pack"] = "fulgora",
|
|
["jellynut"] = "gleba", ["yumako"] = "gleba", ["heating-tower"] = "gleba", ["agriculture"] = "gleba", ["biochamber"] = "gleba", ["artificial-soil"] = "gleba", ["bioflux"] = "gleba", ["bacteria-cultivation"] = "gleba", ["bioflux-processing"] = "gleba", ["agricultural-science-pack"] = "gleba",
|
|
["tungsten-carbide"] = "vulcanus", ["calcite-processing"] = "vulcanus", ["foundry"] = "vulcanus", ["big-mining-drill"] = "vulcanus", ["tungsten-steel"] = "vulcanus", ["metallurgic-science-pack"] = "vulcanus",
|
|
["lithium-processing"] = "aquilo", ["cryogenic-plant"] = "aquilo", ["cryogenic-science-pack"] = "aquilo",
|
|
}
|
|
local BASIC = {["steam-power"] = true, ["electronics"] = true, ["automation-science-pack"] = true, ["steel-axe"] = true, ["oil-processing"] = true}
|
|
|
|
local function protect_hub_walls(surface)
|
|
for _, wall in pairs(surface.find_entities_filtered{name = "stone-wall", area = {{HUB_MIN - 1, HUB_MIN - 1}, {HUB_MAX + 1, HUB_MAX + 1}}}) do
|
|
wall.destructible = false
|
|
wall.minable_flag = false
|
|
end
|
|
end
|
|
|
|
local function build_hub_layout(surface)
|
|
surface.request_to_generate_chunks({0, 0}, 2)
|
|
surface.force_generate_chunk_requests()
|
|
|
|
local tiles = {}
|
|
for x = HUB_VOID_MIN, HUB_VOID_MAX do
|
|
for y = HUB_VOID_MIN, HUB_VOID_MAX do
|
|
tiles[#tiles + 1] = {name = "out-of-map", position = {x, y}}
|
|
end
|
|
end
|
|
for x = HUB_MIN, HUB_MAX do
|
|
for y = HUB_MIN, HUB_MAX do
|
|
tiles[#tiles + 1] = {name = "refined-concrete", position = {x, y}}
|
|
end
|
|
end
|
|
surface.set_tiles(tiles, true)
|
|
|
|
-- Replace any older lobby border before placing the updated perimeter.
|
|
for _, wall in pairs(surface.find_entities_filtered{name = "stone-wall", area = {{HUB_VOID_MIN, HUB_VOID_MIN}, {HUB_VOID_MAX + 1, HUB_VOID_MAX + 1}}}) do
|
|
wall.destroy()
|
|
end
|
|
local function create_wall(position)
|
|
local wall = surface.create_entity{name = "stone-wall", position = position, force = game.forces.player}
|
|
if wall then wall.destructible = false; wall.minable_flag = false end
|
|
end
|
|
for x = HUB_MIN, HUB_MAX do
|
|
create_wall({x, HUB_MIN})
|
|
create_wall({x, HUB_MAX})
|
|
end
|
|
for y = HUB_MIN + 1, HUB_MAX - 1 do
|
|
create_wall({HUB_MIN, y})
|
|
create_wall({HUB_MAX, y})
|
|
end
|
|
storage.hub_layout_version = HUB_LAYOUT_VERSION
|
|
end
|
|
|
|
local function get_hub_surface()
|
|
local surface = game.surfaces[HUB_SURFACE_NAME]
|
|
if not surface then
|
|
surface = game.create_surface(HUB_SURFACE_NAME, {
|
|
seed = 7082026,
|
|
peaceful_mode = true,
|
|
autoplace_controls = {},
|
|
autoplace_settings = {
|
|
entity = {treat_missing_as_default = false, settings = {}},
|
|
tile = {treat_missing_as_default = false, settings = {}},
|
|
},
|
|
})
|
|
end
|
|
if storage.hub_layout_version ~= HUB_LAYOUT_VERSION then
|
|
build_hub_layout(surface)
|
|
else
|
|
protect_hub_walls(surface)
|
|
end
|
|
return surface
|
|
end
|
|
|
|
local function teleport_to_hub(player)
|
|
if not (player and player.valid) or player.controller_type == defines.controllers.spectator then return end
|
|
local surface = get_hub_surface()
|
|
if player.controller_type == defines.controllers.cutscene then player.exit_cutscene() end
|
|
local position = surface.find_non_colliding_position("character", {0, 0}, 48, 1) or {0, 0}
|
|
player.teleport(position, surface)
|
|
storage.player_surfaces[player.index] = surface.index
|
|
end
|
|
|
|
local function has_selected_team(player)
|
|
if storage.player_team_joined and storage.player_team_joined[player.index] then return true end
|
|
for _, force_name in pairs(storage.planet_teams or {}) do
|
|
if player.force and player.force.name == force_name then
|
|
storage.player_team_joined = storage.player_team_joined or {}
|
|
storage.player_team_joined[player.index] = true
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
local function assign_fulgora_attractors(surface, area)
|
|
local force_name = storage.planet_teams and storage.planet_teams.fulgora
|
|
local force = force_name and game.forces[force_name]
|
|
if not (surface and surface.valid and force) then return end
|
|
for _, attractor in pairs(surface.find_entities_filtered{
|
|
name = "fulgoran-ruin-attractor",
|
|
area = area,
|
|
}) do
|
|
attractor.force = force
|
|
end
|
|
end
|
|
|
|
local function set_pvp_relations()
|
|
for i, a_name in ipairs(PLANETS) do
|
|
local a = game.forces[a_name]
|
|
if a then for j, b_name in ipairs(PLANETS) do
|
|
local b = game.forces[b_name]
|
|
if i ~= j and b then a.set_friend(b, false); b.set_friend(a, false); a.set_cease_fire(b, false); b.set_cease_fire(a, false) end
|
|
end end
|
|
end
|
|
end
|
|
|
|
local function requirement(tech)
|
|
local found
|
|
for _, ingredient in pairs(tech.research_unit_ingredients) do
|
|
if not UNIVERSAL[ingredient.name] then if found and found ~= ingredient.name then return "mixed" end; found = ingredient.name end
|
|
end
|
|
return found or "base"
|
|
end
|
|
|
|
local function unlock(force, planet_name)
|
|
force.unlock_space_location(planet_name)
|
|
for _, tech in pairs(force.technologies) do
|
|
if tech.enabled then
|
|
local assigned = TRIGGERS[tech.name]
|
|
local unlock_tech = BASIC[tech.name] or (requirement(tech) == "base" and not tech.prototype.upgrade)
|
|
if assigned then unlock_tech = assigned == planet_name and not tech.prototype.upgrade end
|
|
if tech.name == "metallurgic-science-pack" or tech.name == "electromagnetic-science-pack" or tech.name == "agricultural-science-pack" or tech.name == "cryogenic-science-pack" then unlock_tech = false end
|
|
if (tech.name:find("productivity%-module") or tech.name:find("speed%-module") or tech.name:find("efficiency%-module") or tech.name:find("quality%-module")) and tech.prototype.max_level < 3 then unlock_tech = true end
|
|
tech.researched = unlock_tech
|
|
end
|
|
end
|
|
end
|
|
|
|
local function show_admin(player)
|
|
if player.gui.screen.pvp_admin_frame then player.gui.screen.pvp_admin_frame.destroy() end
|
|
local frame = player.gui.screen.add{type = "frame", name = "pvp_admin_frame", caption = "ADMIN: CONFIGURE PLANET TEAMS", direction = "vertical"}
|
|
frame.auto_center = true
|
|
local table_ui = frame.add{type = "table", column_count = 2, name = "setup_table"}
|
|
for _, planet in pairs(PLANETS) do
|
|
table_ui.add{type = "label", caption = planet:gsub("^%l", string.upper) .. " Force Name:"}
|
|
table_ui.add{type = "textfield", name = "tf_" .. planet, text = "Team " .. planet:gsub("^%l", string.upper)}
|
|
end
|
|
frame.add{type = "button", name = "confirm_admin_setup", caption = "INITIALIZE WORLD", style = "confirm_button"}
|
|
end
|
|
|
|
local function show_join(player)
|
|
if player.gui.screen.pvp_join_frame then player.gui.screen.pvp_join_frame.destroy() end
|
|
if not storage.game_started or not storage.planet_teams then return end
|
|
local frame = player.gui.screen.add{type = "frame", name = "pvp_join_frame", caption = "CHOOSE YOUR HOME PLANET", direction = "vertical"}
|
|
frame.auto_center = true
|
|
for planet, force_name in pairs(storage.planet_teams) do frame.add{type = "button", name = "join_btn_" .. planet, caption = "Join " .. force_name .. " (" .. planet .. ")", style = "confirm_button"} end
|
|
end
|
|
|
|
local function show_waiting(player)
|
|
if player.gui.screen.pvp_waiting_frame then player.gui.screen.pvp_waiting_frame.destroy() end
|
|
local frame = player.gui.screen.add{type = "frame", name = "pvp_waiting_frame", caption = "PLANET PvP LOBBY", direction = "vertical"}
|
|
frame.auto_center = true
|
|
frame.add{type = "label", caption = "The admin is setting up the game. You can choose a team when setup is complete."}
|
|
end
|
|
|
|
function setup.on_init(observer)
|
|
storage.planet_teams, storage.player_targets, storage.grid_pos = {}, {}, {}
|
|
storage.game_started, storage.team_kit_spawned, storage.player_surfaces = false, {}, {}
|
|
storage.player_team_joined = {}
|
|
storage.force_bases, storage.permadead, storage.pending_spectator, storage.force_colors, storage.base_label_ids = {}, {}, {}, {}, {}
|
|
storage.player_lights, storage.crash_site_cleanup_done = {}, false
|
|
observer.create_force()
|
|
set_pvp_relations()
|
|
get_hub_surface()
|
|
for _, player in pairs(game.players) do player.set_shortcut_available("lock_drop_zone_shortcut", true) end
|
|
end
|
|
|
|
function setup.on_configuration_changed()
|
|
for _, key in pairs({"team_kit_spawned", "player_surfaces", "force_bases", "permadead", "pending_spectator", "force_colors", "base_label_ids", "player_targets", "grid_pos", "player_lights", "player_team_joined"}) do storage[key] = storage[key] or {} end
|
|
get_hub_surface()
|
|
for planet_name, force_name in pairs(storage.planet_teams or {}) do
|
|
local force = game.forces[force_name]
|
|
if force then
|
|
force.unlock_space_location(planet_name)
|
|
local tech = force.technologies["planet-discovery-nauvis"]
|
|
if tech and planet_name == "nauvis" then tech.researched = true end
|
|
end
|
|
end
|
|
local fulgora = game.planets.fulgora
|
|
if fulgora and fulgora.surface then assign_fulgora_attractors(fulgora.surface) end
|
|
for _, player in pairs(game.players) do player.set_shortcut_available("lock_drop_zone_shortcut", true) end
|
|
for _, player in pairs(game.connected_players) do
|
|
if not has_selected_team(player) then
|
|
teleport_to_hub(player)
|
|
if storage.game_started then show_join(player) elseif player.admin then show_admin(player) else show_waiting(player) end
|
|
end
|
|
end
|
|
end
|
|
|
|
function setup.on_chunk_generated(event)
|
|
if event.surface and event.surface.name == "fulgora" then
|
|
assign_fulgora_attractors(event.surface, event.area)
|
|
end
|
|
end
|
|
|
|
function setup.on_player_created(event)
|
|
local player = game.players[event.player_index]
|
|
storage.player_team_joined = storage.player_team_joined or {}
|
|
player.set_shortcut_available("lock_drop_zone_shortcut", true)
|
|
if player.controller_type == defines.controllers.cutscene then player.exit_cutscene() end
|
|
teleport_to_hub(player)
|
|
if storage.game_started then show_join(player) elseif player.admin then show_admin(player) else show_waiting(player) end
|
|
end
|
|
|
|
function setup.on_player_joined_game(event)
|
|
local player = game.players[event.player_index]
|
|
if not (player and player.valid) then return end
|
|
storage.player_team_joined = storage.player_team_joined or {}
|
|
if has_selected_team(player) or (storage.observers and storage.observers[player.index]) then return end
|
|
teleport_to_hub(player)
|
|
if storage.game_started then show_join(player) elseif player.admin then show_admin(player) else show_waiting(player) end
|
|
end
|
|
|
|
function setup.on_player_respawned(event)
|
|
local player = game.players[event.player_index]
|
|
if player and player.valid and not has_selected_team(player) then
|
|
teleport_to_hub(player)
|
|
end
|
|
end
|
|
|
|
function setup.on_gui_click(event)
|
|
local element, player = event.element, game.players[event.player_index]
|
|
if not (element and element.valid and player and player.valid) then return end
|
|
if element.name == "confirm_admin_setup" then
|
|
storage.planet_teams = {}
|
|
for _, planet in pairs(PLANETS) do
|
|
local textfield = element.parent.setup_table["tf_" .. planet]
|
|
local name = textfield and textfield.text ~= "" and textfield.text or "Team " .. planet
|
|
if not game.forces[name] then game.create_force(name) end
|
|
unlock(game.forces[name], planet); base.assign_force_color(name); storage.planet_teams[planet] = name
|
|
end
|
|
local fulgora = game.planets.fulgora
|
|
if fulgora and fulgora.surface then assign_fulgora_attractors(fulgora.surface) end
|
|
storage.game_started = true; element.parent.destroy()
|
|
for _, target in pairs(game.players) do
|
|
if target.valid and not (storage.player_team_joined and storage.player_team_joined[target.index]) then
|
|
teleport_to_hub(target)
|
|
if target.gui.screen.pvp_waiting_frame then target.gui.screen.pvp_waiting_frame.destroy() end
|
|
show_join(target)
|
|
end
|
|
end
|
|
elseif element.name:find("^join_btn_") then
|
|
local planet_name = element.name:gsub("^join_btn_", "")
|
|
local force_name = storage.planet_teams[planet_name]
|
|
if force_name then
|
|
player.force = game.forces[force_name]; player.clear_items_inside()
|
|
storage.player_team_joined = storage.player_team_joined or {}
|
|
storage.player_team_joined[player.index] = true
|
|
local planet = game.planets[planet_name]
|
|
if planet then
|
|
local surface = planet.create_surface()
|
|
if planet_name == "fulgora" then assign_fulgora_attractors(surface) end
|
|
if not storage.team_kit_spawned[force_name] then
|
|
storage.team_kit_spawned[force_name] = true
|
|
local position = surface.find_non_colliding_position("steel-chest", {x = 5, y = 0}, 100, .5) or {x = 5, y = 0}
|
|
local chest = surface.create_entity{name = "steel-chest", position = position, force = player.force, raise_built = true}
|
|
if chest and chest.valid then
|
|
local inventory = chest.get_inventory(defines.inventory.chest)
|
|
if inventory then for _, item in pairs(LOADOUTS[planet_name]) do if prototypes.item[item.name] then inventory.insert(item) end end end
|
|
end
|
|
base.spawn_initial(force_name, planet_name)
|
|
end
|
|
drop_zone.teleport_to_planet(player, surface)
|
|
end
|
|
end
|
|
if element.parent and element.parent.valid then element.parent.destroy() end
|
|
end
|
|
end
|
|
|
|
return setup
|