local Public = {} local Math = require 'maps.pirates.math' local Memory = require 'maps.pirates.memory' local Common = require 'maps.pirates.common' local Utils = require 'maps.pirates.utils_local' local inspect = require 'utils.inspect'.inspect Public.base_extra_character_speed = 0.20 Public.technology_price_multiplier = 1 function Public.starting_boatEEIpower_production_MW() -- return 3 * Math.sloped(Common.capacity_scale(), 1/2) / 2 --/2 as we have 2 return 3/2 end function Public.starting_boatEEIelectric_buffer_size_MJ() --maybe needs to be at least the power_production -- return 3 * Math.sloped(Common.capacity_scale(), 1/2) / 2 --/2 as we have 2 return 3/2 end Public.EEI_stages = { --multipliers 1,2,5,8,12 } function Public.scripted_biters_pollution_cost_multiplier() return 1.33 --tuned end function Public.cost_to_leave_multiplier() return Common.difficulty() end Public.rocket_launch_coin_reward = 5000 function Public.crew_scale() local ret = Common.activecrewcount()/10 if ret == 0 then ret = 1/10 end --if all players are afk return ret end function Public.silo_base_est_time() local T = Public.expected_time_on_island() * Public.crew_scale()^(2/10) --to undo some of the time scaling local est_secs if T > 0 then est_secs = T/6 else est_secs = 60 * 6 end if Common.overworldx() == 0 then est_secs = 60 * 2 end return est_secs end function Public.time_quest_seconds() return 2.8 * Public.silo_base_est_time() end function Public.silo_energy_needed_MJ() local est_secs = Public.silo_base_est_time() local est_base_power = 2*Public.starting_boatEEIpower_production_MW() * (1 + 0.05 * (Common.overworldx()/40)^(5/3)) return est_secs * est_base_power -- return est_secs * est_base_power * Math.sloped(Common.difficulty(), 1/3) end function Public.silo_count() local E = Public.silo_energy_needed_MJ() return Math.ceil(E/(16.8 * 210)) --no more than this many seconds to charge it. Players can in fact go even faster using beacons end function Public.max_time_on_island_formula() --always >0 --tuned return 60 * ( (32 + 2 * (Common.overworldx()/40)^(1/3)) ) / Public.crew_scale()^(65/100) / Math.sloped(Common.difficulty(), 1/4) --changed crew_scale factor significantly to help smaller crews end function Public.max_time_on_island() if Common.overworldx() == 0 or ((Common.overworldx()/40) > 20 and (Common.overworldx()/40) < 25) then return -1 else return Math.ceil(Public.max_time_on_island_formula()) end end function Public.expected_time_on_island() --always >0 return 3/5 * Public.max_time_on_island_formula() end function Public.fuel_depletion_rate_static() if (not Common.overworldx()) then return 0 end local T = Public.expected_time_on_island() local rate if Common.overworldx() > 0 then rate = 410 * (0 + (Common.overworldx()/40)^(9/10)) * Public.crew_scale()^(1/6) * Math.sloped(Common.difficulty(), 1) / T --most of the crewsize dependence is through T, i.e. the coal cost per island stays the same... but the extra player dependency accounts for the fact that even in compressed time, more players seem to get more resources per island else rate = 0 end return -rate end function Public.fuel_depletion_rate_sailing() if (not Common.overworldx()) then return 0 end return - 8 * (1 + 0.13 * (Common.overworldx()/40)^(9/10)) * Math.sloped(Common.difficulty(), 3/5) end function Public.silo_total_pollution() return ( 400 * (Common.difficulty()^(1.2)) * Public.crew_scale()^(2/5) * (3.2 + 0.7 * (Common.overworldx()/40)^(1.6)) --shape of the curve with x is tuned ) end function Public.boat_passive_pollution_per_minute(time) local boost = 1 local T = Public.max_time_on_island_formula() if time then if time >= 90/100 * T then boost = 15 elseif time >= 85/100 * T then boost = 8 elseif time >= 80/100 * T then boost = 6 elseif time >= 70/100 * T then boost = 4 elseif time >= 55/100 * T then boost = 3 elseif time >= 40/100 * T then boost = 2 elseif time >= 25/100 * T then boost = 1.5 end end return boost * ( 6 * Common.difficulty() * (Common.overworldx()/40)^(1.6) * (Public.crew_scale())^(60/100) ) -- No T dependence! Is that the right idea? I wrote it this way earlier, and it can make sense, but I'm not 100% sure. end function Public.base_evolution() local evo = (0.0201 * (Common.overworldx()/40)) * Math.sloped(Common.difficulty(), 1/5) if Common.overworldx()/40 == 0 then evo = 0 end return evo end function Public.expected_time_evo() return 0.14 end function Public.evolution_per_second() local destination = Common.current_destination() local T = Public.expected_time_on_island() --always greater than 0 local rate = Public.expected_time_evo() / T if Common.overworldx() == 0 then rate = 0 end -- scale by biter nests remaining: if destination and destination.dynamic_data then local initial_spawner_count = destination.dynamic_data.initial_spawner_count if initial_spawner_count and initial_spawner_count > 0 then local surface = game.surfaces[destination.surface_name] if surface and surface.valid then rate = rate * Common.spawner_count(surface) / destination.dynamic_data.initial_spawner_count end end end if _DEBUG then local surface = game.surfaces[destination.surface_name] game.print(Common.spawner_count(surface) .. ' ' .. destination.dynamic_data.initial_spawner_count) end return rate end function Public.evolution_per_biter_base_kill() --it's important to have evo go up with biter base kills, to provide resistance if you try to plow through all the bases local destination = Common.current_destination() if Common.overworldx() == 0 then return 0 end if destination and destination.dynamic_data and destination.dynamic_data.timer and destination.dynamic_data.timer > 0 and destination.dynamic_data.initial_spawner_count and destination.dynamic_data.initial_spawner_count > 0 then local initial_spawner_count = destination.dynamic_data.initial_spawner_count local time = destination.dynamic_data.timer local expected_time = Public.expected_time_on_island() if time > expected_time then return 0 else -- evo it 'would have' contributed: return 1/initial_spawner_count * Public.expected_time_evo() * (expected_time - time)/expected_time end else return 0 end -- return 0.003 * Common.difficulty() end function Public.evolution_per_full_silo_charge() return 0.06 --too low and you always charge immediately, too high and you always charge late end function Public.bonus_damage_to_humans() local ret = 0.125 local diff = Common.difficulty() if diff <= 0.7 then ret = 0.1 end if diff >= 1.3 then ret = 0.15 end return ret end function Public.periodic_free_resources_per_x(x) return { } -- return { -- {name = 'iron-plate', count = Math.ceil(5 * (Common.overworldx()/40)^(2/3))}, -- {name = 'copper-plate', count = Math.ceil(1 * (Common.overworldx()/40)^(2/3))}, -- } end function Public.periodic_free_resources_per_destination_5_seconds(x) return { } -- return { -- {name = 'iron-ore', count = Math.ceil(7 * (Common.overworldx()/40)^(0.6))}, -- {name = 'copper-ore', count = Math.ceil(3 * (Common.overworldx()/40)^(0.6))}, -- } end function Public.class_resource_scale() return 1 / (Public.crew_scale()^(3/5)) end function Public.biter_base_density_scale() local p = Public.crew_scale() if p >= 1 then return p^(1/2) else return Math.max((p*10/6)^(1/2), 0.6) end end function Public.launch_fuel_reward() return Math.ceil(1000 * (1 + 0.1 * (Common.overworldx()/40)^(8/10)) / Math.sloped(Common.difficulty(), 1/4)) end function Public.quest_reward_multiplier() return (0.4 + 0.08 * (Common.overworldx()/40)^(8/10)) * Math.sloped(Common.difficulty(), 1/3) * (Public.crew_scale())^(1/8) end function Public.island_richness_avg_multiplier() return 0.7 + 0.1 * (Common.overworldx()/40)^(7/10) end --tuned tbh function Public.resource_quest_multiplier() return (1.0 + 0.075 * (Common.overworldx()/40)^(8/10)) * Math.sloped(Common.difficulty(), 1/3) * (Public.crew_scale())^(1/8) end function Public.apply_crew_buffs_per_x(force) force.laboratory_productivity_bonus = Math.max(0, 10/100 * (Common.overworldx()/40) - (10*(Common.difficulty()) - 5)) --difficulty causes lab productivity boosts to start later end function Public.class_cost() return 9000 -- return Math.ceil(10000 / (Public.crew_scale()*10/4)^(1/6)) end Public.covered_first_appears_at = 40 Public.silo_max_hp = 8000 function Public.pistol_damage_multiplier() return 2.05 end Public.kraken_spawns_base_extra_evo = 0.30 function Public.kraken_evo_increase_per_shot() return 1/100 * 0.05 --started off low, currently slowly upping to see end function Public.kraken_kill_reward() return {{name = 'sulfuric-acid-barrel', count = 5}} end function Public.kraken_health() return Math.ceil(3000 * Math.max(1, 1 + 0.1 * ((Common.overworldx()/40)^(13/10)-6)) * (Public.crew_scale()^(5/8)) * Math.sloped(Common.difficulty(), 3/4)) end Public.kraken_regen_scale = 0.1 --starting off low function Public.krakens_per_slot(overworldx) local rng = Math.random() if rng < 0.03 then return 2 elseif rng < 0.25 then return 1 else return 0 end end function Public.krakens_per_free_slot(overworldx) local rng = Math.random() local multiplier = 1 if overworldx and overworldx > 600 then multiplier = 1 + (overworldx-600)/600 end if rng < 0.075 * multiplier then return 2 elseif rng < 0.5 * multiplier then return 1 else return 0 end end function Public.main_shop_cost_multiplier() return 1 end function Public.covered_entry_price_scale() return 0.9 * (1 + 0.025 * (Common.overworldx()/40 - 1)) * ((1 + Public.crew_scale())^(1/3)) * Math.sloped(Common.difficulty(), 1/2) --whilst resource scales tend to be held fixed with crew size, we account slightly for the fact that more players tend to handcraft more end function Public.barter_decay_parameter() return 0.95 end function Public.sandworm_speed() return 6.4 * Math.sloped(Common.difficulty(), 1/5) end -- function Public.island_otherresources_prospect_decay_parameter() -- return 0.95 -- end Public.research_buffs = { -- these already give .1 productivity so we're adding .1 to get to 20% ['mining-productivity-1'] = {['mining-drill-productivity-bonus'] = .1}, ['mining-productivity-2'] = {['mining-drill-productivity-bonus'] = .1}, ['mining-productivity-3'] = {['mining-drill-productivity-bonus'] = .1}, ['mining-productivity-4'] = {['mining-drill-productivity-bonus'] = .1}, -- -- these already give .1 productivity so we're adding .1 to get to 20% -- ['mining-productivity-1'] = {['mining-drill-productivity-bonus'] = .1, ['character-inventory-slots-bonus'] = 5}, -- ['mining-productivity-2'] = {['mining-drill-productivity-bonus'] = .1, ['character-inventory-slots-bonus'] = 5}, -- ['mining-productivity-3'] = {['mining-drill-productivity-bonus'] = .1, ['character-inventory-slots-bonus'] = 5}, -- ['mining-productivity-4'] = {['mining-drill-productivity-bonus'] = .1, ['character-inventory-slots-bonus'] = 5}, } -- function Public.flamers_nerfs_size(jumps) return 0.02 * jumps * difficulty_sloped(1/2) end function Public.player_ammo_damage_modifiers() -- modifiers are fractional. bullet affects gun turrets, but flamethrower does not affect flamer turrets local data = { ['artillery-shell'] = 0, ['biological'] = 0, ['bullet'] = 0.1, ['cannon-shell'] = 0, ['capsule'] = 0, ['electric'] = 0, ['flamethrower'] = 0, --these nerfs are elsewhere for finer control ['grenade'] = -0.05, ['landmine'] = 0, ['melee'] = 0, -- doesn't do anything apparently ['rocket'] = 0, ['shotgun-shell'] = 0 } return data end function Public.player_turret_attack_modifiers() local data = { ['gun-turret'] = 0, ['artillery-turret'] = 0, ['laser-turret'] = 0, } return data end function Public.player_gun_speed_modifiers() local data = { ['artillery-shell'] = 0, ['biological'] = 0, ['bullet'] = 0, ['cannon-shell'] = 0, ['capsule'] = 0, ['electric'] = 0, ['flamethrower'] = 0, --these nerfs are elsewhere for finer control ['grenade'] = -0.25, ['landmine'] = 0, ['melee'] = 0, -- doesn't do anything ['rocket'] = 0, ['shotgun-shell'] = 0.1 } return data end Public.starting_items_player = {['pistol'] = 1, ['firearm-magazine'] = 12, ['raw-fish'] = 1, ['iron-plate'] = 12, ['medium-electric-pole'] = 4} Public.starting_items_player_late = {['pistol'] = 1, ['firearm-magazine'] = 5} function Public.starting_items_crew_upstairs() return { {['steel-plate'] = 38}, {['stone-brick'] = 60}, {['grenade'] = 3}, {['shotgun'] = 2, ['shotgun-shell'] = 36}, {['raw-fish'] = 5}, {['coin'] = 1000}, } end function Public.starting_items_crew_downstairs() return { {['transport-belt'] = Math.random(600,650)}, {['underground-belt'] = 80}, {['splitter'] = Math.random(50,56)}, {['inserter'] = Math.random(120,140)}, {['storage-tank'] = 4}, {['medium-electric-pole'] = Math.random(15,21)}, {['coin'] = 2000}, {['solar-panel'] = 4}, } end Public.covered1_entry_price_data_raw = { --watch out that the raw_materials chest can only hold e.g. 4.8 iron-plates -- choose things that are easy to make at outposts {1, 0, 1, false, { price = {name = 'iron-stick', count = 1500}, raw_materials = {{name = 'iron-plate', count = 750}}}, {}}, {0.8, 0, 1, false, { price = {name = 'copper-cable', count = 1500}, raw_materials = {{name = 'copper-plate', count = 750}}}, {}}, {1, 0, 0.3, true, { price = {name = 'small-electric-pole', count = 450}, raw_materials = {{name = 'copper-plate', count = 900}}}, {}}, {1, 0.1, 1, false, { price = {name = 'assembling-machine-1', count = 80}, raw_materials = {{name = 'iron-plate', count = 1760}, {name = 'copper-plate', count = 360}}}, {}}, {1, 0, 0.2, false, { price = {name = 'burner-mining-drill', count = 150}, raw_materials = {{name = 'iron-plate', count = 1350}}}, {}}, {0.5, 0, 0.6, false, { price = {name = 'burner-inserter', count = 300}, raw_materials = {{name = 'iron-plate', count = 900}}}, {}}, {1, 0.1, 0.7, false, { price = {name = 'electronic-circuit', count = 800}, raw_materials = {{name = 'iron-plate', count = 800}, {name = 'copper-plate', count = 1200}}}, {}}, {1, 0, 1, false, { price = {name = 'firearm-magazine', count = 500}, raw_materials = {{name = 'iron-plate', count = 2000}}}, {}}, {1, 0.1, 1, false, { price = {name = 'stone-furnace', count = 400}, raw_materials = {}}, {}}, {1, 0.5, 1, false, { price = {name = 'advanced-circuit', count = 100}, raw_materials = {{name = 'iron-plate', count = 200}, {name = 'copper-plate', count = 500}, {name = 'plastic-bar', count = 200}}}, {}}, {1, -1, 1, true, { price = {name = 'wooden-chest', count = 400}, raw_materials = {}}, {}}, {1, 0, 1, true, { price = {name = 'iron-chest', count = 300}, raw_materials = {{name = 'iron-plate', count = 2400}}}, {}}, {1, 0.2, 1.8, true, { price = {name = 'steel-chest', count = 150}, raw_materials = {{name = 'steel-plate', count = 1200}}}, {}}, } function Public.covered1_entry_price_data() local ret = {} local data = Public.covered1_entry_price_data_raw for i = 1, #data do local data_item = data[i] ret[#ret + 1] = { weight = data_item[1], game_completion_progress_min = data_item[2], game_completion_progress_max = data_item[3], scaling = data_item[4], item = data_item[5], map_subtypes = data_item[6], } end return ret end function Public.covered1_entry_price() local rng = Math.random() local memory = Memory.get_crew_memory() local overworldx = memory.overworldx or 0 local game_completion_progress = Math.min(Math.sloped(Common.difficulty(),1/2) * Common.game_completion_progress(), 1) local data = Public.covered1_entry_price_data() local types, weights = {}, {} for i = 1, #data, 1 do table.insert(types, data[i].item) local destination = Common.current_destination() if not (data[i].map_subtypes and #data[i].map_subtypes > 0 and destination and destination.subtype and data[i].map_subtypes and (not Utils.contains(data[i].map_subtypes, destination.subtype))) then if data[i].scaling then -- scale down weights away from the midpoint 'peak' (without changing the mean) local midpoint = (data[i].game_completion_progress_max + data[i].game_completion_progress_min) / 2 local difference = (data[i].game_completion_progress_max - data[i].game_completion_progress_min) table.insert(weights, data[i].weight * Math.max(0, 1 - (Math.abs(game_completion_progress - midpoint) / (difference / 2)))) else -- no scaling if data[i].game_completion_progress_min <= game_completion_progress and data[i].game_completion_progress_max >= game_completion_progress then table.insert(weights, data[i].weight) else table.insert(weights, 0) end end end end local res = Utils.deepcopy(Math.raffle(types, weights)) res.price.count = Math.ceil(res.price.count * Public.covered_entry_price_scale()) for i, _ in pairs(res.raw_materials) do res.raw_materials[i].count = Math.ceil(res.raw_materials[i].count * Public.covered_entry_price_scale()) end return res end return Public