mirror of
https://github.com/ComfyFactory/ComfyFactorio.git
synced 2025-01-06 00:23:49 +02:00
268 lines
10 KiB
Lua
268 lines
10 KiB
Lua
-- 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 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 == 'huge-rock' 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 == 'huge-rock' 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
|
|
|
|
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
|