-- This file is part of thesixthroc's Pirate Ship softmod, licensed under GPLv3 and stored at https://github.com/ComfyFactory/ComfyFactorio and https://github.com/danielmartin0/ComfyFactorio-Pirates. local Balance = require 'maps.pirates.balance' -- local Memory = require 'maps.pirates.memory' local Math = require 'maps.pirates.math' local Raffle = require 'maps.pirates.raffle' local CoreData = require 'maps.pirates.coredata' local _inspect = require 'utils.inspect'.inspect local Common = require 'maps.pirates.common' local Utils = require 'maps.pirates.utils_local' local simplex_noise = require 'utils.simplex_noise'.d2 -- local CustomEvents = require 'maps.pirates.custom_events' local Public = {} -- Gives less and less ore with every call, until given amount slowly converges to 2 -- For now used just for Cave island to give players ore when mining rocks -- NOTE: Also gives some coins function Public.try_give_ore(player, realp, source_name) local destination = Common.current_destination() local choices = destination.dynamic_data.hidden_ore_remaining_abstract if choices and Utils.length(choices) > 0 then local choices_possible = {} local choices_to_prioitise = {} local total_ore_left = 0 for k, v in pairs(choices) do if v>0 then choices_possible[k] = v end total_ore_left = total_ore_left + v if (not destination.dynamic_data.ore_types_spawned[k]) then choices_to_prioitise[#choices_to_prioitise + 1] = k end end if Utils.length(choices_possible) > 0 then local choice if Utils.length(choices_to_prioitise) > 0 then choice = choices_to_prioitise[Math.random(Utils.length(choices_to_prioitise))] else choice = Raffle.raffle2(choices_possible) end if not choice then return end local coin_amount = Math.ceil(0.15 * Balance.coin_amount_from_rock()) local real_amount = Common.ore_abstract_to_real(choices[choice]) local given_amount = Math.ceil(real_amount * Math.random_float_in_range(0.004, 0.006)) if source_name == 'rock-huge' then given_amount = given_amount * 2 coin_amount = coin_amount * 2 end given_amount = Math.max(8 * Balance.game_resources_scale(), given_amount) local to_give = {} to_give[#to_give+1] = {name = choice, count = Math.ceil(given_amount)} to_give[#to_give+1] = {name = 'coin', count = Math.ceil(coin_amount)} Common.give(player, to_give, realp) -- 1 here indicates that ore type should still be given choices[choice] = Math.max(1, choices[choice] - Common.ore_real_to_abstract(given_amount)) end end end function Public.try_ore_spawn(surface, realp, source_name, density_bonus, from_tree) density_bonus = density_bonus or 0 from_tree = from_tree or false -- local memory = Memory.get_crew_memory() local destination = Common.current_destination() local choices = destination.dynamic_data.hidden_ore_remaining_abstract if from_tree then choices = destination.static_params.abstract_ore_amounts end local ret = false if choices and Utils.length(choices) > 0 then local choices_possible = {} local choices_to_prioitise = {} for k, v in pairs(choices) do if v>0 then choices_possible[k] = v end if (not destination.dynamic_data.ore_types_spawned[k]) then choices_to_prioitise[#choices_to_prioitise + 1] = k end end if Utils.length(choices_possible) > 0 then local choice if Utils.length(choices_to_prioitise) > 0 then choice = choices_to_prioitise[Math.random(Utils.length(choices_to_prioitise))] else choice = Raffle.raffle2(choices_possible) end local placed if choice == 'crude-oil' then placed = Common.oil_abstract_to_real(6 + 0.7*choices[choice]/(Math.max(1, Math.ceil((choices[choice]/4)^(1/2))))) * (0.8 + 0.4 * Math.random()) --thesixthroc's magic function, just plot this to see that it makes sense placed = Math.min(placed, Common.oil_abstract_to_real(choices[choice])) local tile = surface.get_tile(realp) if (not (tile and tile.name and Utils.contains(CoreData.tiles_that_conflict_with_resource_layer_extended, tile.name))) then surface.create_entity{name = 'crude-oil', amount = placed, position = realp} else placed = 0 end if placed then choices[choice] = Math.max(0, choices[choice] - Common.oil_real_to_abstract(placed)) if placed > 0 and not destination.dynamic_data.ore_types_spawned[choice] then destination.dynamic_data.ore_types_spawned[choice] = true end ret = true end else if not choice then return false end local real_amount = Common.ore_abstract_to_real(choices[choice]) if from_tree then real_amount = Math.ceil(real_amount * 0.1) end real_amount = Math.max(Common.minimum_ore_placed_per_tile, real_amount) local density = (density_bonus + 17 + 4 * Math.random()) -- not too big, and not too much variation; it makes players have to stay longer local radius_squared = (destination.static_params and destination.static_params.radius_squared_modifier or 1) * (12 + 45 * Math.slopefromto(Common.ore_abstract_to_real(choices[choice]), 800, 20000)) * (0.6 + Math.random()) --tuned if source_name == 'rock-huge' then radius_squared = radius_squared * 1.5 end placed = Public.draw_noisy_ore_patch(surface, realp, choice, real_amount, radius_squared, density) if placed then choices[choice] = Math.max(0, choices[choice] - Common.ore_real_to_abstract(placed)) if placed > 0 and not destination.dynamic_data.ore_types_spawned[choice] then destination.dynamic_data.ore_types_spawned[choice] = true end ret = true end end end end -- script.raise_event(CustomEvents.enum['update_crew_progress_gui'], {}) return ret end function Public.draw_noisy_ore_patch(surface, position, name, budget, radius_squared, density, forced, flat) flat = flat or false budget = budget or 999999999 forced = forced or false local amountplaced = 0 local radius = Math.sqrt(radius_squared) position = {x = Math.ceil(position.x) - 0.5, y = Math.ceil(position.y) - 0.5} if not position then return 0 end if not name then return 0 end if not surface then return 0 end if not radius then return 0 end if not density then return 0 end local mixed_ore_raffle = { 'iron-ore', 'iron-ore', 'iron-ore', 'copper-ore', 'copper-ore', 'coal', 'stone' } local seed = surface.map_gen_settings.seed local function try_draw_at_relative_position(x, y, strength) local absx = x + position.x local absy = y + position.y local absp = {x = absx, y = absy} local amount_to_place_here = Math.min(density * strength, budget - amountplaced) if amount_to_place_here >= Common.minimum_ore_placed_per_tile then if name == 'mixed' then local noise = simplex_noise(x * 0.005, y * 0.005, seed) + simplex_noise(x * 0.01, y * 0.01, seed) * 0.3 + simplex_noise(x * 0.05, y * 0.05, seed) * 0.2 local i = (Math.floor(noise * 100) % #mixed_ore_raffle) + 1 name = mixed_ore_raffle[i] end local entity = {name = name, position = absp, amount = amount_to_place_here} -- local area = {{absx - 0.05, absy - 0.05}, {absx + 0.05, absy + 0.05}} local area2 = {{absx - 0.1, absy - 0.1}, {absx + 0.1, absy + 0.1}} local area3 = {{absx - 2, absy - 2}, {absx + 2, absy + 2}} local preexisting_ores = surface.find_entities_filtered{area = area2, type = 'resource'} local added if #preexisting_ores >= 1 then local addedbool = false for _, ore in pairs(preexisting_ores) do if ore.name == name then ore.amount = ore.amount + amount_to_place_here amountplaced = amountplaced + amount_to_place_here addedbool = true break end end if not addedbool then added = surface.create_entity(entity) end else local tile = surface.get_tile(absp) local silos = surface.find_entities_filtered{area=area3, name='rocket-silo'} if #silos == 0 and (not (tile and tile.name and Utils.contains(CoreData.tiles_that_conflict_with_resource_layer_extended, tile.name))) then if forced then surface.destroy_decoratives{area = area2} for _, tree in pairs(surface.find_entities_filtered{area=area2, type='tree'}) do tree.destroy() end added = surface.create_entity(entity) else local pos2 = surface.find_non_colliding_position(name, absp, 10, 1, true) pos2 = pos2 or absp entity = {name = name, position = pos2, amount = amount_to_place_here} surface.destroy_decoratives{area = area2} if pos2 and surface.can_place_entity(entity) then added = surface.create_entity(entity) end end end end if added and added.valid then amountplaced = amountplaced + amount_to_place_here end end end for _, p in ipairs(Math.points_in_m20t20_squared_sorted_by_distance_to_origin) do local x, y = p[1], p[2] local distance_to_center = Math.sqrt(x^2 + y^2) local noise if flat then noise = 0.99 * simplex_noise((position.x + x) * 1/3, (position.y + y) * 1/3, seed) * simplex_noise((position.x + x) * 1/9, (position.y + y) * 1/9, seed+100) else --put noise on the unit circle if distance_to_center > 0 then noise = 0.99 * simplex_noise((position.x + x/distance_to_center) * 1/3, (position.y + y/distance_to_center) * 1/3, seed) * simplex_noise((position.x + x/distance_to_center) * 1/9, (position.y + y/distance_to_center) * 1/9, seed+100) else noise = 0.99 * simplex_noise((position.x) * 1/3, (position.y) * 1/3, seed) * simplex_noise((position.x) * 1/9, (position.y) * 1/9, seed+100) end end local radius_noisy = radius * (1 + noise) if distance_to_center < radius_noisy then local strength if flat then -- if noise > -0.5 then strength = 1 else strength = 0 end -- its hard to make it both noncircular and flat in per-tile count strength = 1 else strength = (3/2) * (1 - (distance_to_center/radius_noisy)^2) end try_draw_at_relative_position(x, y, strength) end if amountplaced >= budget then break end end return amountplaced end return Public