--[[ Mountain Fortress v3 is maintained by Gerkiz and hosted by Comfy. Want to host it? Ask Gerkiz#0001 at discord! ]] local Functions = require 'maps.mountain_fortress_v3.functions' local BuriedEnemies = require 'maps.mountain_fortress_v3.buried_enemies' -- local HS = require 'maps.mountain_fortress_v3.highscore' local Discord = require 'utils.discord' local IC = require 'maps.mountain_fortress_v3.ic.table' local ICMinimap = require 'maps.mountain_fortress_v3.ic.minimap' local Autostash = require 'modules.autostash' local Group = require 'comfy_panel.group' local PL = require 'comfy_panel.player_list' local CS = require 'maps.mountain_fortress_v3.surface' local Server = require 'utils.server' local Explosives = require 'modules.explosives' local Balance = require 'maps.mountain_fortress_v3.balance' local Entities = require 'maps.mountain_fortress_v3.entities' local Gui_mf = require 'maps.mountain_fortress_v3.gui' local ICW = require 'maps.mountain_fortress_v3.icw.main' local WD = require 'modules.wave_defense.table' local Map = require 'modules.map_info' local RPG = require 'modules.rpg.main' local Event = require 'utils.event' local WPT = require 'maps.mountain_fortress_v3.table' local Locomotive = require 'maps.mountain_fortress_v3.locomotive' local SpawnLocomotive = require 'maps.mountain_fortress_v3.locomotive.spawn_locomotive' local Score = require 'comfy_panel.score' local Poll = require 'comfy_panel.poll' local Collapse = require 'modules.collapse' local Difficulty = require 'modules.difficulty_vote_by_amount' local Task = require 'utils.task' local Token = require 'utils.token' local Alert = require 'utils.alert' local BottomFrame = require 'comfy_panel.bottom_frame' local AntiGrief = require 'utils.antigrief' local Misc = require 'utils.commands.misc' local Modifiers = require 'utils.player_modifiers' local BiterHealthBooster = require 'modules.biter_health_booster_v2' local Reset = require 'functions.soft_reset' local JailData = require 'utils.datastore.jail_data' local RPG_Progression = require 'utils.datastore.rpg_data' require 'maps.mountain_fortress_v3.locomotive.market' require 'maps.mountain_fortress_v3.locomotive.linked_chests' require 'maps.mountain_fortress_v3.rocks_yield_ore_veins' require 'maps.mountain_fortress_v3.generate' require 'maps.mountain_fortress_v3.commands' require 'maps.mountain_fortress_v3.breached_wall' require 'maps.mountain_fortress_v3.ic.main' require 'maps.mountain_fortress_v3.biters_yield_coins' require 'modules.shotgun_buff' require 'modules.no_deconstruction_of_neutral_entities' require 'modules.spawners_contain_biters' require 'modules.wave_defense.main' require 'modules.charging_station' -- Use these settings for live local send_ping_to_channel = Discord.channel_names.mtn_channel local role_to_mention = Discord.role_mentions.mtn_fortress -- Use these settings for testing -- bot-lounge -- local send_ping_to_channel = Discord.channel_names.bot_quarters -- local role_to_mention = Discord.role_mentions.test_role local Public = {} local raise_event = script.raise_event local floor = math.floor local remove = table.remove local collapse_kill = { entities = { ['laser-turret'] = true, ['flamethrower-turret'] = true, ['gun-turret'] = true, ['artillery-turret'] = true, ['landmine'] = true, ['locomotive'] = true, ['cargo-wagon'] = true, ['character'] = true, ['car'] = true, ['tank'] = true, ['assembling-machine'] = true, ['furnace'] = true, ['steel-chest'] = true }, enabled = true } local init_protectors_force = function() local protectors = game.forces.protectors local enemy = game.forces.enemy if not protectors then protectors = game.create_force('protectors') end protectors.set_friend('enemy', true) enemy.set_friend('protectors', true) end local init_bonus_drill_force = function() local bonus_drill = game.forces.bonus_drill local player = game.forces.player if not bonus_drill then bonus_drill = game.create_force('bonus_drill') end bonus_drill.set_friend('player', true) player.set_friend('bonus_drill', true) bonus_drill.mining_drill_productivity_bonus = 0.5 end local is_position_near_tbl = function(position, tbl) local status = false local function inside(pos) return pos.x >= position.x and pos.y >= position.y and pos.x <= position.x and pos.y <= position.y end for i = 1, #tbl do if inside(tbl[i]) then status = true end end return status end local announce_new_map = Token.register( function() local server_name = Server.check_server_name('Mtn Fortress') if server_name then Server.to_discord_named_raw(send_ping_to_channel, role_to_mention .. ' ** Mtn Fortress was just reset! **') end end ) function Public.reset_map() local Diff = Difficulty.get() local this = WPT.get() local wave_defense_table = WD.get_table() Misc.set('creative_are_you_sure', false) Misc.set('creative_enabled', false) Reset.enable_mapkeeper(true) this.active_surface_index = CS.create_surface() -- this.soft_reset_counter = CS.get_reset_counter() Autostash.insert_into_furnace(true) Autostash.insert_into_wagon(true) Autostash.bottom_button(true) BottomFrame.reset() BottomFrame.activate_custom_buttons(true) BuriedEnemies.reset() Poll.reset() ICW.reset() IC.reset() IC.allowed_surface(game.surfaces[this.active_surface_index].name) Functions.reset_table() game.reset_time_played() WPT.reset_table() RPG.rpg_reset_all_players() RPG.set_surface_name(game.surfaces[this.active_surface_index].name) RPG.enable_health_and_mana_bars(true) RPG.enable_wave_defense(true) RPG.enable_mana(true) RPG.enable_flame_boots(true) RPG.personal_tax_rate(0.4) RPG.enable_stone_path(true) RPG.enable_one_punch(true) RPG.enable_one_punch_globally(false) RPG.enable_range_buffs(true) RPG.enable_auto_allocate(true) RPG.disable_cooldowns_on_spells() RPG.enable_explosive_bullets_globally(true) RPG.enable_explosive_bullets(false) RPG_Progression.toggle_module(false) RPG_Progression.set_dataset('mtn_v3_rpg_prestige') if WPT.get('prestige_system_enabled') then RPG_Progression.restore_xp_on_reset() end Group.reset_groups() Group.alphanumeric_only(false) Functions.disable_tech() init_protectors_force() init_bonus_drill_force() local surface = game.surfaces[this.active_surface_index] if this.winter_mode then surface.daytime = 0.45 end JailData.set_valid_surface(tostring(surface.name)) JailData.reset_vote_table() Explosives.set_surface_whitelist({[surface.name] = true}) Explosives.check_growth_below_void(true) game.forces.player.set_spawn_position({-27, 25}, surface) game.forces.player.manual_mining_speed_modifier = 0 game.forces.player.set_ammo_damage_modifier('artillery-shell', -0.95) BiterHealthBooster.set_active_surface(tostring(surface.name)) BiterHealthBooster.acid_nova(true) BiterHealthBooster.check_on_entity_died(true) BiterHealthBooster.boss_spawns_projectiles(true) BiterHealthBooster.enable_boss_loot(false) BiterHealthBooster.enable_randomize_stun_and_slowdown_sticker(true) Balance.init_enemy_weapon_damage() AntiGrief.whitelist_types('tree', true) AntiGrief.enable_capsule_warning(false) AntiGrief.enable_capsule_cursor_warning(false) AntiGrief.enable_jail(true) AntiGrief.damage_entity_threshold(20) AntiGrief.explosive_threshold(32) PL.show_roles_in_list(true) PL.rpg_enabled(true) Score.reset_tbl() local players = game.connected_players for i = 1, #players do local player = players[i] Score.init_player_table(player, true) Misc.insert_all_items(player) Modifiers.reset_player_modifiers(player) if player.gui.left['mvps'] then player.gui.left['mvps'].destroy() end ICMinimap.kill_minimap(player) raise_event(Gui_mf.events.reset_map, {player_index = player.index}) end Difficulty.reset_difficulty_poll({difficulty_poll_closing_timeout = game.tick + 36000}) Diff.gui_width = 20 Collapse.set_kill_entities(false) Collapse.set_kill_specific_entities(collapse_kill) Collapse.set_speed(8) Collapse.set_amount(1) -- Collapse.set_max_line_size(WPT.level_width) Collapse.set_max_line_size(540) Collapse.set_surface(surface) Collapse.set_position({0, 130}) Collapse.set_direction('north') Collapse.start_now(false) this.locomotive_health = 10000 this.locomotive_max_health = 10000 SpawnLocomotive.locomotive_spawn(surface, {x = -18, y = 25}) Locomotive.render_train_hp() Functions.render_direction(surface) WD.reset_wave_defense() wave_defense_table.surface_index = this.active_surface_index wave_defense_table.target = this.locomotive wave_defense_table.nest_building_density = 32 wave_defense_table.game_lost = false wave_defense_table.spawn_position = {x = 0, y = 84} WD.alert_boss_wave(true) WD.remove_entities(true) WD.enable_threat_log(false) -- creates waaaay to many entries in the global table WD.check_collapse_position(true) WD.set_disable_threat_below_zero(true) WD.increase_boss_health_per_wave(true) WD.increase_damage_per_wave(true) WD.increase_health_per_wave(true) Functions.set_difficulty() Functions.disable_creative() if not surface.is_chunk_generated({-20, 22}) then surface.request_to_generate_chunks({-20, 22}, 0.1) surface.force_generate_chunk_requests() end game.forces.player.set_spawn_position({-27, 25}, surface) Task.set_queue_speed(16) -- HS.get_scores() this.chunk_load_tick = game.tick + 200 this.force_chunk = true this.market_announce = game.tick + 1200 this.game_lost = false Task.set_timeout_in_ticks(25, announce_new_map) end local is_locomotive_valid = function() local locomotive = WPT.get('locomotive') if not locomotive.valid then WPT.set('game_lost', true) Entities.loco_died(true) end end local is_player_valid = function() local players = game.connected_players for _, player in pairs(players) do if player.connected and player.controller_type == 2 then player.set_controller {type = defines.controllers.god} player.create_character() end end end local has_the_game_ended = function() local game_reset_tick = WPT.get('game_reset_tick') if game_reset_tick then if game_reset_tick < 0 then return end local this = WPT.get() this.game_reset_tick = this.game_reset_tick - 30 if this.game_reset_tick % 1800 == 0 then if this.game_reset_tick > 0 then local cause_msg if this.restart then cause_msg = 'restart' elseif this.shutdown then cause_msg = 'shutdown' elseif this.soft_reset then cause_msg = 'soft-reset' end game.print(({'main.reset_in', cause_msg, this.game_reset_tick / 60}), {r = 0.22, g = 0.88, b = 0.22}) end -- local diff_name = Difficulty.get('name') if this.soft_reset and this.game_reset_tick == 0 then this.game_reset_tick = nil -- HS.set_scores(diff_name) Public.reset_map() return end if this.restart and this.game_reset_tick == 0 then if not this.announced_message then -- HS.set_scores(diff_name) game.print(({'entity.notify_restart'}), {r = 0.22, g = 0.88, b = 0.22}) local message = 'Soft-reset is disabled! Server will restart from scenario to load new changes.' Server.to_discord_bold(table.concat {'*** ', message, ' ***'}) Server.start_scenario('Mountain_Fortress_v3') this.announced_message = true return end end if this.shutdown and this.game_reset_tick == 0 then if not this.announced_message then -- HS.set_scores(diff_name) game.print(({'entity.notify_shutdown'}), {r = 0.22, g = 0.88, b = 0.22}) local message = 'Soft-reset is disabled! Server will shutdown. Most likely because of updates.' Server.to_discord_bold(table.concat {'*** ', message, ' ***'}) Server.stop_scenario() this.announced_message = true return end end end end end local chunk_load = function() local chunk_load_tick = WPT.get('chunk_load_tick') local tick = game.tick if chunk_load_tick then if chunk_load_tick < tick then WPT.set('force_chunk', false) WPT.remove('chunk_load_tick') Task.set_queue_speed(8) end end end local collapse_message = Token.register( function(data) local pos = data.position local message = data.message local collapse_position = { position = pos } Alert.alert_all_players_location(collapse_position, message) end ) local lock_locomotive_positions = function() local locomotive = WPT.get('locomotive') if not locomotive or not locomotive.valid then return end local locomotive_positions = WPT.get('locomotive_pos') local success = is_position_near_tbl(locomotive.position, locomotive_positions.tbl) local p = locomotive.position if not success then locomotive_positions.tbl[#locomotive_positions.tbl + 1] = {x = floor(p.x), y = floor(p.y)} end local total_pos = #locomotive_positions.tbl if total_pos > 50 then remove(locomotive_positions.tbl, total_pos - total_pos + 1) end end local compare_collapse_and_train = function() local collapse_pos = Collapse.get_position() local locomotive = WPT.get('locomotive') if not (locomotive and locomotive.valid) then return end local c_y = collapse_pos.y local t_y = locomotive.position.y local gap_between_zones = WPT.get('gap_between_zones') if c_y - t_y <= gap_between_zones.gap then Functions.set_difficulty() else Collapse.set_speed(1) Collapse.set_amount(4) end end local collapse_after_wave_200 = function() local collapse_grace = WPT.get('collapse_grace') if not collapse_grace then return end if Collapse.start_now() then return end local wave_number = WD.get_wave() if wave_number >= 200 then Collapse.start_now(true) local data = { position = Collapse.get_position() } data.message = ({'breached_wall.collapse_start'}) Task.set_timeout_in_ticks(550, collapse_message, data) end end local on_tick = function() local update_gui = Gui_mf.update_gui local tick = game.tick if tick % 40 == 0 then for _, player in pairs(game.connected_players) do update_gui(player) end lock_locomotive_positions() is_player_valid() is_locomotive_valid() has_the_game_ended() chunk_load() end if tick % 250 == 0 then compare_collapse_and_train() Functions.set_spawn_position() Functions.boost_difficulty() end if tick % 1000 == 0 then collapse_after_wave_200() Functions.remove_offline_players() Functions.set_difficulty() Functions.is_creativity_mode_on() end end local on_init = function() local this = WPT.get() Public.reset_map() game.map_settings.path_finder.general_entity_collision_penalty = 10 -- Recommended value game.map_settings.path_finder.general_entity_subsequent_collision_penalty = 3 -- Recommended value local tooltip = { [1] = ({'main.diff_tooltip', '500', '50%', '15%', '15%', '1', '12', '50', '10000', '100%', '15', '10'}), [2] = ({'main.diff_tooltip', '300', '25%', '10%', '10%', '2', '10', '50', '7000', '75%', '8', '8'}), [3] = ({'main.diff_tooltip', '50', '0%', '0%', '0%', '4', '3', '10', '5000', '50%', '5', '6'}) } Difficulty.set_tooltip(tooltip) this.rocks_yield_ore_maximum_amount = 500 this.type_modifier = 1 this.rocks_yield_ore_base_amount = 40 this.rocks_yield_ore_distance_modifier = 0.020 local T = Map.Pop_info() T.localised_category = 'mountain_fortress_v3' T.main_caption_color = {r = 150, g = 150, b = 0} T.sub_caption_color = {r = 0, g = 150, b = 0} Explosives.set_destructible_tile('out-of-map', 1500) Explosives.set_destructible_tile('water', 1000) Explosives.set_destructible_tile('water-green', 1000) Explosives.set_destructible_tile('deepwater-green', 1000) Explosives.set_destructible_tile('deepwater', 1000) Explosives.set_destructible_tile('water-shallow', 1000) Explosives.set_destructible_tile('water-mud', 1000) Explosives.set_destructible_tile('lab-dark-2', 1000) Explosives.set_whitelist_entity('straight-rail') Explosives.set_whitelist_entity('curved-rail') Explosives.set_whitelist_entity('character') Explosives.set_whitelist_entity('spidertron') Explosives.set_whitelist_entity('car') Explosives.set_whitelist_entity('tank') end Event.on_nth_tick(10, on_tick) Event.on_init(on_init) Event.add(WPT.events.reset_map, Public.reset_map) return Public