166 lines
7.6 KiB
Lua
166 lines
7.6 KiB
Lua
local drop_zone = require("drop_zone")
|
|
local base = {}
|
|
|
|
local COLORS = {
|
|
{r = .90, g = .45, b = .10, a = 1}, {r = .95, g = .20, b = .20, a = 1},
|
|
{r = .70, g = .20, b = .90, a = 1}, {r = .20, g = .85, b = .20, a = 1},
|
|
{r = .20, g = .60, b = .95, a = 1},
|
|
}
|
|
|
|
local function notify(force_name, message)
|
|
local force = game.forces[force_name]
|
|
if force then for _, player in pairs(force.players) do if player.valid then player.print(message) end end end
|
|
end
|
|
|
|
local function count(force_name)
|
|
local total = 0
|
|
for _ in pairs(storage.force_bases[force_name] or {}) do total = total + 1 end
|
|
return total
|
|
end
|
|
|
|
local function color_for(force_name)
|
|
return storage.force_colors[force_name] or {r = 1, g = 1, b = 1, a = 1}
|
|
end
|
|
|
|
function base.assign_force_color(force_name)
|
|
if storage.force_colors[force_name] then return end
|
|
local used = 0
|
|
for _ in pairs(storage.force_colors) do used = used + 1 end
|
|
storage.force_colors[force_name] = COLORS[(used % #COLORS) + 1]
|
|
end
|
|
|
|
function base.register(entity)
|
|
if not (entity and entity.valid) then return end
|
|
local force_name = entity.force.name
|
|
storage.force_bases[force_name] = storage.force_bases[force_name] or {}
|
|
storage.force_bases[force_name][entity.unit_number] = true
|
|
local color = color_for(force_name)
|
|
entity.color = color
|
|
storage.base_label_ids[entity.unit_number] = rendering.draw_text{
|
|
text = force_name, surface = entity.surface, target = entity, target_offset = {0, -3.5},
|
|
color = color, scale = 2, font = "default-bold", alignment = "center", visible = true,
|
|
}
|
|
notify(force_name, "[color=green][BASE] A base has been established at (" .. math.floor(entity.position.x)
|
|
.. ", " .. math.floor(entity.position.y) .. ") on " .. entity.surface.name .. ".[/color]")
|
|
end
|
|
|
|
function base.spawn_initial(force_name, planet_name)
|
|
local planet = game.planets[planet_name]
|
|
if not planet then return end
|
|
local surface = planet.create_surface()
|
|
local position = surface.find_non_colliding_position("market", {8, 0}, 200, 1) or {x = 8, y = 0}
|
|
local entity = surface.create_entity{name = "pvp-base", position = position, force = game.forces[force_name], raise_built = true}
|
|
if entity and entity.valid then base.register(entity) end
|
|
end
|
|
|
|
local function destroyed(entity)
|
|
local force_name = entity.force.name
|
|
if storage.force_bases[force_name] then storage.force_bases[force_name][entity.unit_number] = nil end
|
|
local label = storage.base_label_ids[entity.unit_number]
|
|
if label and label.valid then label.destroy() end
|
|
storage.base_label_ids[entity.unit_number] = nil
|
|
local remaining = count(force_name)
|
|
if remaining > 0 then
|
|
notify(force_name, "[color=orange][BASE] A base was destroyed! You have " .. remaining .. " base(s) remaining. Respawn is still active.[/color]")
|
|
else
|
|
notify(force_name, "[color=red][BASE] ALL BASES DESTROYED! Any player who dies now is PERMANENTLY ELIMINATED. Rebuild a base core to restore respawning.[/color]")
|
|
end
|
|
end
|
|
|
|
local function spectator(player)
|
|
player.set_controller{type = defines.controllers.spectator}
|
|
player.print("[color=red]You have been permanently eliminated.[/color]")
|
|
end
|
|
|
|
function base.on_built_entity(event)
|
|
if event.entity and event.entity.valid and event.entity.name == "pvp-base" then base.register(event.entity) end
|
|
end
|
|
|
|
function base.on_entity_died(event)
|
|
if event.entity and event.entity.valid and event.entity.name == "pvp-base" then destroyed(event.entity) end
|
|
end
|
|
|
|
function base.on_player_died(event)
|
|
local player = game.players[event.player_index]
|
|
if not (player and player.valid) then return end
|
|
if not (storage.player_team_joined and storage.player_team_joined[player.index]) then return end
|
|
local force_name = player.force.name
|
|
if storage.permadead[force_name] and storage.permadead[force_name][player.index] then return end
|
|
if count(force_name) > 0 then
|
|
player.print("[color=yellow]You died. Respawning... (Base is alive)[/color]")
|
|
else
|
|
storage.permadead[force_name] = storage.permadead[force_name] or {}
|
|
storage.permadead[force_name][player.index] = true
|
|
storage.pending_spectator[player.index] = force_name
|
|
player.print("[color=red]You died while your team had no base. You are PERMANENTLY ELIMINATED.[/color]")
|
|
end
|
|
end
|
|
|
|
function base.on_player_respawned(event)
|
|
local player = game.players[event.player_index]
|
|
if not (player and player.valid) then return end
|
|
if not (storage.player_team_joined and storage.player_team_joined[player.index]) then return end
|
|
local force_name = player.force.name
|
|
if storage.permadead[force_name] and storage.permadead[force_name][player.index] then spectator(player); return end
|
|
if count(force_name) == 0 then
|
|
storage.permadead[force_name] = storage.permadead[force_name] or {}
|
|
storage.permadead[force_name][player.index] = true
|
|
spectator(player)
|
|
return
|
|
end
|
|
for planet_name, assigned_force in pairs(storage.planet_teams or {}) do
|
|
if assigned_force == force_name then
|
|
local planet = game.planets[planet_name]
|
|
if planet and planet.surface then drop_zone.teleport_to_planet(player, planet.surface) end
|
|
return
|
|
end
|
|
end
|
|
end
|
|
|
|
function base.on_pre_player_mined_item(event)
|
|
local entity, player = event.entity, game.players[event.player_index]
|
|
if entity and entity.valid and entity.name == "pvp-base" and player and player.valid then
|
|
player.mining_state = {mining = false}
|
|
player.print("[color=red]The base cannot be moved once placed. Destroy it to retrieve the core.[/color]")
|
|
end
|
|
end
|
|
|
|
function base.on_robot_pre_mined(event)
|
|
local entity = event.entity
|
|
if entity and entity.valid and entity.name == "pvp-base" then entity.cancel_deconstruction("all") end
|
|
end
|
|
|
|
function base.on_tick(event)
|
|
if not storage.crash_site_cleanup_done then
|
|
local nauvis = game.planets["nauvis"] and game.planets["nauvis"].surface
|
|
if nauvis then
|
|
local crash_names = {
|
|
"crash-site-spaceship", "crash-site-spaceship-wreck-big-1", "crash-site-spaceship-wreck-big-2",
|
|
"crash-site-spaceship-wreck-medium-1", "crash-site-spaceship-wreck-medium-2", "crash-site-spaceship-wreck-medium-3",
|
|
"crash-site-spaceship-wreck-small-1", "crash-site-spaceship-wreck-small-2", "crash-site-spaceship-wreck-small-3",
|
|
"crash-site-spaceship-wreck-small-4", "crash-site-spaceship-wreck-small-5", "crash-site-spaceship-wreck-small-6",
|
|
"crash-site-chest-1", "crash-site-chest-2",
|
|
}
|
|
for _, name in pairs(crash_names) do
|
|
for _, entity in pairs(nauvis.find_entities_filtered{name = name}) do if entity.valid then entity.destroy() end end
|
|
end
|
|
for _, type in pairs({"fire", "smoke", "explosion", "particle"}) do
|
|
for _, entity in pairs(nauvis.find_entities_filtered{type = type, area = {{-200, -200}, {200, 200}}}) do if entity.valid then entity.destroy() end end
|
|
end
|
|
if event.tick >= 300 then storage.crash_site_cleanup_done = true end
|
|
end
|
|
end
|
|
if event.tick % 10 ~= 0 or not next(storage.pending_spectator) then return end
|
|
for index in pairs(storage.pending_spectator) do
|
|
local player = game.players[index]
|
|
if player and player.valid and not player.character then spectator(player); storage.pending_spectator[index] = nil end
|
|
end
|
|
end
|
|
|
|
function base.status_command(event)
|
|
local player = game.players[event.player_index]
|
|
if player then for force_name in pairs(storage.force_bases) do player.print(force_name .. ": " .. count(force_name) .. " base(s)") end end
|
|
end
|
|
|
|
return base
|