diff --git a/control.lua b/control.lua index 34ef391c..fb72d34f 100644 --- a/control.lua +++ b/control.lua @@ -104,6 +104,9 @@ require 'modules.autostash' --![[Comfylatron has seized the Fish Train and turned it into a time machine]]-- --require 'maps.chronosphere.main' +--![[Launch rockets in increasingly harder getting worlds.]]-- +--require 'maps.journey.main' + --![[East VS West Survival PVP, where you breed biters with science flasks]]-- --require 'maps.biter_hatchery.main' diff --git a/maps/journey/constants.lua b/maps/journey/constants.lua new file mode 100644 index 00000000..8533b9d6 --- /dev/null +++ b/maps/journey/constants.lua @@ -0,0 +1,148 @@ +--luacheck: ignore +local Public = {} + +Public.mothership_teleporter_position = {x = 0, y = 12} + +Public.mothership_radius = 28 + +Public.particle_spawn_vectors = {} +for x = Public.mothership_radius * -1 - 32, Public.mothership_radius + 32, 1 do + for y = Public.mothership_radius * -1 - 32, Public.mothership_radius + 32, 1 do + local position = {x = x, y = y} + local distance = math.sqrt(position.x ^ 2 + position.y ^ 2) + if distance > Public.mothership_radius then + table.insert(Public.particle_spawn_vectors, {position.x, position.y}) + end + end +end +Public.size_of_particle_spawn_vectors = #Public.particle_spawn_vectors + +Public.world_selector_width = 6 +Public.world_selector_height = 8 + +local area = { + left_top = {x = -3, y = math.floor(Public.mothership_radius * 0.5) * -1}, + right_bottom = {x = 3, y = math.floor(Public.mothership_radius * 0.5) * -1 + Public.world_selector_height}, +} + +Public.world_selector_areas = { + [1] = { + left_top = {x = area.left_top.x - 12, y = area.left_top.y}, + right_bottom = {x = area.left_top.x - 6, y = area.right_bottom.y}, + }, + [2] = area, + [3] = { + left_top = {x = area.right_bottom.x + 6, y = area.left_top.y}, + right_bottom = {x = area.right_bottom.x + 12, y = area.right_bottom.y}, + }, +} + +Public.world_selector_colors = { + [1] = {r = 200, g = 200, b = 0, a = 255}, + [2] = {r = 150, g = 150, b = 255, a = 255}, + [3] = {r = 200, g = 100, b = 100, a = 255}, +} + +Public.mothership_messages = { + waiting = { + "Return to me, so we can continue the journey!", + "Don't leave me waiting for so long. Let's continue our journey.", + "Please return to me.", + "Board me, so we can continue this adventure!", + }, +} + +Public.mothership_gen_settings = { + ["water"] = 0, + ["starting_area"] = 1, + ["cliff_settings"] = {cliff_elevation_interval = 0, cliff_elevation_0 = 0}, + ["default_enable_all_autoplace_controls"] = false, + ["autoplace_settings"] = { + ["entity"] = {treat_missing_as_default = false}, + ["tile"] = {treat_missing_as_default = false}, + ["decorative"] = {treat_missing_as_default = false}, + }, + autoplace_controls = { + ["coal"] = {frequency = 0, size = 0, richness = 0}, + ["stone"] = {frequency = 0, size = 0, richness = 0}, + ["copper-ore"] = {frequency = 0, size = 0, richness = 0}, + ["iron-ore"] = {frequency = 0, size = 0, richness = 0}, + ["uranium-ore"] = {frequency = 0, size = 0, richness = 0}, + ["crude-oil"] = {frequency = 0, size = 0, richness = 0}, + ["trees"] = {frequency = 0, size = 0, richness = 0}, + ["enemy-base"] = {frequency = 0, size = 0, richness = 0} + }, +} + +Public.modifiers = { + ["cliff_settings"] = {20, 40, "Cliffs"}, + ["enemy-base"] = {15, 25, "Nests"}, + ["starting_area"] = {-25, -10, "Starting Area"}, + ["water"] = {-30, -15, "Water"}, + ["coal"] = {-20, -10, "Coal"}, + ["stone"] = {-20, -10, "Stone"}, + ["copper-ore"] = {-20, -10, "Copper Ore"}, + ["iron-ore"] = {-20, -10, "Iron Ore"}, + ["uranium-ore"] = {-20, -10, "Uranium Ore"}, + ["crude-oil"] = {-20, -10, "Oil"}, + ["trees"] = {-35, -15, "Trees"}, + ["time_factor"] = {20, 40, "Evolution Time Factor"}, + ["destroy_factor"] = {20, 40, "Evolution Destroy Factor"}, + ["pollution_factor"] = {20, 40, "Evolution Pollution Factor"}, + ["expansion_cooldown"] = {-30, -15, "Nest Expansion Cooldown"}, + ["ageing"] = {-25, -10, "Terrain Pollution Consumption"}, + ["enemy_attack_pollution_consumption_modifier"] = {-25, -10, "Nest Pollution Consumption"}, + ["technology_price_multiplier"] = {5, 10, "Technology Price"}, +} + +Public.starter_goods_pool = { + {"accumulator", 8, 16}, + {"big-electric-pole", 8, 16}, + {"burner-inserter", 64, 128}, + {"burner-mining-drill", 8, 16}, + {"car", 2, 4}, + {"copper-cable", 128, 256}, + {"copper-plate", 64, 128}, + {"electric-furnace", 4, 8}, + {"electric-mining-drill", 4, 8}, + {"firearm-magazine", 64, 128}, + {"grenade", 8, 16}, + {"gun-turret", 4, 8}, + {"inserter", 32, 64}, + {"iron-gear-wheel", 64, 128}, + {"iron-plate", 64, 128}, + {"lab", 2, 4}, + {"long-handed-inserter", 32, 64}, + {"medium-electric-pole", 16, 32}, + {"pipe", 128, 256}, + {"radar", 4, 8}, + {"small-lamp", 64, 128}, + {"solar-panel", 8, 16}, + {"solid-fuel", 256, 512}, + {"stack-inserter", 16, 32}, + {"stack-filter-inserter", 16, 32}, + {"steam-turbine", 4, 8}, + {"steel-chest", 16, 32}, + {"steel-furnace", 8, 16}, + {"steel-plate", 32, 64}, + {"stone-wall", 128, 256}, + {"substation", 4, 8}, +} + +Public.build_type_whitelist = { + ["arithmetic-combinator"] = true, + ["constant-combinator"] = true, + ["decider-combinator"] = true, + ["electric-energy-interface"] = true, + ["electric-pole"] = true, + ["gate"] = true, + ["heat-pipe"] = true, + ["lamp"] = true, + ["pipe"] = true, + ["pipe-to-ground"] = true, + ["programmable-speaker"] = true, + ["transport-belt"] = true, + ["wall"] = true, +} + +return Public \ No newline at end of file diff --git a/maps/journey/functions.lua b/maps/journey/functions.lua new file mode 100644 index 00000000..f9e7a3e7 --- /dev/null +++ b/maps/journey/functions.lua @@ -0,0 +1,752 @@ +--luacheck: ignore +local Public = {} +local Constants = require 'maps.journey.constants' + +local function clear_world_selectors(journey) + for k, world_selector in pairs(journey.world_selectors) do + for _, ID in pairs(world_selector.texts) do + rendering.destroy(ID) + end + journey.world_selectors[k].texts = {} + journey.world_selectors[k].activation_level = 0 + end +end + +local function drop_player_items(player) + local character = player.character + if not character then return end + if not character.valid then return end + + player.clear_cursor() + + for i = 1, player.crafting_queue_size, 1 do + if player.crafting_queue_size > 0 then + player.cancel_crafting{index = 1, count = 99999999} + end + end + + local surface = player.surface + local spill_blockage = surface.create_entity{name = "stone-furnace", position = player.position} + + for _, define in pairs({defines.inventory.character_main, defines.inventory.character_guns, defines.inventory.character_ammo, defines.inventory.character_armor, defines.inventory.character_vehicle, defines.inventory.character_trash}) do + local inventory = character.get_inventory(define) + if inventory and inventory.valid then + for i = 1, #inventory, 1 do + local slot = inventory[i] + if slot.valid and slot.valid_for_read then + surface.spill_item_stack(player.position, slot, true, nil, false) + end + end + inventory.clear() + end + end + + spill_blockage.destroy() +end + +function Public.clear_player(player) + local character = player.character + if not character then return end + if not character.valid then return end + player.character.destroy() + player.set_controller({type = defines.controllers.god}) + player.create_character() + player.clear_items_inside() +end + +function Public.mothership_message_queue(journey) + local text = journey.mothership_messages[1] + if not text then return end + if text ~= "" then + text = "[font=default-game][color=200,200,200]" .. text .. "[/color][/font]" + text = "[font=heading-1][color=255,155,155] [/color][/font]" .. text + game.print(text) + end + table.remove(journey.mothership_messages, 1) +end + +function Public.deny_building(event) + local entity = event.created_entity + if not entity.valid then return end + if entity.surface.name ~= "mothership" then return end + if Constants.build_type_whitelist[entity.type] then return end + entity.die() +end + +function Public.draw_gui(journey) + local surface = game.surfaces.nauvis + local mgs = surface.map_gen_settings + local caption = "World - " .. journey.world_number + local tooltip = "" + for k, autoplace in pairs(mgs.autoplace_controls) do + tooltip = tooltip .. Constants.modifiers[k][3] .. " - " .. math.floor(autoplace.frequency * 100) .. "%\n" + end + tooltip = tooltip .. "Cliff Interval - " .. math.round(mgs.cliff_settings.cliff_elevation_interval * 2.5, 2) .. "%\n" + tooltip = tooltip .. "Water - " .. math.floor(mgs.water * 100) .. "%\n" + tooltip = tooltip .. "Starting area - " .. math.floor(mgs.starting_area * 100) .. "%\n" + tooltip = tooltip .. "Evolution Time Factor - " .. math.round(game.map_settings.enemy_evolution.time_factor * 25000000, 1) .. "%\n" + tooltip = tooltip .. "Evolution Destroy Factor - " .. math.round(game.map_settings.enemy_evolution.destroy_factor * 50000, 1) .. "%\n" + tooltip = tooltip .. "Evolution Pollution Factor - " .. math.round(game.map_settings.enemy_evolution.pollution_factor * 111100000, 1) .. "%\n" + tooltip = tooltip .. "Nest Expansion Cooldown - " .. math.round(game.map_settings.enemy_expansion.min_expansion_cooldown / 144, 1) .. "%\n" + tooltip = tooltip .. Constants.modifiers["enemy_attack_pollution_consumption_modifier"][3] .. " - " .. math.round(game.map_settings.pollution.enemy_attack_pollution_consumption_modifier * 100, 1) .. "%\n" + tooltip = tooltip .. Constants.modifiers["ageing"][3] .. " - " .. math.round(game.map_settings.pollution.ageing * 100, 1) .. "%\n" + tooltip = tooltip .. Constants.modifiers["technology_price_multiplier"][3] .. " - " .. math.round(game.difficulty_settings.technology_price_multiplier * 200, 1) .. "%" + + tooltip = tooltip .. "\n\nCapsules:\n" + local c = 0 + for k, v in pairs(journey.bonus_goods) do + tooltip = tooltip .. v .. "x " .. k .. " " + c = c + 1 + if c % 2 == 0 then tooltip = tooltip .. "\n" end + end + + for _, player in pairs(game.connected_players) do + if not player.gui.top.journey_button then + local button = player.gui.top.add({type = "sprite-button", name = "journey_button", caption = ""}) + button.style.font = "heading-1" + button.style.font_color = {222, 222, 222} + button.style.minimal_height = 38 + button.style.minimal_width = 100 + button.style.padding = -2 + end + local gui = player.gui.top.journey_button + gui.caption = caption + gui.tooltip = tooltip + end +end + +local function is_mothership(position) + if math.abs(position.x) > Constants.mothership_radius then return false end + if math.abs(position.y) > Constants.mothership_radius then return false end + local p = {x = position.x, y = position.y} + if p.x > 0 then p.x = p.x + 1 end + if p.y > 0 then p.y = p.y + 1 end + local d = math.sqrt(p.x ^ 2 + p.y ^ 2) + if d < Constants.mothership_radius then + return true + end +end + +function Public.on_mothership_chunk_generated(event) + local left_top = event.area.left_top + local surface = event.surface + local seed = surface.map_gen_settings.seed + local tiles = {} + for x = 0, 31, 1 do + for y = 0, 31, 1 do + local position = {x = left_top.x + x, y = left_top.y + y} + if is_mothership(position) then + table.insert(tiles, {name = "black-refined-concrete", position = position}) + else + table.insert(tiles, {name = "out-of-map", position = position}) + end + end + end + surface.set_tiles(tiles, true) +end + +function Public.hard_reset(journey) + if game.surfaces.mothership and game.surfaces.mothership.valid then + game.delete_surface(game.surfaces.mothership) + end + + game.map_settings.enemy_expansion.enabled = true + game.map_settings.enemy_expansion.max_expansion_distance = 20 + game.map_settings.enemy_expansion.settler_group_min_size = 5 + game.map_settings.enemy_expansion.settler_group_max_size = 50 + game.map_settings.enemy_expansion.min_expansion_cooldown = 14400 + game.map_settings.enemy_expansion.max_expansion_cooldown = 216000 + + game.map_settings.pollution.enabled = true + game.map_settings.pollution.ageing = 1 + game.map_settings.pollution.enemy_attack_pollution_consumption_modifier = 1 + + game.difficulty_settings.technology_price_multiplier = 0.5 + + game.map_settings.enemy_evolution.time_factor = 0.000004 + game.map_settings.enemy_evolution.destroy_factor = 0.002 + game.map_settings.enemy_evolution.pollution_factor = 0.0000009 + + local surface = game.surfaces[1] + local mgs = surface.map_gen_settings + mgs.water = 1 + mgs.starting_area = 1 + mgs.cliff_settings = {cliff_elevation_interval = 40, cliff_elevation_0 = 10} + mgs.autoplace_controls = { + ["coal"] = {frequency = 1, size = 1, richness = 1}, + ["stone"] = {frequency = 1, size = 1, richness = 1}, + ["copper-ore"] = {frequency = 1, size = 1, richness = 1}, + ["iron-ore"] = {frequency = 1, size = 1, richness = 1}, + ["uranium-ore"] = {frequency = 1, size = 1, richness = 1}, + ["crude-oil"] = {frequency = 1, size = 1, richness = 1}, + ["trees"] = {frequency = 1, size = 1, richness = 1}, + ["enemy-base"] = {frequency = 1, size = 1, richness = 1}, + } + surface.map_gen_settings = mgs + surface.clear(true) + + if journey.world_selectors and journey.world_selectors[1].border then + for k, world_selector in pairs(journey.world_selectors) do + for _, ID in pairs(world_selector.rectangles) do + rendering.destroy(ID) + end + rendering.destroy(world_selector.border) + end + end + + journey.world_selectors = {} + for i = 1, 3, 1 do journey.world_selectors[i] = {activation_level = 0, texts = {}} end + journey.mothership_speed = 0.5 + journey.characters_in_mothership = 0 + journey.mothership_messages = {} + journey.mothership_cargo = {} + journey.bonus_goods = {} + + journey.world_number = 0 + journey.game_state = "create_mothership" +end + +function Public.create_mothership(journey) + local surface = game.create_surface("mothership", Constants.mothership_gen_settings) + surface.request_to_generate_chunks({x = 0, y = 0}, 6) + surface.force_generate_chunk_requests() + surface.freeze_daytime = true + journey.game_state = "draw_mothership" +end + +function Public.draw_mothership(journey) + local surface = game.surfaces.mothership + + local positions = {} + for x = Constants.mothership_radius * -1, Constants.mothership_radius, 1 do + for y = Constants.mothership_radius * -1, Constants.mothership_radius, 1 do + local position = {x = x, y = y} + if is_mothership(position) then table.insert(positions, position) end + end + end + + table.shuffle_table(positions) + + for _, position in pairs(positions) do + if surface.count_tiles_filtered({area = {{position.x - 1, position.y - 1}, {position.x + 2, position.y + 2}}, name = "out-of-map"}) > 0 then + local e = surface.create_entity({name = "stone-wall", position = position, force = "player"}) + e.destructible = false + e.minable = false + end + if surface.count_tiles_filtered({area = {{position.x - 1, position.y - 1}, {position.x + 2, position.y + 2}}, name = "lab-dark-1"}) < 4 then + surface.set_tiles({{name = "lab-dark-1", position = position}}, true) + end + end + + for _, tile in pairs(surface.find_tiles_filtered({area = {{Constants.mothership_teleporter_position.x - 2, Constants.mothership_teleporter_position.y - 2}, {Constants.mothership_teleporter_position.x + 2, Constants.mothership_teleporter_position.y + 2}}})) do + surface.set_tiles({{name = "lab-dark-1", position = tile.position}}, true) + end + + for k, area in pairs(Constants.world_selector_areas) do + journey.world_selectors[k].rectangles = {} + + local center = {x = area.left_top.x + Constants.world_selector_width * 0.5, y = area.left_top.y + Constants.world_selector_height * 0.5} + + local position = area.left_top + local rectangle = rendering.draw_rectangle { + width = 1, + filled=true, + surface = surface, + left_top = position, + right_bottom = {position.x + Constants.world_selector_width, position.y + Constants.world_selector_height}, + color = Constants.world_selector_colors[k], + draw_on_ground = true, + only_in_alt_mode = false + } + table.insert(journey.world_selectors[k].rectangles, rectangle) + + journey.world_selectors[k].border = rendering.draw_rectangle { + width = 8, + filled=false, + surface = surface, + left_top = position, + right_bottom = {position.x + Constants.world_selector_width, position.y + Constants.world_selector_height}, + color = {r = 100, g = 100, b = 100, a = 255}, + draw_on_ground = true, + only_in_alt_mode = false + } + end + + for k, item_name in pairs({"arithmetic-combinator", "constant-combinator", "decider-combinator", "programmable-speaker", "red-wire", "green-wire", "small-lamp", "substation", "pipe", "gate", "stone-wall", "transport-belt"}) do + local e = surface.create_entity({name = "steel-chest", position = {-7 + k, Constants.mothership_radius - 3}, force = "player"}) + local stack_size = game.item_prototypes[item_name].stack_size + e.insert({name = item_name, count = stack_size * 10}) + e.minable = false + e.destructible = false + end + + for m = -1, 1, 2 do + local e = surface.create_entity({name = "electric-energy-interface", position = {8 * m, Constants.mothership_radius - 4}, force = "player"}) + e.minable = false + e.destructible = false + local e = surface.create_entity({name = "substation", position = {10 * m, Constants.mothership_radius - 5}, force = "player"}) + e.minable = false + e.destructible = false + end + + for _ = 1, 5, 1 do + local e = surface.create_entity({name = "compilatron", position = Constants.mothership_teleporter_position, force = "player"}) + e.destructible = false + end + + Public.draw_gui(journey) + + journey.game_state = "set_world_selectors" +end + +function Public.teleport_players_to_mothership(journey) + local surface = game.surfaces.mothership + for _, player in pairs(game.connected_players) do + if player.surface.name ~= "mothership" then + Public.clear_player(player) + player.teleport(surface.find_non_colliding_position("character", {0,0}, 32, 0.5), surface) + journey.characters_in_mothership = journey.characters_in_mothership + 1 + table.insert(journey.mothership_messages, "Welcome home " .. player.name .. "!") + return + end + end +end + +local function get_activation_level(surface, area) + local player_count_in_area = surface.count_entities_filtered({area = area, name = "character"}) + local player_count_for_max_activation = #game.connected_players * 0.66 + local level = player_count_in_area / player_count_for_max_activation + level = math.round(level, 2) + return level +end + +local function animate_selectors(journey) + for k, world_selector in pairs(journey.world_selectors) do + local activation_level = journey.world_selectors[k].activation_level + if activation_level < 0.2 then activation_level = 0.2 end + if activation_level > 1 then activation_level = 1 end + for _, rectangle in pairs(world_selector.rectangles) do + local color = Constants.world_selector_colors[k] + rendering.set_color(rectangle, {r = color.r * activation_level, g = color.g * activation_level, b = color.b * activation_level, a = 255}) + end + end +end + +local function draw_background(journey, surface) + if journey.characters_in_mothership == 0 then return end + local speed = journey.mothership_speed + for c = 1, 16 * speed, 1 do + local position = Constants.particle_spawn_vectors[math.random(1, Constants.size_of_particle_spawn_vectors)] + surface.create_entity({name = "shotgun-pellet", position = position, target = {position[1], position[2] + Constants.mothership_radius * 2}, speed = speed}) + end + for c = 1, 16 * speed, 1 do + local position = Constants.particle_spawn_vectors[math.random(1, Constants.size_of_particle_spawn_vectors)] + surface.create_entity({name = "piercing-shotgun-pellet", position = position, target = {position[1], position[2] + Constants.mothership_radius * 2}, speed = speed}) + end + for c = 1, 2 * speed, 1 do + local position = Constants.particle_spawn_vectors[math.random(1, Constants.size_of_particle_spawn_vectors)] + surface.create_entity({name = "cannon-projectile", position = position, target = {position[1], position[2] + Constants.mothership_radius * 2}, speed = speed}) + end + for c = 1, 1 * speed, 1 do + local position = Constants.particle_spawn_vectors[math.random(1, Constants.size_of_particle_spawn_vectors)] + surface.create_entity({name = "uranium-cannon-projectile", position = position, target = {position[1], position[2] + Constants.mothership_radius * 2}, speed = speed}) + end + if math.random(1, 32) == 1 then + local position = Constants.particle_spawn_vectors[math.random(1, Constants.size_of_particle_spawn_vectors)] + surface.create_entity({name = "explosive-uranium-cannon-projectile", position = position, target = {position[1], position[2] + Constants.mothership_radius * 3}, speed = speed}) + end +end + +function Public.set_world_selectors(journey) + local surface = game.surfaces.mothership + local modifier_names = {} + for k, _ in pairs(Constants.modifiers) do + table.insert(modifier_names, k) + end + + local bonus_goods_keys = {} + for i = 1, #Constants.starter_goods_pool, 1 do + table.insert(bonus_goods_keys, i) + end + + for k, world_selector in pairs(journey.world_selectors) do + table.shuffle_table(bonus_goods_keys) + table.shuffle_table(modifier_names) + world_selector.modifiers = {} + world_selector.bonus_goods = {} + local position = Constants.world_selector_areas[k].left_top + local texts = world_selector.texts + local modifiers = world_selector.modifiers + local bonus_goods = world_selector.bonus_goods + local y_modifier = - 8.5 + + for i = 1, 6, 1 do + local modifier = modifier_names[i] + modifiers[i] = {modifier, math.random(Constants.modifiers[modifier][1], Constants.modifiers[modifier][2])} + end + for i = 7, 8, 1 do + local modifier = modifier_names[i] + modifiers[i] = {modifier, -1 * math.random(Constants.modifiers[modifier][1], Constants.modifiers[modifier][2])} + end + + for k2, modifier in pairs(modifiers) do + y_modifier = y_modifier + 0.8 + local text = "" + if modifier[2] > 0 then text = text .. "+" end + text = text .. modifier[2] .. "% " + text = text .. Constants.modifiers[modifier[1]][3] + + local color + if k2 < 7 then + color = {200, 0, 0, 255} + else + color = {0, 200, 0, 255} + end + + texts[k2] = rendering.draw_text{ + text = text, + surface = surface, + target = {position.x + Constants.world_selector_width * 0.5, position.y + y_modifier}, + color = color, + scale = 1.25, + font = "default-large", + alignment = "center", + scale_with_zoom = false + } + end + + for i = 1, 3, 1 do + local key = bonus_goods_keys[i] + local bonus_good = Constants.starter_goods_pool[key] + bonus_goods[i] = {bonus_good[1], math.random(bonus_good[2], bonus_good[3])} + end + + y_modifier = y_modifier + 1 + local x_modifier = -0.5 + + for k2, good in pairs(world_selector.bonus_goods) do + local render_id = rendering.draw_text{ + text = "+" .. good[2], + surface = surface, + target = {position.x + x_modifier, position.y + y_modifier}, + color = {200, 200, 0, 255}, + scale = 1.25, + font = "default-large", + alignment = "center", + scale_with_zoom = false + } + table.insert(texts, render_id) + + x_modifier = x_modifier + 0.95 + if good[2] >= 10 then x_modifier = x_modifier + 0.18 end + if good[2] >= 100 then x_modifier = x_modifier + 0.18 end + + local render_id = rendering.draw_sprite{ + sprite = "item/" .. good[1], + surface = surface, + target = {position.x + x_modifier, position.y + 0.5 + y_modifier}, + } + table.insert(texts, render_id) + + x_modifier = x_modifier + 1.70 + end + end + journey.game_state = "mothership_world_selection" +end + +function Public.mothership_world_selection(journey) + if journey.mothership_teleporter and journey.mothership_teleporter.valid then + journey.mothership_teleporter.destroy() + end + + local surface = game.surfaces.mothership + + local daytime = surface.daytime + daytime = daytime - 0.025 + if daytime < 0 then daytime = 0 end + surface.daytime = daytime + + Public.teleport_players_to_mothership(journey) + + journey.mothership_teleporter_online = false + journey.selected_world = false + for i = 1, 3, 1 do + local activation_level = get_activation_level(surface, Constants.world_selector_areas[i]) + journey.world_selectors[i].activation_level = activation_level + if activation_level > 1 then + journey.selected_world = i + end + end + + if journey.selected_world then + if not journey.mothership_advancing_to_world then + table.insert(journey.mothership_messages, "Advancing to selected world.") + journey.mothership_advancing_to_world = game.tick + math.random(60 * 45, 60 * 75) + else + local seconds_left = math.floor((journey.mothership_advancing_to_world - game.tick) / 60) + if seconds_left <= 0 then + journey.mothership_advancing_to_world = false + table.insert(journey.mothership_messages, "Arriving at targeted destination!") + journey.game_state = "mothership_arrives_at_world" + return + end + if seconds_left % 15 == 0 then table.insert(journey.mothership_messages, "Estimated arrival in " .. seconds_left .. " seconds.") end + end + + journey.mothership_speed = journey.mothership_speed + 0.1 + if journey.mothership_speed > 4 then journey.mothership_speed = 4 end + else + if journey.mothership_advancing_to_world then + table.insert(journey.mothership_messages, "Aborting travling sequence.") + journey.mothership_advancing_to_world = false + end + journey.mothership_speed = journey.mothership_speed - 0.25 + if journey.mothership_speed < 0.35 then journey.mothership_speed = 0.35 end + end + + draw_background(journey, surface) + animate_selectors(journey) +end + +function Public.mothership_arrives_at_world(journey) + local surface = game.surfaces.mothership + + Public.teleport_players_to_mothership(journey) + + if journey.mothership_speed == 0.15 then + journey.mothership_teleporter = surface.create_entity({name = "player-port", position = Constants.mothership_teleporter_position, force = "player"}) + table.insert(journey.mothership_messages, "Teleporter deployed. [gps=" .. Constants.mothership_teleporter_position.x .. "," .. Constants.mothership_teleporter_position.y .. ",mothership]") + journey.mothership_teleporter.destructible = false + journey.mothership_teleporter.minable = false + + for _ = 1, 16, 1 do table.insert(journey.mothership_messages, "") end + table.insert(journey.mothership_messages, "[img=item/uranium-fuel-cell] Fuel cells depleted ;_;") + for _ = 1, 16, 1 do table.insert(journey.mothership_messages, "") end + table.insert(journey.mothership_messages, "Refuel via supply rocket required!") + for _ = 1, 16, 1 do table.insert(journey.mothership_messages, "") end + table.insert(journey.mothership_messages, "Good luck on your adventure! ^.^") + + for i = 1, 3, 1 do + journey.world_selectors[i].activation_level = 0 + end + animate_selectors(journey) + + journey.game_state = "create_the_world" + else + journey.mothership_speed = journey.mothership_speed - 0.15 + end + + if journey.mothership_speed < 0.15 then + journey.mothership_speed = 0.15 + end + + draw_background(journey, surface) +end + +function Public.create_the_world(journey) + local surface = game.surfaces.nauvis + local mgs = surface.map_gen_settings + mgs.seed = math.random(1, 4294967295) + mgs.peaceful_mode = false + + local modifiers = journey.world_selectors[journey.selected_world].modifiers + for _, modifier in pairs(modifiers) do + local m = (100 + modifier[2]) * 0.01 + local name = modifier[1] + for _, autoplace in pairs({"iron-ore", "copper-ore", "uranium-ore", "coal", "stone", "crude-oil", "stone", "trees", "enemy-base"}) do + if name == autoplace then + for k, v in pairs(mgs.autoplace_controls[name]) do + mgs.autoplace_controls[name][k] = mgs.autoplace_controls[name][k] * m + end + break + end + end + if name == "cliff_settings" then + --smaller value = more cliffs + local m2 = (100 - modifier[2]) * 0.01 + mgs.cliff_settings.cliff_elevation_interval = mgs.cliff_settings.cliff_elevation_interval * m2 + mgs.cliff_settings.cliff_elevation_0 = mgs.cliff_settings.cliff_elevation_0 * m2 + end + if name == "water" then + mgs.water = mgs.water * m + end + if name == "starting_area" then + mgs.water = mgs.water * m + end + for _, evo in pairs({"time_factor", "destroy_factor", "pollution_factor"}) do + if name == evo then + game.map_settings.enemy_evolution[name] = game.map_settings.enemy_evolution[name] * m + break + end + end + if name == "expansion_cooldown" then + game.map_settings.enemy_expansion.min_expansion_cooldown = game.map_settings.enemy_expansion.min_expansion_cooldown * m + game.map_settings.enemy_expansion.max_expansion_cooldown = game.map_settings.enemy_expansion.min_expansion_cooldown * m + end + if name == "technology_price_multiplier" then + game.difficulty_settings.technology_price_multiplier = game.difficulty_settings.technology_price_multiplier * m + end + if name == "enemy_attack_pollution_consumption_modifier" then + game.map_settings.pollution.enemy_attack_pollution_consumption_modifier = game.map_settings.pollution.enemy_attack_pollution_consumption_modifier * m + end + if name == "ageing" then + game.map_settings.pollution.ageing = game.map_settings.pollution.ageing * m + end + end + + surface.map_gen_settings = mgs + surface.clear(false) + + journey.world_number = journey.world_number + 1 + + for _, good in pairs(journey.world_selectors[journey.selected_world].bonus_goods) do + if journey.bonus_goods[good[1]] then + journey.bonus_goods[good[1]] = journey.bonus_goods[good[1]] + good[2] + else + journey.bonus_goods[good[1]] = good[2] + end + end + journey.goods_to_dispatch = {} + for k, v in pairs(journey.bonus_goods) do table.insert(journey.goods_to_dispatch, {k, v}) end + + Public.draw_gui(journey) + + journey.game_state = "wipe_offline_players" +end + +function Public.wipe_offline_players(journey) + for _, player in pairs(game.players) do + if not player.connected then + player.force = game.forces.enemy + end + end + journey.game_state = "place_teleporter_into_world" +end + +function Public.place_teleporter_into_world(journey) + local surface = game.surfaces.nauvis + surface.request_to_generate_chunks({x = 0, y = 0}, 3) + surface.force_generate_chunk_requests() + journey.nauvis_teleporter = surface.create_entity({name = "player-port", position = Constants.mothership_teleporter_position, force = "player"}) + journey.nauvis_teleporter.destructible = false + journey.nauvis_teleporter.minable = false + journey.game_state = "make_it_night" +end + +function Public.make_it_night(journey) + draw_background(journey, game.surfaces.mothership) + local surface = game.surfaces.mothership + local daytime = surface.daytime + daytime = daytime + 0.02 + surface.daytime = daytime + if daytime > 0.5 then + clear_world_selectors(journey) + game.reset_time_played() + game.forces.player.reset() + game.forces.player.reset_technologies() + game.forces.player.reset_technology_effects() + game.forces.enemy.reset_evolution() + journey.mothership_cargo["uranium-fuel-cell"] = nil + journey.mothership_teleporter_online = true + journey.game_state = "dispatch_goods" + end +end + +function Public.dispatch_goods(journey) + draw_background(journey, game.surfaces.mothership) + + if math.random(1, 16) ~= 1 then return end + if journey.characters_in_mothership == #game.connected_players then return end + + local goods_to_dispatch = journey.goods_to_dispatch + local size_of_goods_to_dispatch = #goods_to_dispatch + if size_of_goods_to_dispatch == 0 then + journey.game_state = "world" + return + end + + if journey.dispatch_beacon and journey.dispatch_beacon.valid then return end + + local surface = game.surfaces.nauvis + + if journey.dispatch_beacon_position then + local good = goods_to_dispatch[journey.dispatch_key] + surface.spill_item_stack(journey.dispatch_beacon_position, {name = good[1], count = good[2]}, true, nil, false) + table.remove(journey.goods_to_dispatch, journey.dispatch_key) + journey.dispatch_beacon = nil + journey.dispatch_beacon_position = nil + journey.dispatch_key = nil + return + end + + local chunk = surface.get_random_chunk() + local position = {x = chunk.x * 32 + math.random(0, 31), y = chunk.y * 32 + math.random(0, 31)} + position = surface.find_non_colliding_position("rocket-silo", position, 32, 1) + if not position then return end + + journey.dispatch_beacon = surface.create_entity({name = "stone-wall", position = position, force = "neutral"}) + journey.dispatch_beacon.minable = false + journey.dispatch_beacon_position = {x = position.x, y = position.y} + journey.dispatch_key = math.random(1, size_of_goods_to_dispatch) + + local good = goods_to_dispatch[journey.dispatch_key] + table.insert(journey.mothership_messages, "Capsule containing " .. good[2] .. "x [img=item/" .. good[1] .. "] dispatched. [gps=" .. position.x .. "," .. position.y .. ",nauvis]") + + surface.create_entity({name = "artillery-projectile", position = {x = position.x - 256 + math.random(0, 512), y = position.y - 256}, target = position, speed = 0.2}) +end + +function Public.world(journey) + if journey.mothership_cargo["uranium-fuel-cell"] then + if journey.mothership_cargo["uranium-fuel-cell"] >= 50 then + table.insert(journey.mothership_messages, "Refuel operation successful!! =^.^=") + journey.game_state = "mothership_waiting_for_players" + end + end + draw_background(journey, game.surfaces.mothership) +end + +function Public.mothership_waiting_for_players(journey) + if journey.characters_in_mothership > #game.connected_players * 0.5 then + journey.game_state = "set_world_selectors" + return + end + + if math.random(1, 2) == 1 then return end + local tick = game.tick % 3600 + if tick == 0 then + local messages = Constants.mothership_messages.waiting + table.insert(journey.mothership_messages, messages[math.random(1, #messages)]) + end +end + +function Public.teleporters(journey, player) + local surface = player.surface + local base_position = {Constants.mothership_teleporter_position.x , Constants.mothership_teleporter_position.y - 5} + if surface.count_entities_filtered({position = player.position, name = "player-port"}) == 0 then return end + if surface.index == 1 then + drop_player_items(player) + local position = game.surfaces.mothership.find_non_colliding_position("character", base_position, 32, 0.5) + if position then + player.teleport(position, game.surfaces.mothership) + else + player.teleport(base_position, game.surfaces.mothership) + end + journey.characters_in_mothership = journey.characters_in_mothership + 1 + return + end + if not journey.mothership_teleporter_online then return end + if surface.name == "mothership" then + drop_player_items(player) + local position = game.surfaces.nauvis.find_non_colliding_position("character", base_position, 32, 0.5) + if position then + player.teleport(position, game.surfaces.nauvis) + else + player.teleport(base_position, game.surfaces.nauvis) + end + + journey.characters_in_mothership = journey.characters_in_mothership - 1 + return + end +end + +return Public \ No newline at end of file diff --git a/maps/journey/main.lua b/maps/journey/main.lua new file mode 100644 index 00000000..aba844d9 --- /dev/null +++ b/maps/journey/main.lua @@ -0,0 +1,130 @@ +--luacheck: ignore +--[[ +Journey, launch a rocket in increasingly harder getting worlds. - MewMew +]]-- + +local Constants = require 'maps.journey.constants' +local Functions = require 'maps.journey.functions' +local Map = require 'modules.map_info' +local Global = require 'utils.global' + +local journey = {} +Global.register( + journey, + function(tbl) + journey = tbl + end +) + +local function on_chunk_generated(event) + local surface = event.surface + if surface.name ~= "mothership" then return end + Functions.on_mothership_chunk_generated(event) +end + +local function on_player_joined_game(event) + local player = game.players[event.player_index] + Functions.draw_gui(journey) + + if player.surface.name == "mothership" then + journey.characters_in_mothership = journey.characters_in_mothership + 1 + end + + if player.force.name == "enemy" then + Functions.clear_player(player) + player.force = game.forces.player + end +end + +local function on_player_left_game(event) + local player = game.players[event.player_index] + Functions.draw_gui(journey) + + if player.surface.name == "mothership" then + journey.characters_in_mothership = journey.characters_in_mothership - 1 + end +end + +local function on_player_changed_position(event) + local player = game.players[event.player_index] + Functions.teleporters(journey, player) +end + +local function on_built_entity(event) + Functions.deny_building(event) +end + +local function on_robot_built_entity(event) + Functions.deny_building(event) +end + +local function on_rocket_launched(event) + local rocket_inventory = event.rocket.get_inventory(defines.inventory.rocket) + local slot = rocket_inventory[1] + if slot and slot.valid and slot.valid_for_read then + if journey.mothership_cargo[slot.name] then + journey.mothership_cargo[slot.name] = journey.mothership_cargo[slot.name] + slot.count + else + journey.mothership_cargo[slot.name] = slot.count + end + end +end + +local function on_nth_tick() + Functions[journey.game_state](journey) + Functions.mothership_message_queue(journey) +end + +local function on_init() + local T = Map.Pop_info() + T.main_caption = 'Journey' + T.sub_caption = 'v 1.3' + T.text = + table.concat( + { + 'The selectors in the mothership, allow you to select a destination.\n', + 'Once enough players are on a selector, mothership will start traveling.\n', + 'A teleporter will be deployed, after reaching the target.\n', + 'It is however, only capable of transfering the subjects body, anything besides will be left on the ground.\n\n', + + 'Worlds will get more difficult with each jump, adding the chosen modifiers.\n', + 'Launch a stack of uranium fuel cells via rocket cargo, to advance to the next world.\n', + 'The tooltip on the top button has information about the current world.\n', + 'If the journey ends, an admin can fully reset the map via command "/reset-journey".\n\n', + + 'How far will this journey lead?\n\n', + } + ) + T.main_caption_color = {r = 100, g = 20, b = 255} + T.sub_caption_color = {r = 100, g = 100, b = 100} + Functions.hard_reset(journey) +end + +commands.add_command( + 'reset-journey', + 'Fully resets the journey map.', + function() + local player = game.player + if not (player and player.valid) then + return + end + if not player.admin then + player.print("You are not an admin!") + return + end + Functions.hard_reset(journey) + game.print(player.name .. " has reset the map.") + end +) + +local Event = require 'utils.event' +Event.on_init(on_init) +Event.on_nth_tick(10, on_nth_tick) +Event.add(defines.events.on_chunk_generated, on_chunk_generated) +Event.add(defines.events.on_player_changed_position, on_player_changed_position) +Event.add(defines.events.on_player_joined_game, on_player_joined_game) +Event.add(defines.events.on_player_left_game, on_player_left_game) +Event.add(defines.events.on_player_changed_position, on_player_changed_position) +Event.add(defines.events.on_rocket_launched, on_rocket_launched) +Event.add(defines.events.on_robot_built_entity, on_robot_built_entity) +Event.add(defines.events.on_built_entity, on_built_entity) \ No newline at end of file