PlanetPvPGreen/setup.lua
2026-09-30 21:13:44 -05:00

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