From b579ff27f9d863ba2964262865531f630624a9fd Mon Sep 17 00:00:00 2001 From: Piratux <58703216+Piratux@users.noreply.github.com> Date: Wed, 1 Feb 2023 16:24:42 +0200 Subject: [PATCH] Difficulty and biter boat adjustments Changes: - In hard and nightmare difficulties, spawners have a chance to become elite. - Biter boats now can arrive at any time, instead of only arriving within few minutes of crew ship's landing. - Fixed memory leak with healthbars. Previous change update: - Allowing ore to spawn on top of another in walkways. - Disabled boat steering in Mysterious Caves island. --- maps/pirates/ai.lua | 48 +------- maps/pirates/api_events.lua | 113 +++++++++++------- maps/pirates/api_on_tick.lua | 28 ++--- maps/pirates/balance.lua | 8 +- maps/pirates/commands.lua | 14 +-- maps/pirates/common.lua | 55 ++++++++- maps/pirates/memory.lua | 1 - maps/pirates/progression.lua | 6 +- .../quest_structures/market1/market1.lua | 4 +- .../quest_structures/quest_structures.lua | 6 +- maps/pirates/surfaces/islands/islands.lua | 13 +- maps/pirates/surfaces/surfaces.lua | 94 ++++++++++----- 12 files changed, 232 insertions(+), 158 deletions(-) diff --git a/maps/pirates/ai.lua b/maps/pirates/ai.lua index a296508c..a69d7620 100644 --- a/maps/pirates/ai.lua +++ b/maps/pirates/ai.lua @@ -307,7 +307,7 @@ function Public.create_mail_delivery_biters() --these travel cross-map between b local surface = game.surfaces[Common.current_destination().surface_name] local enemy_force_name = memory.enemy_force_name - local spawners = Public.get_valid_spawners(surface) + local spawners = Common.get_valid_spawners(surface) local try_how_many_groups = Math.clamp(0, 4, (#spawners - 8) / 100) @@ -360,7 +360,7 @@ function Public.spawn_group_of_scripted_biters(fraction_of_floating_pollution, m local surface = game.surfaces[Common.current_destination().surface_name] local enemy_force_name = memory.enemy_force_name - local spawner = Public.get_random_valid_spawner(surface) + local spawner = Common.get_random_valid_spawner(surface) if not spawner then log('no spawner found') return end local nearby_units_to_bring @@ -587,50 +587,6 @@ end -- return false -- end -function Public.get_valid_spawners(surface) - local memory = Memory.get_crew_memory() - - local spawners = surface.find_entities_filtered({type = 'unit-spawner', force = memory.enemy_force_name}) - - local boat_spawners = {} - - if memory.enemyboats and #memory.enemyboats > 0 then - for i = 1, #memory.enemyboats do - local eb = memory.enemyboats[i] - if eb.spawner and eb.spawner.valid then - boat_spawners[#boat_spawners + 1] = eb.spawner - end - end - end - - local valid_spawners = {} - for i = 1, #spawners do - local s = spawners[i] - local valid = true - for j = 1, #boat_spawners do - local bs = boat_spawners[j] - if s == bs then - valid = false - break - end - end - if valid then - valid_spawners[#valid_spawners + 1] = s - end - end - - return valid_spawners -end - -function Public.get_random_valid_spawner(surface) - - local spawners = Public.get_valid_spawners(surface) - - if #spawners == 0 then return end - - return spawners[Math.random(#spawners)] -end - function Public.is_biter_inactive(biter) if (not biter.entity) or (not biter.entity.valid) then return true diff --git a/maps/pirates/api_events.lua b/maps/pirates/api_events.lua index acf62c44..7b42c9ee 100644 --- a/maps/pirates/api_events.lua +++ b/maps/pirates/api_events.lua @@ -160,7 +160,7 @@ local function damage_to_silo(event) destination.dynamic_data.rocketsilos[1].valid and entity == Common.current_destination().dynamic_data.rocketsilos[1] then - if string.sub(event.cause.force.name, 1, 4) ~= 'crew' then + if string.sub(event.cause.force.name, 1, 4) ~= 'crew' then -- @Piratux: wonder why this is needed -- play alert sound for all crew members if memory.seconds_until_alert_sound_can_be_played_again <= 0 then @@ -172,10 +172,12 @@ local function damage_to_silo(event) end end - if Common.entity_damage_healthbar(entity, event.original_damage_amount / Balance.silo_resistance_factor * (1 + Balance.biter_timeofday_bonus_damage(event.cause.surface.darkness))) <= 0 then + local damage = event.original_damage_amount / Balance.silo_resistance_factor * (1 + Balance.biter_timeofday_bonus_damage(event.cause.surface.darkness)) + local remaining_health = Common.entity_damage_healthbar(entity, damage, destination.dynamic_data) + if remaining_health and remaining_health <= 0 then Public.silo_die() else - destination.dynamic_data.rocketsilohp = memory.healthbars[entity.unit_number].health + destination.dynamic_data.rocketsilohp = remaining_health end else entity.health = entity.prototype.max_health @@ -187,29 +189,52 @@ end local function damage_to_enemyboat_spawners(event) local memory = Memory.get_crew_memory() + local destination = Common.current_destination() - if memory.enemyboats and - #memory.enemyboats > 0 and + if destination.dynamic_data.enemyboats and + #destination.dynamic_data.enemyboats > 0 and event.cause and event.cause.valid and event.entity and event.entity.valid and event.entity.force.name == memory.enemy_force_name then - for i = 1, #memory.enemyboats do - local eb = memory.enemyboats[i] + for i = 1, #destination.dynamic_data.enemyboats do + local eb = destination.dynamic_data.enemyboats[i] if eb.spawner and eb.spawner.valid and event.entity == eb.spawner then -- if eb.spawner and eb.spawner.valid and event.entity == eb.spawner and eb.state == Structures.Boats.enum_state.APPROACHING then local damage = event.final_damage_amount - local adjusted_damage = damage + local remaining_health = Common.entity_damage_healthbar(event.entity, damage, destination.dynamic_data) - adjusted_damage = adjusted_damage / 2.6 + if remaining_health and remaining_health <= 0 then + event.entity.die() + end + end + end + end +end - -- if event.cause.name == 'artillery-turret' then - -- adjusted_damage = adjusted_damage / 1 - -- end +-- Does not include krakens or biter boat spawners +local function damage_to_elite_spawners(event) + local memory = Memory.get_crew_memory() + local destination = Common.current_destination() - if Common.entity_damage_healthbar(event.entity, adjusted_damage) <= 0 then + if destination.dynamic_data.elite_spawners and + #destination.dynamic_data.elite_spawners > 0 and + event.cause and + event.cause.valid and + event.entity and + event.entity.valid and + event.entity.force.name == memory.enemy_force_name + then + for i = 1, #destination.dynamic_data.elite_spawners do + local spawner = destination.dynamic_data.elite_spawners[i] + if spawner and spawner.valid and event.entity == spawner then + local damage = event.final_damage_amount + + local remaining_health = Common.entity_damage_healthbar(event.entity, damage, destination.dynamic_data) + + if remaining_health and remaining_health <= 0 then event.entity.die() end end @@ -224,15 +249,7 @@ local function damage_to_artillery(event) if not event.cause.valid then return end if not event.cause.name then return end - if (event.cause.name == 'small-biter') - or (event.cause.name == 'small-spitter') - or (event.cause.name == 'medium-biter') - or (event.cause.name == 'medium-spitter') - or (event.cause.name == 'big-biter') - or (event.cause.name == 'big-spitter') - or (event.cause.name == 'behemoth-biter') - or (event.cause.name == 'behemoth-spitter') - then + if Utils.contains(CoreData.enemy_units, event.cause.name) then if event.cause.force.name ~= memory.enemy_force_name then return end -- play alert sound for all crew members @@ -248,7 +265,11 @@ local function damage_to_artillery(event) -- remove resistances: -- event.entity.health = event.entity.health + event.final_damage_amount - event.original_damage_amount - if Common.entity_damage_healthbar(event.entity, event.original_damage_amount / Balance.cannon_resistance_factor * (1 + Balance.biter_timeofday_bonus_damage(event.cause.surface.darkness)), Memory.get_crew_memory().boat) <= 0 then + local damage = event.original_damage_amount / Balance.cannon_resistance_factor + damage = damage * (1 + Balance.biter_timeofday_bonus_damage(event.cause.surface.darkness)) + local remaining_health = Common.entity_damage_healthbar(event.entity, damage, memory.boat) + + if remaining_health and remaining_health <= 0 then event.entity.die() end else @@ -279,7 +300,6 @@ local function damage_to_krakens(event) local adjusted_damage = damage if event.damage_type.name and event.damage_type.name == 'poison' then - -- if event.cause.name == 'artillery-turret' then adjusted_damage = adjusted_damage / 1.25 elseif event.damage_type.name and (event.damage_type.name == 'explosion') then adjusted_damage = adjusted_damage / 1.5 @@ -295,8 +315,13 @@ local function damage_to_krakens(event) adjusted_damage = adjusted_damage / 7 --laser turrets are in range. give some resistance end - if Common.entity_damage_healthbar(event.entity, adjusted_damage) <= 0 then - Kraken.kraken_die(memory.healthbars[unit_number].id) + -- There should be a better way to do it than this... + if memory.healthbars and memory.healthbars[unit_number] then + local kraken_id = memory.healthbars[unit_number].id + local remaining_health = Common.entity_damage_healthbar(event.entity, adjusted_damage) + if remaining_health and remaining_health <= 0 then + Kraken.kraken_die(kraken_id) + end end end @@ -346,17 +371,9 @@ local function damage_to_players_changes(event) end elseif class == Classes.enum.VETERAN then local chance = Balance.veteran_on_hit_slow_chance - if Math.random() < chance then + if Math.random() <= chance then -- only certain targets accept stickers - if event.cause.name == 'small-biter' or - event.cause.name == 'small-spitter' or - event.cause.name == 'medium-biter' or - event.cause.name == 'medium-spitter' or - event.cause.name == 'big-biter' or - event.cause.name == 'big-spitter' or - event.cause.name == 'behemoth-biter' or - event.cause.name == 'behemoth-spitter' - then + if Utils.contains(CoreData.enemy_units, event.cause.name) then player.surface.create_entity{ name = 'slowdown-sticker', position = player.character.position, @@ -616,6 +633,7 @@ local function event_on_entity_damaged(event) damage_to_silo(event) damage_to_krakens(event) damage_to_enemyboat_spawners(event) + damage_to_elite_spawners(event) if event.entity and event.entity.valid and event.entity.name and event.entity.name == 'artillery-turret' then damage_to_artillery(event) @@ -1000,10 +1018,13 @@ local function event_on_player_mined_entity(event) local points_to_avoid = destination.dynamic_data.ore_spawn_points_to_avoid local can_place_ores = true - for _, pos in ipairs(points_to_avoid) do - if Math.distance(pos, entity.position) < Balance.min_ore_spawn_distance then - can_place_ores = false - break + -- Sometimes there can be very little amount of rocks here, so it probably isn't bad idea to spawn ore on top of another + if destination.subtype ~= IslandEnum.enum.WALKWAYS then + for _, pos in ipairs(points_to_avoid) do + if Math.distance(pos, entity.position) < Balance.min_ore_spawn_distance then + can_place_ores = false + break + end end end @@ -1168,9 +1189,9 @@ local function base_kill_rewards(event) if (entity_name == 'biter-spawner' or entity_name == 'spitter-spawner') and entity.position and entity.surface and entity.surface.valid then --check if its a boat biter entity local boat_spawner = false - if memory.enemyboats then - for i = 1, #memory.enemyboats do - local eb = memory.enemyboats[i] + if destination.dynamic_data.enemyboats then + for i = 1, #destination.dynamic_data.enemyboats do + local eb = destination.dynamic_data.enemyboats[i] if eb.spawner and eb.spawner.valid and event.entity == eb.spawner then boat_spawner = true break @@ -1194,9 +1215,9 @@ local function spawner_died(event) if (destination and destination.type and destination.type == Surfaces.enum.ISLAND) then local not_boat = true - if memory.enemyboats and #memory.enemyboats > 0 then - for i = 1, #memory.enemyboats do - local eb = memory.enemyboats[i] + if destination.dynamic_data.enemyboats and #destination.dynamic_data.enemyboats > 0 then + for i = 1, #destination.dynamic_data.enemyboats do + local eb = destination.dynamic_data.enemyboats[i] if eb.spawner and eb.spawner.valid and event.entity and event.entity.valid and event.entity == eb.spawner then not_boat = false break diff --git a/maps/pirates/api_on_tick.lua b/maps/pirates/api_on_tick.lua index 6b75303d..41b13ea8 100644 --- a/maps/pirates/api_on_tick.lua +++ b/maps/pirates/api_on_tick.lua @@ -813,9 +813,9 @@ function Public.boat_movement_tick(tickinterval) end end - if memory.enemyboats then - for i = 1, #memory.enemyboats do - local eboat = memory.enemyboats[i] + if destination.dynamic_data.enemyboats then + for i = 1, #destination.dynamic_data.enemyboats do + local eboat = destination.dynamic_data.enemyboats[i] if eboat and eboat.surface_name and game.surfaces[eboat.surface_name] and game.surfaces[eboat.surface_name].valid then if eboat.state == Boats.enum_state.APPROACHING and eboat.speed and eboat.speed > 0 and memory.game_lost == false then local ticker_increase = eboat.speed / 60 * tickinterval @@ -860,7 +860,7 @@ function Public.boat_movement_tick(tickinterval) do end end else - memory.enemyboats[i] = nil + destination.dynamic_data.enemyboats[i] = nil end end end @@ -1161,17 +1161,17 @@ function Public.slower_boat_tick(tickinterval) game.pollution_statistics.on_flow('locomotive', pollution) end - if memory.enemyboats then - for i = 1, #memory.enemyboats do - local b = memory.enemyboats[i] + -- if memory.enemyboats then + -- for i = 1, #memory.enemyboats do + -- local b = memory.enemyboats[i] - -- if b.landing_time and destination.dynamic_data.timer and destination.dynamic_data.timer >= b.landing_time and b.spawner and b.spawner.valid then - -- -- if b.landing_time and destination.dynamic_data.timer and destination.dynamic_data.timer >= b.landing_time + 3 and b.spawner and b.spawner.valid then - -- b.spawner.destructible = true - -- b.landing_time = nil - -- end - end - end + -- -- if b.landing_time and destination.dynamic_data.timer and destination.dynamic_data.timer >= b.landing_time and b.spawner and b.spawner.valid then + -- -- -- if b.landing_time and destination.dynamic_data.timer and destination.dynamic_data.timer >= b.landing_time + 3 and b.spawner and b.spawner.valid then + -- -- b.spawner.destructible = true + -- -- b.landing_time = nil + -- -- end + -- end + -- end end function Public.LOS_tick(tickinterval) diff --git a/maps/pirates/balance.lua b/maps/pirates/balance.lua index b0040225..40029fa3 100644 --- a/maps/pirates/balance.lua +++ b/maps/pirates/balance.lua @@ -90,6 +90,8 @@ Public.prevent_waves_from_spawning_in_cave_timer_length = 10 -- in seconds Public.min_ore_spawn_distance = 20 +Public.biter_boat_average_arrival_rate = 8*60 -- in seconds + function Public.starting_boatEEIpower_production_MW() -- return 3 * Math.sloped(Common.capacity_scale(), 1/2) / 2 --/2 as we have 2 return 3/2 @@ -569,7 +571,11 @@ function Public.krakens_per_free_slot(overworldx) end function Public.biter_boat_health() - return Math.ceil(700 * Math.max(1, 1 + 0.075 * (Common.overworldx()/40)^(13/10)) * (Public.crew_scale()^(1/5)) * Math.sloped(Common.difficulty_scale(), 3/4)) + return Math.ceil(1500 * Math.max(1, 1 + 0.075 * (Common.overworldx()/40)^(13/10)) * (Public.crew_scale()^(1/5)) * Math.sloped(Common.difficulty_scale(), 3/4)) +end + +function Public.elite_spawner_health() + return Math.ceil(5000 * Math.max(1, 1 + 0.075 * (Common.overworldx()/40)^(13/10)) * (Public.crew_scale()^(1/5)) * Math.sloped(Common.difficulty_scale(), 3/4)) end function Public.main_shop_cost_multiplier() diff --git a/maps/pirates/commands.lua b/maps/pirates/commands.lua index 665e6e51..30d9b22e 100644 --- a/maps/pirates/commands.lua +++ b/maps/pirates/commands.lua @@ -658,7 +658,7 @@ if _DEBUG then if not Common.get_id_from_force_name(player.character.force.name) then local proposal = { capacity_option = 3, - difficulty_option = 2, + difficulty_option = 4, -- mode_option = 'left', endorserindices = { 1 }, name = "AdminRun" @@ -898,10 +898,9 @@ if _DEBUG then cmd_set_memory(cmd) local param = tostring(cmd.parameter) if check_admin(cmd) then - local player = game.players[cmd.player_index] - local memory = Memory.get_crew_memory() + local destination = Common.current_destination() Islands.spawn_enemy_boat(Boats.enum.RAFT) - local boat = memory.enemyboats[1] + local boat = destination.dynamic_data.enemyboats[1] Ai.spawn_boat_biters(boat, 0.89, Boats.get_scope(boat).Data.capacity, Boats.get_scope(boat).Data.width) game.print('enemy boat spawned') end @@ -914,10 +913,9 @@ if _DEBUG then cmd_set_memory(cmd) local param = tostring(cmd.parameter) if check_admin(cmd) then - local player = game.players[cmd.player_index] - local memory = Memory.get_crew_memory() + local destination = Common.current_destination() Islands.spawn_enemy_boat(Boats.enum.RAFTLARGE) - local boat = memory.enemyboats[1] + local boat = destination.dynamic_data.enemyboats[1] Ai.spawn_boat_biters(boat, 0.89, Boats.get_scope(boat).Data.capacity, Boats.get_scope(boat).Data.width) game.print('large enemy boat spawned') end @@ -1159,7 +1157,7 @@ if _DEBUG then end for i = -2, 2 do local p1 = scope.Data.cannons[2] - local p2 = {x = boat.position.x + p1.x + i * 2, y = boat.position.y + p1.y + 4} + local p2 = {x = boat.position.x + p1.x + i * 2, y = boat.position.y + p1.y + 3} local e = surface.create_entity({name = 'gun-turret', position = p2, force = boat.force_name, create_build_effect_smoke = false}) if e and e.valid then e.insert({name = "uranium-rounds-magazine", count = 200}) diff --git a/maps/pirates/common.lua b/maps/pirates/common.lua index 62afdc8f..01074ed3 100644 --- a/maps/pirates/common.lua +++ b/maps/pirates/common.lua @@ -744,6 +744,7 @@ end function Public.transfer_healthbar(old_unit_number, new_entity, location_override) location_override = location_override or Memory.get_crew_memory() if not location_override.healthbars then return end + local old_healthbar = location_override.healthbars[old_unit_number] -- local new_unit_number = new_entity.unit_number @@ -771,11 +772,12 @@ end function Public.entity_damage_healthbar(entity, damage, location_override) location_override = location_override or Memory.get_crew_memory() - local unit_number = entity.unit_number + if not (location_override.healthbars) then return end + local unit_number = entity.unit_number local healthbar = location_override.healthbars[unit_number] - if not healthbar then return 0 end + if not healthbar then return end local new_health = healthbar.health - damage healthbar.health = new_health @@ -785,6 +787,10 @@ function Public.entity_damage_healthbar(entity, damage, location_override) entity.health = entity.prototype.max_health end + if healthbar.health <= 0 then + location_override.healthbars[unit_number] = nil + end + return healthbar.health end @@ -1705,4 +1711,49 @@ function Public.replace_unwalkable_tiles(surface, position, width, height) end end +function Public.get_valid_spawners(surface) + local memory = Memory.get_crew_memory() + local destination = Public.current_destination() + + local spawners = surface.find_entities_filtered({type = 'unit-spawner', force = memory.enemy_force_name}) + + local boat_spawners = {} + + if destination.dynamic_data.enemyboats and #destination.dynamic_data.enemyboats > 0 then + for i = 1, #destination.dynamic_data.enemyboats do + local eb = destination.dynamic_data.enemyboats[i] + if eb.spawner and eb.spawner.valid then + boat_spawners[#boat_spawners + 1] = eb.spawner + end + end + end + + local valid_spawners = {} + for i = 1, #spawners do + local s = spawners[i] + local valid = true + for j = 1, #boat_spawners do + local bs = boat_spawners[j] + if s == bs then + valid = false + break + end + end + if valid and s.valid then + valid_spawners[#valid_spawners + 1] = s + end + end + + return valid_spawners +end + +function Public.get_random_valid_spawner(surface) + + local spawners = Public.get_valid_spawners(surface) + + if #spawners == 0 then return end + + return spawners[Math.random(#spawners)] +end + return Public \ No newline at end of file diff --git a/maps/pirates/memory.lua b/maps/pirates/memory.lua index d54efa5f..2a6e15b5 100644 --- a/maps/pirates/memory.lua +++ b/maps/pirates/memory.lua @@ -90,7 +90,6 @@ function Public.initialise_crew_memory(id) --mostly serves as a dev reference of memory.speed_boost_characters = nil - memory.enemyboats = nil memory.overworld_krakens = nil memory.active_sea_enemies = nil memory.kraken_stream_registrations = nil diff --git a/maps/pirates/progression.lua b/maps/pirates/progression.lua index 1d40119f..576d7c04 100644 --- a/maps/pirates/progression.lua +++ b/maps/pirates/progression.lua @@ -283,8 +283,6 @@ function Public.progress_to_destination(destination_index) boat.state = destination_data.init_boat_state boat.dockedposition = nil - memory.enemyboats = {} - local old_water = 'deepwater' if old_type == Surfaces.enum.LOBBY or old_type == Surfaces.enum.DOCK then old_water = 'water' end @@ -312,6 +310,10 @@ function Public.progress_to_destination(destination_index) destination.dynamic_data.timer = 0 destination.dynamic_data.timeratlandingtime = nil + destination.dynamic_data.enemyboats = {} + destination.dynamic_data.elite_spawners = {} + + destination.dynamic_data.healthbars = {} memory.extra_time_at_sea = 0 diff --git a/maps/pirates/structures/quest_structures/market1/market1.lua b/maps/pirates/structures/quest_structures/market1/market1.lua index 08b83be7..044ee146 100644 --- a/maps/pirates/structures/quest_structures/market1/market1.lua +++ b/maps/pirates/structures/quest_structures/market1/market1.lua @@ -256,7 +256,7 @@ Public.entry_price_data_raw = { ['steel-chest'] = { overallWeight = 0.5, minLambda = 0.2, - maxLambda = 0.7, + maxLambda = 1, shape = false, base_amount = 125, raw_materials = {{name = 'steel-plate', count = 1000}} @@ -264,7 +264,7 @@ Public.entry_price_data_raw = { ['rail'] = { overallWeight = 1, minLambda = 0.2, - maxLambda = 0.8, + maxLambda = 1, shape = false, base_amount = 400, raw_materials = {{name = 'iron-plate', count = 1100}} diff --git a/maps/pirates/structures/quest_structures/quest_structures.lua b/maps/pirates/structures/quest_structures/quest_structures.lua index a93402ed..baf9621b 100644 --- a/maps/pirates/structures/quest_structures/quest_structures.lua +++ b/maps/pirates/structures/quest_structures/quest_structures.lua @@ -31,14 +31,16 @@ function Public.choose_quest_structure_type() local destination = Common.current_destination() local subtype = destination.subtype - local rng = Math.random(3) + if subtype == IslandEnum.enum.WALKWAYS then + return enum.MARKET1 + end -- Furnace quests are more interesting after that rather than collecting stone furnaces if Common.overworldx() >= 600 then return enum.FURNACE1 end - if rng == 1 or subtype and subtype == IslandEnum.enum.WALKWAYS then + if Math.random(3) == 1 then return enum.MARKET1 else return enum.FURNACE1 diff --git a/maps/pirates/surfaces/islands/islands.lua b/maps/pirates/surfaces/islands/islands.lua index e45889c4..fb3d5b81 100644 --- a/maps/pirates/surfaces/islands/islands.lua +++ b/maps/pirates/surfaces/islands/islands.lua @@ -303,7 +303,7 @@ function Public.spawn_silo_setup(points_to_avoid) silo.operable = false if i == 1 then silo.auto_launch = true - Common.new_healthbar(true, silo, Balance.silo_max_hp, nil, Balance.silo_max_hp, 0.6, -2) + Common.new_healthbar(true, silo, Balance.silo_max_hp, nil, Balance.silo_max_hp, 0.6, -2, destination.dynamic_data) else silo.destructible = false end @@ -345,20 +345,21 @@ end - +-- NOTE: Currently the boats can trigger landing early if 2 boats spawn in same lane in short interval. Too lazy to fix. +-- NOTE: As well as biter boats can miss the island on smaller ones when boat is steered function Public.spawn_enemy_boat(type) local memory = Memory.get_crew_memory() local destination = Common.current_destination() local surface = game.surfaces[destination.surface_name] - local offsets = {50, -50, 63, -63} + local offsets = {50, -50, 63, -63, 76, -76, 89, -89} - local enemyboats = memory.enemyboats + local enemyboats = destination.dynamic_data.enemyboats if enemyboats then local boat = { state = Boats.enum_state.APPROACHING, type = type, speed = 4, - position = {x = - surface.map_gen_settings.width/2 + 23.5, y = (memory.boat.dockedposition or memory.boat.position).y + offsets[Math.random(4)]}, + position = {x = - surface.map_gen_settings.width/2 + 23.5, y = (memory.boat.dockedposition or memory.boat.position).y + offsets[Math.random(#offsets)]}, force_name = memory.enemy_force_name, surface_name = surface.name, unit_group = nil, @@ -375,7 +376,7 @@ function Public.spawn_enemy_boat(type) boat.spawner = e local max_health = Balance.biter_boat_health() - Common.new_healthbar(true, e, max_health, nil, max_health, 0.5) + Common.new_healthbar(true, e, max_health, nil, max_health, 0.5, nil, destination.dynamic_data) end return enemyboats[#enemyboats] diff --git a/maps/pirates/surfaces/surfaces.lua b/maps/pirates/surfaces/surfaces.lua index c4457997..d6f97288 100644 --- a/maps/pirates/surfaces/surfaces.lua +++ b/maps/pirates/surfaces/surfaces.lua @@ -180,9 +180,9 @@ function Public.destination_on_collide(destination) Common.parrot_speak(memory.force, {'pirates.parrot_cave_tip_1'}) else - local scheduled_raft_raids + local scheduled_raft_raids = {} -- temporarily placed this back here, as moving it to shorehit broke things: - local playercount = Common.activecrewcount() + -- local playercount = Common.activecrewcount() local max_evo local difficulty_name = CoreData.get_difficulty_option_informal_name_from_value(Common.difficulty_scale()) @@ -209,34 +209,53 @@ function Public.destination_on_collide(destination) -- Currently biter boats don't spawn properly for cave island, so disabling it for now if destination.subtype ~= IslandEnum.enum.CAVE then - if memory.overworldx > 200 then - scheduled_raft_raids = {} - local times = {600, 360, 215, 210, 120, 30, 10, 5} - for i = 1, #times do - local t = times[i] - if Math.random(6) == 1 and #scheduled_raft_raids < 6 then - scheduled_raft_raids[#scheduled_raft_raids + 1] = {timeinseconds = t, max_evo = max_evo} - -- scheduled_raft_raids[#scheduled_raft_raids + 1] = {timeinseconds = t, max_bonus_evolution = 0.52} + -- if memory.overworldx > 200 then + -- scheduled_raft_raids = {} + -- local times = {600, 360, 215, 210, 120, 30, 10, 5} + -- for i = 1, #times do + -- local t = times[i] + -- if Math.random(6) == 1 and #scheduled_raft_raids < 6 then + -- scheduled_raft_raids[#scheduled_raft_raids + 1] = {timeinseconds = t, max_evo = max_evo} + -- -- scheduled_raft_raids[#scheduled_raft_raids + 1] = {timeinseconds = t, max_bonus_evolution = 0.52} + -- end + -- end + -- elseif memory.overworldx == 200 then + -- local times + -- if playercount <= 2 then + -- times = {1, 5, 10, 15, 20} + -- elseif playercount <= 8 then + -- times = {1, 5, 10, 15, 20, 25} + -- elseif playercount <= 15 then + -- times = {1, 5, 10, 15, 20, 25, 30} + -- elseif playercount <= 21 then + -- times = {1, 5, 10, 15, 20, 25, 30, 35} + -- else + -- times = {1, 5, 10, 15, 20, 25, 30, 35, 40} + -- end + -- scheduled_raft_raids = {} + -- for _, t in pairs(times) do + -- -- scheduled_raft_raids[#scheduled_raft_raids + 1] = {timeinseconds = t, max_bonus_evolution = 0.62} + -- scheduled_raft_raids[#scheduled_raft_raids + 1] = {timeinseconds = t, max_evo = max_evo} + -- end + -- end + + -- NOTE: No need to scale boat count as boat spawner health already scales + local max_time = Balance.max_time_on_island(destination.subtype) + local boat_count = Math.floor(max_time / Balance.biter_boat_average_arrival_rate) - 2 -- avoid spawning biter boats at very last seconds + + for i = 1, boat_count do + local spawn_time = Math.random((i-1) * Balance.biter_boat_average_arrival_rate, (i+1) * Balance.biter_boat_average_arrival_rate) + spawn_time = spawn_time + 5 + + if memory.overworldx == 200 then + if i == 1 then + spawn_time = 5 + elseif i == 2 then + spawn_time = 15 end end - elseif memory.overworldx == 200 then - local times - if playercount <= 2 then - times = {1, 5, 10, 15, 20} - elseif playercount <= 8 then - times = {1, 5, 10, 15, 20, 25} - elseif playercount <= 15 then - times = {1, 5, 10, 15, 20, 25, 30} - elseif playercount <= 21 then - times = {1, 5, 10, 15, 20, 25, 30, 35} - else - times = {1, 5, 10, 15, 20, 25, 30, 35, 40} - end - scheduled_raft_raids = {} - for _, t in pairs(times) do - -- scheduled_raft_raids[#scheduled_raft_raids + 1] = {timeinseconds = t, max_bonus_evolution = 0.62} - scheduled_raft_raids[#scheduled_raft_raids + 1] = {timeinseconds = t, max_evo = max_evo} - end + + scheduled_raft_raids[#scheduled_raft_raids + 1] = {timeinseconds = spawn_time, max_evo = max_evo} end destination.static_params.scheduled_raft_raids = scheduled_raft_raids @@ -465,6 +484,25 @@ function Public.destination_on_crewboat_hits_shore(destination) ShopMerchants.generate_merchant_trades(destination.dynamic_data.merchant_market) end + + + if CoreData.get_difficulty_option_from_value(memory.difficulty) >= 3 and + destination.subtype ~= IslandEnum.enum.FIRST + then + local surface = game.surfaces[destination.surface_name] + local spawner = Common.get_random_valid_spawner(surface) + if spawner then + local max_health = Balance.elite_spawner_health() + Common.new_healthbar(true, spawner, max_health, nil, max_health, 0.8, nil, destination.dynamic_data) + + local elite_spawners = destination.dynamic_data.elite_spawners + if elite_spawners then + elite_spawners[#elite_spawners + 1] = spawner + end + + spawner.destructible = true + end + end end end