2021-10-13 10:21:53 +02:00
local Memory = require ' maps.pirates.memory '
2022-03-19 23:20:55 +02:00
-- local Roles = require 'maps.pirates.roles.roles'
2021-10-13 10:21:53 +02:00
local Balance = require ' maps.pirates.balance '
local Common = require ' maps.pirates.common '
2022-03-19 23:20:55 +02:00
-- local Utils = require 'maps.pirates.utils_local'
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 '
2022-03-19 23:20:55 +02:00
-- local Loot = require 'maps.pirates.loot'
2022-03-15 20:50:19 +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 Public = { }
local enum = {
TIME = ' Time ' ,
FIND = ' Find ' ,
NODAMAGE = ' No_Damage ' ,
RESOURCEFLOW = ' Resource_Flow ' ,
RESOURCECOUNT = ' Resource_Count ' ,
WORMS = ' Worms ' ,
2022-03-19 23:20:55 +02:00
}
2021-10-13 10:21:53 +02:00
Public.enum = enum
Public.quest_icons = {
[ enum.TIME ] = ' [img=utility.time_editor_icon] ' ,
[ enum.NODAMAGE ] = ' [item=stone-wall] ' ,
[ enum.WORMS ] = ' [entity=small-worm-turret] ' ,
[ enum.FIND ] = ' [img=utility.ghost_time_to_live_modifier_icon] ' ,
[ enum.RESOURCEFLOW ] = ' ' ,
[ enum.RESOURCECOUNT ] = ' ' ,
}
2022-03-13 20:19:59 +02:00
-- @TODO remake into a loot-style table:
2021-10-13 10:21:53 +02:00
function Public . quest_reward ( )
local ret
local multiplier = Balance.quest_reward_multiplier ( )
local rng = Math.random ( )
if rng <= 0.3 then
2022-03-16 17:01:50 +02:00
ret = { name = ' iron-plate ' , count = Math.ceil ( 2000 * multiplier ) , display_sprite = ' [item=iron-plate] ' , display_amount = string.format ( ' %.1fk ' , 2 * multiplier ) , chat_name = ' [item=iron-plate] ' }
2021-10-13 10:21:53 +02:00
elseif rng <= 0.5 then
2022-03-16 17:01:50 +02:00
ret = { name = ' copper-plate ' , count = Math.ceil ( 2000 * multiplier ) , display_sprite = ' [item=copper-plate] ' , display_amount = string.format ( ' %.1fk ' , 2 * multiplier ) , chat_name = ' [item=copper-plate] ' }
2022-05-06 14:00:57 +02:00
elseif rng <= 0.6 then
2022-04-30 04:15:50 +02:00
ret = { name = ' steel-plate ' , count = Math.ceil ( 380 * multiplier ) , display_sprite = ' [item=steel-plate] ' , display_amount = string.format ( ' %.0f ' , 380 * multiplier ) , chat_name = ' [item=steel-plate] ' }
2022-05-06 14:00:57 +02:00
elseif rng <= 0.7 then
2022-05-07 22:41:45 +02:00
ret = { name = ' raw-fish ' , count = Math.ceil ( 420 * ( multiplier ^ ( 1 / 2 ) ) ) , display_sprite = ' [item=raw-fish] ' , display_amount = string.format ( ' %.1fk ' , 0.42 * ( multiplier ^ ( 1 / 2 ) ) ) , chat_name = ' [item=raw-fish] ' }
2022-05-06 14:00:57 +02:00
elseif rng <= 0.85 then
ret = { name = ' piercing-rounds-magazine ' , count = Math.ceil ( 250 * multiplier ) , display_sprite = ' [item=piercing-rounds-magazine] ' , display_amount = string.format ( ' %.0f ' , Math.ceil ( 250 * multiplier ) ) , chat_name = ' [item=piercing-rounds-magazine] ' }
2022-05-07 22:41:45 +02:00
elseif rng <= 0.94 then
2022-05-06 14:00:57 +02:00
ret = { name = ' solid-fuel ' , count = Math.ceil ( 450 * multiplier ) , display_sprite = ' [item=solid-fuel] ' , display_amount = string.format ( ' %.0f ' , Math.ceil ( 450 * multiplier ) ) , chat_name = ' [item=solid-fuel] ' }
2021-10-13 10:21:53 +02:00
else
2022-05-06 02:47:27 +02:00
ret = { name = ' modular-armor ' , count = 1 , display_sprite = ' [item=modular-armor] ' , display_amount = ' 1 ' , chat_name = ' [item=modular-armor] ' }
2021-10-13 10:21:53 +02:00
end
return ret
end
function Public . initialise_random_quest ( )
local destination = Common.current_destination ( )
destination.dynamic_data . quest_complete = false
if destination.destination_index == 2 then return end
2022-05-07 22:41:45 +02:00
local rng = Math.random ( 100 )
if rng <= 10 then
2021-10-13 10:21:53 +02:00
Public.initialise_nodamage_quest ( )
2022-05-07 22:41:45 +02:00
elseif rng <= 33 then
2021-10-13 10:21:53 +02:00
Public.initialise_worms_quest ( )
2022-05-07 22:41:45 +02:00
elseif rng <= 54 then
2021-10-13 10:21:53 +02:00
Public.initialise_time_quest ( )
2022-05-07 22:41:45 +02:00
elseif rng <= 74 then
2021-10-13 10:21:53 +02:00
Public.initialise_find_quest ( )
2022-05-07 22:41:45 +02:00
elseif rng <= 100 then
2021-10-13 10:21:53 +02:00
Public.initialise_resourcecount_quest ( )
-- Public.initialise_resourceflow_quest()
end
-- Public.initialise_time_quest()
end
function Public . initialise_time_quest ( )
local destination = Common.current_destination ( )
destination.dynamic_data . quest_type = enum.TIME
destination.dynamic_data . quest_reward = Public.quest_reward ( )
destination.dynamic_data . quest_progress = Balance.time_quest_seconds ( )
destination.dynamic_data . quest_progressneeded = 9999999
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
return true
end
function Public . initialise_find_quest ( )
local destination = Common.current_destination ( )
-- @FIXME: Magic numbers
if destination.subtype and destination.subtype == ' 1 ' or destination.subtype == ' 5 ' or destination.subtype == ' 6 ' then
destination.dynamic_data . quest_type = enum.FIND
destination.dynamic_data . quest_reward = Public.quest_reward ( )
destination.dynamic_data . quest_progress = 0
2022-02-24 21:39:03 +02:00
if # Common.crew_get_crew_members ( ) > 15 then
destination.dynamic_data . quest_progressneeded = 2
else
destination.dynamic_data . quest_progressneeded = 1
end
2021-10-13 10:21:53 +02:00
return true
else
2022-03-12 00:53:36 +02:00
log ( ' Find quest not appropriate, rerolling ' )
2021-10-13 10:21:53 +02:00
Public.initialise_random_quest ( ) --@FIXME: mild danger of loop
return false
end
end
function Public . initialise_nodamage_quest ( )
local destination = Common.current_destination ( )
if not destination and destination.dynamic_data and destination.dynamic_data . rocketsilomaxhp then return end
destination.dynamic_data . quest_type = enum.NODAMAGE
destination.dynamic_data . quest_reward = Public.quest_reward ( )
destination.dynamic_data . quest_progress = 0
destination.dynamic_data . quest_progressneeded = destination.dynamic_data . rocketsilomaxhp
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
return true
end
function Public . initialise_resourceflow_quest ( )
local destination = Common.current_destination ( )
if not destination and destination.dynamic_data and destination.dynamic_data . rocketsilomaxhp then return end
destination.dynamic_data . quest_type = enum.RESOURCEFLOW
destination.dynamic_data . quest_reward = Public.quest_reward ( )
destination.dynamic_data . quest_progress = 0
local generated_flow_quest = Public.generate_flow_quest ( )
destination.dynamic_data . quest_params = { item = generated_flow_quest.item }
local progressneeded_before_rounding = generated_flow_quest.base_rate * Balance.resource_quest_multiplier ( )
destination.dynamic_data . quest_progressneeded = Math.ceil ( progressneeded_before_rounding / 10 ) * 10
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
return true
end
function Public . initialise_resourcecount_quest ( )
local memory = Memory.get_crew_memory ( )
local destination = Common.current_destination ( )
if not destination and destination.dynamic_data and destination.dynamic_data . rocketsilomaxhp then return end
destination.dynamic_data . quest_type = enum.RESOURCECOUNT
destination.dynamic_data . quest_reward = Public.quest_reward ( )
destination.dynamic_data . quest_progress = 0
local generated_production_quest = Public.generate_resourcecount_quest ( )
destination.dynamic_data . quest_params = { item = generated_production_quest.item }
2022-03-04 19:57:58 +02:00
local force = memory.force
2021-10-13 10:21:53 +02:00
if force and force.valid then
destination.dynamic_data . quest_params.initial_count = force.item_production_statistics . get_flow_count { name = generated_production_quest.item , input = true , precision_index = defines.flow_precision_index . one_thousand_hours , count = true }
end
2022-05-03 14:52:21 +02:00
local progressneeded_before_rounding = generated_production_quest.base_rate * Balance.resource_quest_multiplier ( ) * Common.difficulty_scale ( )
2021-10-13 10:21:53 +02:00
destination.dynamic_data . quest_progressneeded = Math.ceil ( progressneeded_before_rounding / 10 ) * 10
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
return true
end
function Public . initialise_worms_quest ( )
local destination = Common.current_destination ( )
if not ( destination.surface_name and game.surfaces [ destination.surface_name ] ) then return end
local surface = game.surfaces [ destination.surface_name ]
local worms = surface.find_entities_filtered { type = ' turret ' }
local count = 0
for i = 1 , # worms do
local w = worms [ i ]
if w.destructible then count = count + 1 end
end
local needed = Math.ceil (
1 + 9 * Math.slopefromto ( count , 0 , 20 ) + 10 * Math.slopefromto ( count , 20 , 70 )
)
2022-05-03 14:52:21 +02:00
if Common.difficulty_scale ( ) < 1 then needed = Math.max ( 1 , needed - 3 ) end
if Common.difficulty_scale ( ) > 1 then needed = Math.max ( 1 , needed + 2 ) end
2021-10-13 10:21:53 +02:00
2022-05-03 14:52:21 +02:00
local difficulty_name = CoreData.get_difficulty_name_from_value ( Common.difficulty_scale ( ) )
2022-03-15 20:50:19 +02:00
if difficulty_name == CoreData.difficulty_options [ 1 ] . text then
needed = Math.max ( 1 , needed - 3 )
elseif difficulty_name ~= CoreData.difficulty_options [ 2 ] . text then
needed = Math.max ( 1 , needed + 2 )
end
2021-10-13 10:21:53 +02:00
if needed >= 5 then
destination.dynamic_data . quest_type = enum.WORMS
destination.dynamic_data . quest_reward = Public.quest_reward ( )
destination.dynamic_data . quest_progress = 0
destination.dynamic_data . quest_progressneeded = needed
return true
else
2022-03-12 00:53:36 +02:00
log ( ' Worms quest not appropriate, rerolling ' )
2021-10-13 10:21:53 +02:00
Public.initialise_random_quest ( ) --@FIXME: mild danger of loop
return false
end
end
function Public . try_resolve_quest ( )
local memory = Memory.get_crew_memory ( )
local destination = Common.current_destination ( )
if destination.dynamic_data . quest_type and destination.dynamic_data . quest_progress and destination.dynamic_data . quest_progressneeded and destination.dynamic_data . quest_progress >= destination.dynamic_data . quest_progressneeded and ( not destination.dynamic_data . quest_complete ) then
2022-03-04 19:57:58 +02:00
local force = memory.force
2021-10-13 10:21:53 +02:00
if not ( force and force.valid ) then return end
2022-05-05 10:55:48 +02:00
Common.notify_force_light ( force , ' Granted: ' .. destination.dynamic_data . quest_reward.display_amount .. ' ' .. destination.dynamic_data . quest_reward.chat_name )
2021-10-13 10:21:53 +02:00
local name = destination.dynamic_data . quest_reward.name
local count = destination.dynamic_data . quest_reward.count
-- destination.dynamic_data.quest_type = nil
-- destination.dynamic_data.quest_reward = nil
-- destination.dynamic_data.quest_progress = nil
-- destination.dynamic_data.quest_progressneeded = nil
destination.dynamic_data . quest_complete = true
local boat = memory.boat
if not boat then return end
local surface_name = boat.surface_name
if not surface_name then return end
local surface = game.surfaces [ surface_name ]
if not ( surface and surface.valid ) then return end
local chest = boat.output_chest
if not chest and chest.valid then return end
local inventory = chest.get_inventory ( defines.inventory . chest )
local inserted = inventory.insert { name = name , count = count }
2022-03-19 23:20:55 +02:00
2021-10-13 10:21:53 +02:00
if inserted < count then
2022-03-14 23:38:44 +02:00
local chest2 = boat.backup_output_chest
if chest2 and chest2.valid then
local inventory2 = chest2.get_inventory ( defines.inventory . chest )
local inserted2 = inventory2.insert { name = name , count = count - inserted }
if ( inserted + inserted2 ) < count then
Common.notify_force ( force , ' Sadly, there wasn \' t space in the cabin for all of your reward. ' )
end
end
2021-10-13 10:21:53 +02:00
end
end
end
-- Public.flow_quest_data_raw = {
-- {0.2, 0, 1, false, 'submachine-gun', 3 * 12},
-- {1, 0, 1, false, 'electronic-circuit', 3 * 120},
-- {0.2, 0.1, 1, false, 'big-electric-pole', 1 * 120},
-- {0.4, 0.2, 1, false, 'engine-unit', 3 * 6},
-- -- {1, 0.5, 1, false, 'advanced-circuit', 1 * 10},
-- -- {0.3, 0.8, 1, false, 'electric-engine-unit', 1 * 6},
-- }
-- function Public.flow_quest_data()
-- local ret = {}
-- local data = Public.flow_quest_data_raw
-- for i = 1, #data do
-- local datum = data[i]
-- ret[#ret + 1] = {
-- weight = datum[1],
-- game_completion_progress_min = datum[2],
-- game_completion_progress_max = datum[3],
-- scaling = datum[4],
-- item = datum[5],
-- base_rate = datum[6],
-- }
-- end
-- return ret
-- end
function Public . generate_flow_quest ( )
2022-05-08 12:06:22 +02:00
--@TODO: Ensure this function cannot return nil
--@TODO: This is related to a more general problem with raffles — how they handle game_completion being above 1. As of May '22, we cap game_completion at 1 before passing it to the raffle
2022-02-28 22:35:45 +02:00
local game_completion_progress = Common.game_completion_progress_capped ( )
2021-10-13 10:21:53 +02:00
local data = Public.flow_quest_data ( )
local v , w = { } , { }
for i = 1 , # data , 1 do
table.insert ( v , { item = data [ i ] . item , base_rate = data [ i ] . base_rate } )
local destination = Common.current_destination ( )
if not ( destination and destination.subtype and data [ i ] . map_subtype and data [ i ] . map_subtype == 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 ( w , 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 ( w , data [ i ] . weight )
else
table.insert ( w , 0 )
end
end
end
end
2022-05-14 00:35:12 +02:00
return Raffle.raffle ( v , w )
2021-10-13 10:21:53 +02:00
end
Public.resourcecount_quest_data_raw = {
2022-05-07 22:41:45 +02:00
{ 1.1 , 0 , 1 , false , ' iron-gear-wheel ' , 2400 } ,
{ 0.5 , 0 , 1 , false , ' electronic-circuit ' , 1400 } ,
{ 1.1 , 0 , 1 , false , ' transport-belt ' , 1600 } ,
{ 0.8 , 0 , 1 , false , ' repair-pack ' , 350 } ,
2021-10-13 10:21:53 +02:00
-- {0.1, 0, 1, false, 'red-wire', 500},
2022-05-07 22:41:45 +02:00
{ 0.4 , 0 , 1 , false , ' empty-barrel ' , 200 } ,
{ 0.7 , 0 , 0.5 , false , ' underground-belt ' , 200 } ,
{ 0.7 , 0 , 0.5 , false , ' splitter ' , 150 } ,
{ 0.35 , 0.2 , 1 , false , ' fast-splitter ' , 60 } ,
{ 0.35 , 0.2 , 1 , false , ' fast-underground-belt ' , 75 } ,
{ 0.7 , 0.3 , 1 , false , ' big-electric-pole ' , 100 } ,
{ 0.3 , 0.61 , 1 , false , ' advanced-circuit ' , 350 } ,
2022-03-13 20:19:59 +02:00
{ 1 , 0 , 1 , false , ' shotgun-shell ' , 600 } ,
2022-05-07 22:41:45 +02:00
{ 1 , 0.9 , 1 , false , ' processing-unit ' , 40 } ,
{ 0.6 , 0.8 , 1 , false , ' electric-engine-unit ' , 1 * 6 } ,
2021-10-13 10:21:53 +02:00
}
function Public . resourcecount_quest_data ( )
local ret = { }
local data = Public.resourcecount_quest_data_raw
for i = 1 , # data do
local datum = data [ i ]
ret [ # ret + 1 ] = {
weight = datum [ 1 ] ,
game_completion_progress_min = datum [ 2 ] ,
game_completion_progress_max = datum [ 3 ] ,
scaling = datum [ 4 ] ,
item = datum [ 5 ] ,
base_rate = datum [ 6 ] ,
}
end
return ret
end
function Public . generate_resourcecount_quest ( )
2022-02-28 22:35:45 +02:00
local game_completion_progress = Common.game_completion_progress_capped ( )
2021-10-13 10:21:53 +02:00
local data = Public.resourcecount_quest_data ( )
local v , w = { } , { }
for i = 1 , # data , 1 do
table.insert ( v , { item = data [ i ] . item , base_rate = data [ i ] . base_rate } )
local destination = Common.current_destination ( )
if not ( destination and destination.subtype and data [ i ] . map_subtype and data [ i ] . map_subtype == 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 ( w , 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 ( w , data [ i ] . weight )
else
table.insert ( w , 0 )
end
end
end
end
2022-05-14 00:35:12 +02:00
return Raffle.raffle ( v , w )
2021-10-13 10:21:53 +02:00
end
return Public