2024-09-10 12:29:44 +02:00
-- 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.
2021-10-13 10:21:53 +02:00
2023-01-29 23:01:48 +02:00
local Balance = require ' maps.pirates.balance '
2022-03-19 23:20:55 +02:00
-- local Memory = require 'maps.pirates.memory'
2021-10-13 10:21:53 +02:00
local Math = require ' maps.pirates.math '
2022-05-14 00:35:12 +02:00
local Raffle = require ' maps.pirates.raffle '
2021-10-13 10:21:53 +02:00
local CoreData = require ' maps.pirates.coredata '
2022-03-19 23:20:55 +02:00
local _inspect = require ' utils.inspect ' . inspect
2021-10-13 10:21:53 +02:00
local Common = require ' maps.pirates.common '
local Utils = require ' maps.pirates.utils_local '
local simplex_noise = require ' utils.simplex_noise ' . d2
2022-03-19 23:20:55 +02:00
-- local CustomEvents = require 'maps.pirates.custom_events'
2022-03-13 03:44:32 +02:00
2021-10-13 10:21:53 +02:00
local Public = { }
2022-11-18 22:18:16 +02:00
-- Gives less and less ore with every call, until given amount slowly converges to 2
2022-10-02 23:37:54 +02:00
-- 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
2023-02-19 22:42:07 +02:00
local coin_amount = Math.ceil ( 0.15 * Balance.coin_amount_from_rock ( ) )
2022-11-18 22:18:16 +02:00
local real_amount = Common.ore_abstract_to_real ( choices [ choice ] )
2022-10-02 23:37:54 +02:00
local given_amount = Math.ceil ( real_amount * Math.random_float_in_range ( 0.004 , 0.006 ) )
if source_name == ' rock-huge ' then
2022-11-18 22:18:16 +02:00
given_amount = given_amount * 2
2022-10-02 23:37:54 +02:00
coin_amount = coin_amount * 2
end
2024-09-09 16:39:26 +02:00
given_amount = Math.max ( 8 * Balance.game_resources_scale ( ) , given_amount )
2022-11-18 22:18:16 +02:00
2022-10-02 23:37:54 +02:00
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 )
2021-10-13 10:21:53 +02:00
2022-11-18 22:18:16 +02:00
-- 1 here indicates that ore type should still be given
choices [ choice ] = Math.max ( 1 , choices [ choice ] - Common.ore_real_to_abstract ( given_amount ) )
2022-10-02 23:37:54 +02:00
end
end
end
2021-10-13 10:21:53 +02:00
2023-01-30 17:19:45 +02:00
function Public . try_ore_spawn ( surface , realp , source_name , density_bonus , from_tree )
2021-10-13 10:21:53 +02:00
density_bonus = density_bonus or 0
2023-01-30 17:19:45 +02:00
from_tree = from_tree or false
2022-03-19 23:20:55 +02:00
-- local memory = Memory.get_crew_memory()
2021-10-13 10:21:53 +02:00
local destination = Common.current_destination ( )
local choices = destination.dynamic_data . hidden_ore_remaining_abstract
2023-01-30 17:19:45 +02:00
if from_tree then
choices = destination.static_params . abstract_ore_amounts
end
2022-03-13 03:44:32 +02:00
local ret = false
2021-10-13 10:21:53 +02:00
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
2022-05-14 00:35:12 +02:00
choice = Raffle.raffle2 ( choices_possible )
2021-10-13 10:21:53 +02:00
end
local placed
if choice == ' crude-oil ' then
2022-03-17 03:40:18 +02:00
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
2021-10-13 10:21:53 +02:00
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
2022-02-28 18:36:46 +02:00
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
2022-03-13 03:44:32 +02:00
ret = true
2022-02-28 18:36:46 +02:00
end
2021-10-13 10:21:53 +02:00
else
2022-10-04 20:28:35 +02:00
if not choice then return false end
2023-01-30 17:19:45 +02:00
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 )
2021-10-13 10:21:53 +02:00
2022-02-24 21:39:03 +02:00
local density = ( density_bonus + 17 + 4 * Math.random ( ) ) -- not too big, and not too much variation; it makes players have to stay longer
2022-03-19 23:20:55 +02:00
2022-03-01 17:57:23 +02:00
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
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
if source_name == ' rock-huge ' then
radius_squared = radius_squared * 1.5
end
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
placed = Public.draw_noisy_ore_patch ( surface , realp , choice , real_amount , radius_squared , density )
2022-03-19 23:20:55 +02:00
2022-02-28 18:36:46 +02:00
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
2022-03-13 03:44:32 +02:00
ret = true
2021-10-13 10:21:53 +02:00
end
end
end
end
2022-03-13 03:44:32 +02:00
-- script.raise_event(CustomEvents.enum['update_crew_progress_gui'], {})
return ret
2021-10-13 10:21:53 +02:00
end
function Public . draw_noisy_ore_patch ( surface , position , name , budget , radius_squared , density , forced , flat )
2021-10-14 11:23:34 +02:00
flat = flat or false
2021-10-13 10:21:53 +02:00
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 }
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
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
2022-02-27 18:42:25 +02:00
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 )
2021-10-13 10:21:53 +02:00
local noise
2022-02-27 18:42:25 +02:00
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
2021-10-13 10:21:53 +02:00
end
local radius_noisy = radius * ( 1 + noise )
if distance_to_center < radius_noisy then
local strength
if flat then
2022-02-27 18:42:25 +02:00
-- if noise > -0.5 then strength = 1 else strength = 0 end
-- its hard to make it both noncircular and flat in per-tile count
2021-10-13 10:21:53 +02:00
strength = 1
else
strength = ( 3 / 2 ) * ( 1 - ( distance_to_center / radius_noisy ) ^ 2 )
end
2022-02-27 18:42:25 +02:00
try_draw_at_relative_position ( x , y , strength )
2021-10-13 10:21:53 +02:00
end
2022-02-27 18:42:25 +02:00
if amountplaced >= budget then break end
2021-10-13 10:21:53 +02:00
end
return amountplaced
end
return Public