global.this = {} local _global = require("utils.global") local _evt = require("utils.event") local _server = require("utils.server") local _map = require("tools.map_functions") local _timers = require("planet_prison.mod.timers") local _common = require("planet_prison.mod.common") local _layers = require("planet_prison.mod.layers") local _ai = require("planet_prison.mod.ai") local _bp = require("planet_prison.mod.bp") local _afk = require("planet_prison.mod.afk") local _claims = require("planet_prison.mod.claims") global.this._config = require("planet_prison.config") global.this.maps = { { name = "flooded-metropolia", height = 2000, width = 2000, water = 1, terrain_segmentation = 8, property_expression_names = { moisture = 0, temperature = 30. }, cliff_settings = { richness = 0, }, starting_area = "none", autoplace_controls = { ["iron-ore"] = { frequency = 0, }, ["copper-ore"] = { frequency = 0, }, ["uranium-ore"] = { frequency = 0, }, ["stone"] = { frequency = 0, }, ["coal"] = { frequency = 0, }, ["crude-oil"] = { frequency = 1000, size = 1, }, ["trees"] = { frequency = 4, }, ["enemy-base"] = { frequency = 0, } }, } } global.this.assign_camouflage = function(ent, common) local shade = common.rand_range(20, 200) ent.color = { r = shade, g = shade, b = shade } ent.disable_flashlight() end local function noise_hostile_hook(ent, common) ent.force = "enemy" if ent.name == "character" then global.this.assign_camouflage(ent, common) if common.rand_range(1, 5) == 1 then ent.insert({name="shotgun", count=1}) ent.insert({name="shotgun-shell", count=20}) else ent.insert({name="pistol", count=1}) ent.insert({name="firearm-magazine", count=20}) end else ent.insert({name="firearm-magazine", count=200}) end end local function noise_set_neutral_hook(ent) ent.force = "neutral" end local industrial_zone_layers = { { type = "LuaTile", name = "concrete", objects = { "concrete", }, elevation = 0.3, resolution = 0.2, hook = nil, deps = nil, }, { type = "LuaTile", name = "stones", objects = { "stone-path", }, elevation = 0.2, resolution = 0.4, hook = nil, deps = nil, }, { type = "LuaTile", name = "shallows", objects = { "water-shallow", }, elevation = 0.7, resolution = 0.01, hook = nil, deps = nil, }, { type = "LuaEntity", name = "scrap", objects = { "mineable-wreckage", }, elevation = 0.5, resolution = 0.1, hook = nil, deps = nil, }, { type = "LuaEntity", name = "walls", objects = { "stone-wall" }, elevation = 0.5, resolution = 0.09, hook = noise_set_neutral_hook, deps = nil, }, { type = "LuaEntity", name = "hostile", objects = { "character", "gun-turret", }, elevation = 0.92, resolution = 0.99, hook = noise_hostile_hook, deps = _common, }, { type = "LuaEntity", name = "structures", objects = { "big-electric-pole", "medium-electric-pole", }, elevation = 0.9, resolution = 0.9, hook = noise_set_neutral_hook, deps = nil, }, } global.this.presets = { ["flooded-metropolia"] = industrial_zone_layers, } global.this.entities_cache = nil global.this.surface = nil global.this.last_friend = nil local function pick_map() return global.this.maps[_common.rand_range(1, #global.this.maps)] end local function find_force(name) for _, f in pairs(game.forces) do if f.name == name then return f end end return nil end local function init_player_ship_bp(entity, player) entity.force = player.force if entity.name == "crash-site-chest-1" then for _, stack in pairs(global.this._config.player_ship_loot) do entity.insert(stack) end end if entity.name == "crash-site-generator" then entity.electric_buffer_size = 2000 entity.power_production = 2000 end end global.this.events = { merchant = { alive = false, moving = false, spawn_tick = 0, embark_tick = 0, position = { x = 0, y = 0 }, offer = global.this._config.merchant_offer, } } local function init_merchant_bp(entity, _) entity.force = "merchant" entity.rotatable = false entity.minable = false if entity.name ~= "market" then entity.operable = false else for _, entry in pairs(global.this.events.merchant.offer) do entity.add_market_item(entry) end end end local function create_orbit_group() local orbit = game.permissions.create_group("orbit") for _, perm in pairs(global.this._config.permission_orbit) do orbit.set_allows_action(perm, false) end end global.this.bp = { player_ship = require("planet_prison.bp.player_ship"), merchant = require("planet_prison.bp.merchant") } local function init_game() _common.init() _layers.init() _bp.init() _ai.init() _timers.init() _claims.init(global.this._config.claim_markers, global.this._config.claim_max_distance) local map = pick_map() local preset = global.this.presets[map.name] global.this.surface = game.create_surface("arena", map) global.this.surface.brightness_visual_weights = { 1 / 0.85, 1 / 0.85, 1 / 0.85 } global.this.surface.ticks_per_day = 25000 * 4 global.this.perks = {} global.this.events.merchant.spawn_tick = game.tick + 5000 global.this.events.raid_groups = {} global.this.events.raid_init = false global.this.events.annihilation = false global.this.events.reset_time = nil create_orbit_group() game.map_settings.pollution.enabled = false game.map_settings.enemy_evolution.enabled = false game.difficulty_settings.technology_price_multiplier = 0.1 game.difficulty_settings.research_queue_setting = "always" _layers.set_collision_mask({"water-tile"}) for _, layer in pairs(preset) do _layers.add_noise_layer(layer.type, layer.name, layer.objects, layer.elevation, layer.resolution) if layer.hook ~= nil then _layers.add_noise_layer_hook(layer.name, layer.hook) end if layer.deps ~= nil then _layers.add_noise_layer_dependency(layer.name, layer.deps) end end _bp.push_blueprint("player_ship", global.this.bp.player_ship) _bp.set_blueprint_hook("player_ship", init_player_ship_bp) _bp.push_blueprint("merchant", global.this.bp.merchant) _bp.set_blueprint_hook("merchant", init_merchant_bp) end local function explode_ship(deps) local bp = deps.modules.bp local layers = deps.modules.layers for _, ent in pairs(bp.reference_get_entities(deps.ship)) do if not ent.valid then goto continue end local explosion = { name = "massive-explosion", position = ent.position } deps.surf.create_entity(explosion) ::continue:: end local bb = bp.reference_get_bounding_box(deps.ship) layers.remove_excluding_bounding_box(bb) bp.destroy_reference(deps.surf, deps.ship) rendering.destroy(deps.id) end local function explode_ship_update(left, deps) local common = deps.modules.common for _, ent in pairs(deps.ship.entities) do if not ent.valid then return false end end rendering.set_text(deps.id, common.get_time(left)) return true end local function do_spawn_point(player) local point = { x = _common.get_axis(player.position, "x"), y = _common.get_axis(player.position, "y") - 2 } local instance = _bp.build(player.surface, "player_ship", point, player) _layers.push_excluding_bounding_box(instance.bb) local left = global.this._config.self_explode local object = { text = _common.get_time(left), surface = player.surface, color = { r = 255, g = 20, b = 20 }, target = { x = point.x - 2, y = point.y - 3, }, scale = 2.0 } local entry = { id = rendering.draw_text(object), ship = instance, modules = { bp = _bp, layers = _layers, common = _common, timers = _timers, func = _bp.destroy_reference, }, surf = player.surface, } local timer = _timers.set_timer(left, explode_ship) _timers.set_timer_on_update(timer, explode_ship_update) _timers.set_timer_dependency(timer, entry) _timers.set_timer_start(timer) end local function get_non_obstructed_position(s, radius) local chunk for i = 1, 32 do chunk = s.get_random_chunk() chunk.x = chunk.x * 32 chunk.y = chunk.y * 32 local search_info = { position = chunk, radius = radius, } local tiles = s.find_tiles_filtered(search_info) for _, tile in pairs(tiles) do if string.find(tile.name, "water") ~= nil or string.find(tile.name, "out") ~= nil then goto continue end end search_info = { position = chunk, radius = radius, force = {"neutral", "enemy"}, invert = true } local ents = s.find_entities_filtered(search_info) if not ents or #ents == 0 then break end ::continue:: end return chunk end local function switchable_perk(caption, status) if status then return string.format("[color=0,80,0]%s[/color]", caption) end return string.format("[color=80,0,0]%s[/color]", caption) end local function draw_normal_gui(player) local button local merchant = global.this.events.merchant if merchant.alive then button = { type = "button", name = "merchant_find", caption = "Merchant", } player.gui.left.add(button) end button = { type = "button", name = "flashlight_toggle", caption = "Toggle flashlight" } player.gui.left.add(button) end local function draw_common_gui(player) local perks = global.this.perks[player.name] local chat_type = "Global chat" if not perks.chat_global then chat_type = "NAP chat" end local button = { type = "button", name = "manual_toggle", caption = "Manual" } player.gui.left.add(button) button = { type = "button", name = "chat_toggle", caption = chat_type, } player.gui.left.add(button) end local function draw_orbit_gui(player) local button = { type = "button", name = "annihilate", caption = "Annihilate" } player.gui.left.add(button) end local function redraw_gui(player) player.gui.left.clear() draw_common_gui(player) if player.spectator == true then draw_orbit_gui(player) else draw_normal_gui(player) end end local function print_merchant_position(player) local position = global.this.events.merchant.position local perks = global.this.perks[player.name] if not perks.minimap then player.print(string.format(">> You were able to spot him %s from your location", _common.get_readable_direction(player.position, position))) else player.print(string.format(">> You received a broadcast with [gps=%d,%d] coordinates", position.x, position.y)) end end local function on_tick_reset() if global.this.events.reset_time == nil then return end if global.this.events.reset_time > game.tick then return end _server.start_scenario('planet_prison') global.this.events.reset_time = nil end local function annihilate(caller) global.this.events.annihilation = true for _, player in pairs(game.connected_players) do if player.name == caller.name then goto continue end local coeff for i = 1, 5 do if i % 2 == 0 then coeff = -1 else coeff = 1 end local query = { name = "atomic-rocket", position = { player.position.x - 100, player.position.y - 100, }, target = { player.position.x + (8 * i * coeff), player.position.y + (8 * i * coeff), }, speed = 0.1, } player.surface.create_entity(query) player.print(">> Annihilation in progress...") end ::continue:: end global.this.events.reset_time = game.tick + (60 * 15) end local function on_gui_click(e) local elem = e.element local p = game.players[e.player_index] local perks = global.this.perks[p.name] if not elem.valid then return end if elem.name == "chat_toggle" then if perks.chat_global then elem.caption = "NAP chat" perks.chat_global = false else elem.caption = "Global chat" perks.chat_global = true end elseif elem.name == "flashlight_toggle" then if perks.flashlight_enable then perks.flashlight_enable = false p.character.disable_flashlight() else perks.flashlight_enable = true p.character.enable_flashlight() end elseif elem.name == "merchant_find" then print_merchant_position(p) elseif elem.name == "manual_toggle" then local children = p.gui.center.children if #children >= 1 then p.gui.center.clear() return end local text_box = { type = "text-box", text = global.this._config.manual } text_box = p.gui.center.add(text_box) text_box.style.minimal_width = 512 text_box.read_only = true text_box.word_wrap = true elseif elem.name == "annihilate" then if global.this.events.annihilation == true then return end elem.destroy() annihilate(p) end end local function get_random_name() while true do local id = _common.rand_range(100, 999) local name = string.format("#%d", id) if global.this.perks[name] == nil then return name end end end local function init_player(p) p.teleport({0, 0}, "arena") local s = p.surface local position = get_non_obstructed_position(s, 10) global.this.perks[p.name] = nil p.teleport(position, "arena") --p.name = get_random_name() --player name is read only p.force = game.create_force(p.name) p.force.set_friend("neutral", true) global.this.perks[p.name] = { flashlight_enable = true, minimap = false, chat_global = true, } local merch = find_force("merchant") if merch then p.force.set_friend(merch, true) merch.set_friend(p.force, true) end p.force.research_queue_enabled = true for _, tech in pairs(p.force.technologies) do for name, status in pairs(global.this._config.technologies) do if tech.name == name then tech.researched = status tech.enabled = status end end end p.minimap_enabled = false redraw_gui(p) do_spawn_point(p) end local function on_player_joined_game(e) local p = game.players[e.player_index] init_player(p) end local function _build_merchant_bp(surf, position) local instance = _bp.build(surf, "merchant", position, nil) _layers.push_excluding_bounding_box(instance.bb) end local function _remove_merchant_bp(surf) local refs = _bp.get_references("merchant") local bb = _bp.reference_get_bounding_box(refs[1]) _layers.remove_excluding_bounding_box(bb) _bp.destroy_references(surf, "merchant") global.this.events.merchant.position = { x = 0, y = 0 } end local function spawn_merchant(s) local merchant = global.this.events.merchant local position = get_non_obstructed_position(s, 10) local merch if not merchant.moving then merch = game.create_force("merchant") else merch = find_force("merchant") end merchant.position = position merchant.alive = true merchant.moving = false merchant.embark_tick = game.tick + 90000 _build_merchant_bp(s, position) s.print(">> Merchant appeared in the area") for _, p in pairs(game.players) do p.force.set_friend(merch, true) merch.set_friend(p.force, true) print_merchant_position(p) redraw_gui(p) end end local function embark_merchant(s) global.this.events.merchant.alive = false global.this.events.merchant.moving = true global.this.events.merchant.spawn_tick = game.tick + 10000 s.print(">> Merchant is moving to new location") _remove_merchant_bp(s) for _, player in pairs(game.players) do redraw_gui(player) end end local function merchant_event(s) local e = global.this.events local m = e.merchant if not m.alive and m.spawn_tick <= game.tick then spawn_merchant(s) end if m.alive and not m.moving and m.embark_tick <= game.tick then embark_merchant(s) end end local function _get_outer_points(surf, x, y, deps) local inner = deps.inner local points = deps.points local point = { x = x, y = y, } if _common.point_in_bounding_box(point, inner) then return end local tile = surf.get_tile(point) if string.find(tile.name, "water") ~= nil or string.find(tile.name, "out") ~= nil then return end table.insert(points, point) end local function _calculate_attack_costs(surf, bb) local query = { area = bb, force = { "enemy", "neutral", "player", }, invert = true, } local objects = surf.find_entities_filtered(query) if next(objects) == nil then log("B") return 0 end local cost = 0 local costs = global.this._config.base_costs for _, obj in pairs(objects) do for name, coeff in pairs(costs) do if obj.name == name then cost = cost + coeff end end end return cost end local function _get_raid_info(surf, bb) local pick = nil local cost = _calculate_attack_costs(surf, bb) for _, entry in pairs(global.this._config.raid_costs) do if entry.cost <= cost then pick = entry else break end end return pick end local function _create_npc_group(claim, surf) local inner = _common.create_bounding_box_by_points(claim) local info = _get_raid_info(surf, inner) if info == nil then return {} end local outer = _common.deepcopy(inner) _common.enlarge_bounding_box(outer, 10) local points = {} local deps = { points = points, inner = inner, } _common.for_bounding_box_extra(surf, outer, _get_outer_points, deps) local agents = {} for i, point in ipairs(points) do if _common.rand_range(1, info.chance) ~= 1 then goto continue end local query = { name = "character", position = point } local agent = surf.create_entity(query) local stash = {} for attr, value in pairs(info.gear[(i % #info.gear) + 1]) do local prop = { name = value } if attr == "ammo" then prop.count = 20 elseif attr == "weap" then prop.count = 1 elseif attr == "armor" then prop.count = 1 end table.insert(stash, prop) end for _, stack in pairs(stash) do agent.insert(stack) end global.this.assign_camouflage(agent, _common) table.insert(agents, agent) ::continue:: end return agents end local function populate_raid_event(surf) local claims, group local status = false local groups = global.this.events.raid_groups for _, p in pairs(game.connected_players) do groups[p.name] = {} claims = _claims.get_claims(p.name) for _, claim in pairs(claims) do if #claim == 0 then goto continue end status = true group = { agents = _create_npc_group(claim, surf), objects = claim } table.insert(groups[p.name], group) ::continue:: end end return status end local function raid_event(surf) local raid_groups = global.this.events.raid_groups if global.this.events.raid_init then if surf.daytime > 0.01 and surf.daytime <= 0.1 then for name, groups in pairs(raid_groups) do for i = #groups, 1, -1 do local group = groups[i] local agents = group.agents for j = #agents, 1, -1 do local agent = agents[j] if agent.valid then agent.destroy() end table.remove(agents, j) end if #agents == 0 then table.remove(group, i) end end if #groups == 0 then raid_groups[name] = nil end end global.this.events.raid_init = false end else if surf.daytime < 0.4 or surf.daytime > 0.6 then return end if populate_raid_event(surf) then global.this.events.raid_init = true end end if game.tick % 4 ~= 0 then return end for name, groups in pairs(raid_groups) do local exists = false for _, p in pairs(game.connected_players) do if p.name == name then exists = true break end end if not exists then raid_groups[name] = nil goto continue end for _, group in pairs(groups) do _ai.do_job(surf, _ai.command.attack_objects, group) end ::continue:: end end local function cause_event(s) merchant_event(s) raid_event(s) end local function kill_player(p) p.character.die() end local function on_tick() local s = global.this.surface if not s then log("on_tick: surface empty!") return end local surf = global.this.surface if game.tick % 4 == 0 then _ai.do_job(surf, _ai.command.seek_and_destroy_player) end _layers.do_job(surf) cause_event(s) if (game.tick + 1) % 100 == 0 then _afk.on_inactive_players(90, kill_player) end if (game.tick + 1) % 60 == 0 then _timers.do_job() end end local function make_ore_patch(e) if _common.rand_range(1, 30) ~= 1 then return end local surf = e.surface local point = e.area.left_top _map.draw_entity_circle(point, "stone", surf, 6, true, 1000000) _map.draw_entity_circle(point, "coal", surf, 12, true, 1000000) _map.draw_entity_circle(point, "copper-ore", surf, 18, true, 1000000) _map.draw_entity_circle(point, "iron-ore", surf, 24, true, 1000000) _map.draw_noise_tile_circle(point, "water", surf, 4) end local function on_chunk_generated(e) if e.surface.name ~= "arena" then return end make_ore_patch(e) _layers.push_chunk(e.position) end local function mined_wreckage(e) if e.entity.name ~= "mineable-wreckage" then return end local candidates = {} local chance = _common.rand_range(0, 1000) for name, attrs in pairs(global.this._config.wreck_loot) do local prob = attrs.rare * 100 if prob < chance then local cand = { name = name, count = _common.rand_range(attrs.count[1], attrs.count[2]), } table.insert(candidates, cand) end end local count = #candidates if count == 0 then return end local cand = candidates[_common.rand_range(1, count)] e.buffer.insert(cand) end local function on_player_mined_entity(e) local ent = e.entity if not ent.valid then return end mined_wreckage(e) _claims.on_player_mined_entity(ent) end local function on_player_died(e) local index = e.player_index if not index then return -- banned/kicked somewhere else end local p = game.players[index] _claims.on_player_died(p) game.merge_forces(p.name, "neutral") end local function on_player_respawned(e) local p = game.players[e.player_index] init_player(p) end local function on_player_dropped_item(e) if not global.this.last_friend then global.this.last_friend = {} end local p = game.players[e.player_index] local ent = e.entity if ent.stack.name == "raw-fish" then local ent_list = p.surface.find_entities_filtered({ name = "character", position = ent.position, radius = 2, }) if not ent_list then return end local peer = nil for _, char in pairs(ent_list) do if char.player and char.player.name ~= p.name then peer = char.player break end end if peer == nil then return end if p.force.get_cease_fire(peer.name) then p.print(string.format("You're in the NAP with %s already", peer.name)) return end if global.this.last_friend[peer.name] == p.name then p.force.set_cease_fire(peer.name, true) peer.force.set_cease_fire(p.name, true) p.print(string.format("The NAP was formed with %s", peer.name)) peer.print(string.format("The NAP was formed with %s", p.name)) global.this.last_friend[p.name] = "" global.this.last_friend[peer.name] = "" return end global.this.last_friend[p.name] = peer.name p.print(string.format("You want to form the NAP with %s", peer.name)) peer.print(string.format("The %s wants to form NAP with you", p.name)) elseif ent.stack.name == "coal" then local ent_list = p.surface.find_entities_filtered({ name = "character", position = ent.position, radius = 2, }) if not ent_list then return end local peer = nil for _, char in pairs(ent_list) do if char.player and char.player.name ~= p.name then peer = char.player break end end if peer == nil then return end if not p.force.get_cease_fire(peer.name) then p.print(string.format("You don't have the NAP with %s", p.name)) return end p.force.set_cease_fire(peer.name, false) peer.force.set_cease_fire(p.name, false) global.this.last_friend[p.name] = "" global.this.last_friend[peer.name] = "" p.print(string.format("You're no longer in the NAP with %s", peer.name)) peer.print(string.format("You're no longer in the NAP with %s", p.name)) end end local function on_chunk_charted(e) local f_perks = global.this.perks[e.force.name] if not f_perks then return end if not f_perks.minimap then e.force.clear_chart() end end local function on_entity_damaged(e) local ent = e.entity if ent.force.name == "merchant" then if not ent.force.get_friend(e.force) then return end ent.force.set_friend(e.force, false) e.force.set_friend(ent.force, false) end if ent.name == "character" then local hp = 1.0 - ent.get_health_ratio() local particles = 45 * hp local coeff = _common.rand_range(-20, 20) / 100.0 for i = 1, particles do local blood = { name = "blood-particle", position = { x = ent.position.x, y = ent.position.y, }, movement = { (_common.rand_range(-20, 20) / 100.0) + coeff, (_common.rand_range(-20, 20) / 100.0) + coeff, }, frame_speed = 0.01, vertical_speed = 0.02, height = 0.01, } ent.surface.create_particle(blood) end end end local function merchant_death(e) local ent = e.entity if ent.force.name ~= "merchant" then return false end if ent.name ~= "character" and ent.name ~= "market" then return false end local s = ent.surface local explosion = { name = "massive-explosion", position = ent.position } s.create_entity(explosion) _remove_merchant_bp(s) global.this.events.merchant.alive = false global.this.events.merchant.moving = false global.this.events.merchant.spawn_tick = game.tick + 1000 game.merge_forces("merchant", "neutral") s.print(">> Merchant died") for _, player in pairs(game.players) do redraw_gui(player) end return true end local function hostile_death(e) local ent = e.entity local loot = e.loot if ent.name ~= "character" then return false end if ent.player then loot.insert({name = "coin", count = 70}) else loot.insert({name = "coin", count = 10}) end return true end local function character_death(e) local ent = e.entity if ent.name ~= "character" then return false end local explosion = { name = "blood-explosion-big", position = ent.position, } ent.surface.create_entity(explosion) end local function on_entity_died(e) if not e.entity.valid then return end if merchant_death(e) then return end hostile_death(e) character_death(e) _claims.on_entity_died(e.entity) end local function merchant_exploit_check(ent) if ent.type ~= "electric-pole" then return end local refs = _bp.get_references("merchant") if not refs or #refs <= 0 then return end local bp_ent = _bp.reference_get_entities(refs[1])[1] local surf = bp_ent.surface local query = { type = "electric-pole", position = bp_ent.position, radius = 18 } local ents = surf.find_entities_filtered(query) for _, s_ent in pairs(ents) do if s_ent.valid and s_ent.force.name ~= "merchant" then s_ent.die() end end end local function on_built_entity(e) local ent = e.created_entity if not ent or not ent.valid then return end _claims.on_built_entity(ent) merchant_exploit_check(ent) end local function on_market_item_purchased(e) local p = game.players[e.player_index] local m = e.market local o = m.get_market_items()[e.offer_index].offer local perks = global.this.perks[p.name] if o.effect_description == "Construct a GPS receiver" then perks.minimap = true p.minimap_enabled = true end end local function stringify_color(color) local r, g, b = color.r, color.g, color.b if r <= 1 then r = math.floor(r * 255) end if g <= 1 then g = math.floor(g * 255) end if b <= 1 then b = math.floor(b * 255) end return string.format("%d,%d,%d", r, g, b) end local function create_console_message(p, message) local prefix_fmt = "[color=%s]%s:[/color]" local msg_fmt = "[color=%s]%s[/color]" local color = stringify_color(p.chat_color) local prefix = string.format(prefix_fmt, color, p.name) local p_msg = string.format(msg_fmt, color, message) if global.this.perks[p.name].chat_global then msg_fmt = "[color=red]global:[/color] %s %s" else msg_fmt = "[color=green]nap:[/color] %s %s" end return string.format(msg_fmt, prefix, p_msg) end local function filter_out_gps(message) local msg = string.gsub(message, '%[gps=%-?%d+%,?%s*%-?%d+%]', '[gps]') return msg end local function on_console_chat(e) local pid = e.player_index if not pid then return end local p = game.players[pid] local msg = create_console_message(p, e.message) if global.this.perks[p.name].chat_global then for _, peer in pairs(game.players) do if peer.name ~= p.name then local perks = global.this.perks[peer.name] if perks.minimap then peer.print(msg) else peer.print(filter_out_gps(msg)) end end end else for _, f in pairs(game.forces) do if p.force.get_cease_fire(f) then local peer = f.players[1] if peer.name ~= p.name then local perks = global.this.perks[peer.name] if perks.minimap then peer.print(msg) else peer.print(filter_out_gps(msg)) end end end end end end local function on_research_finished(e) local r = e.research if not r.valid then return end local reward = { name = "coin", count = math.ceil(r.research_unit_count * 3) } local f = r.force for _, player in pairs(f.players) do if player.can_insert(reward) then player.insert(reward) end end end local function move_to_orbit(player) local char = player.character player.character = nil char.destroy() game.merge_forces(player.name, "neutral") player.spectator = true redraw_gui(player) local orbit_perms = game.permissions.get_group("orbit") orbit_perms.add_player(player) end local function on_rocket_launched(e) local surf = global.this.surface local pid = e.player_index surf.print(">> The rocket was launched") if pid == nil then surf.print(">> Nobody escaped by it") else local player = game.players[pid] surf.print(string.format(">> The %s was able to escape", player.name)) move_to_orbit(player) end end _evt.on_init(init_game) _evt.add(defines.events.on_built_entity, on_built_entity) _evt.add(defines.events.on_robot_built_entity, on_built_entity) _evt.add(defines.events.on_research_finished, on_research_finished) _evt.add(defines.events.on_player_joined_game, on_player_joined_game) _evt.add(defines.events.on_chunk_generated, on_chunk_generated) _evt.add(defines.events.on_player_mined_entity, on_player_mined_entity) _evt.add(defines.events.on_player_died, on_player_died) _evt.add(defines.events.on_player_kicked, on_player_died) _evt.add(defines.events.on_player_banned, on_player_died) _evt.add(defines.events.on_player_respawned, on_player_respawned) _evt.add(defines.events.on_player_dropped_item, on_player_dropped_item) _evt.add(defines.events.on_pre_player_left_game, on_player_died) _evt.add(defines.events.on_entity_damaged, on_entity_damaged) _evt.add(defines.events.on_entity_died, on_entity_died) _evt.add(defines.events.on_market_item_purchased, on_market_item_purchased) _evt.add(defines.events.on_chunk_charted, on_chunk_charted) _evt.add(defines.events.on_console_chat, on_console_chat) _evt.add(defines.events.on_gui_click, on_gui_click) _evt.add(defines.events.on_tick, on_tick) _evt.add(defines.events.on_tick, on_tick_reset) _evt.add(defines.events.on_rocket_launched, on_rocket_launched) _global.register_init({}, function(tbl) tbl.this = global.this end, function(tbl) global.this = tbl.this end)