2022-06-01 19:50:36 +01:00
-- This file is part of thesixthroc's Pirate Ship softmod, licensed under GPLv3 and stored at https://github.com/danielmartin0/ComfyFactorio-Pirates.
2021-10-13 09:21:53 +01:00
local Memory = require ' maps.pirates.memory '
2022-03-19 21:20:55 +00:00
-- local Roles = require 'maps.pirates.roles.roles'
2021-10-13 09:21:53 +01:00
local Classes = require ' maps.pirates.roles.classes '
2022-04-29 23:48:34 +01:00
local Crew = require ' maps.pirates.crew '
2022-03-19 21:20:55 +00:00
-- local Boats = require 'maps.pirates.structures.boats.boats'
-- local Dock = require 'maps.pirates.surfaces.dock'
2021-10-13 09:21:53 +01:00
local Balance = require ' maps.pirates.balance '
local Common = require ' maps.pirates.common '
local Utils = require ' maps.pirates.utils_local '
2022-04-29 23:48:34 +01:00
local Roles = require ' maps.pirates.roles.roles '
2021-10-13 09:21:53 +01:00
local Math = require ' maps.pirates.math '
2022-03-19 21:20:55 +00:00
local _inspect = require ' utils.inspect ' . inspect
2022-02-26 23:33:19 +00:00
local SurfacesCommon = require ' maps.pirates.surfaces.common '
2022-04-29 23:48:34 +01:00
local Upgrades = require ' maps.pirates.boat_upgrades '
2022-03-19 21:20:55 +00:00
-- local Upgrades = require 'maps.pirates.boat_upgrades'
2021-10-13 09:21:53 +01:00
local Public = { }
2022-03-07 18:41:42 +00:00
Public.Captains = require ' maps.pirates.shop.captains '
Public.Covered = require ' maps.pirates.shop.covered '
Public.Merchants = require ' maps.pirates.shop.merchants '
Public.Minimarket = require ' maps.pirates.shop.dock '
2021-10-13 09:21:53 +01:00
2022-05-22 23:39:25 +01:00
function Public . print_transaction ( player , offer_itemname , offer_itemcount , price )
2022-05-29 12:36:27 +01:00
local type = ' traded away '
local s2 = { ' ' }
2022-05-22 23:39:25 +01:00
local s3 = offer_itemcount .. ' ' .. offer_itemname
2022-05-29 12:36:27 +01:00
if offer_itemname == ' coin ' then type = ' sold ' end
2022-05-06 16:16:15 +01:00
for i , p in pairs ( price ) do
local p2 = { name = p.name , amount = p.amount }
if p2.name == ' raw-fish ' then p2.name = ' fish ' end
if p2.name == ' coin ' then
2022-05-29 12:36:27 +01:00
type = ' bought '
2022-05-06 16:16:15 +01:00
p2.name = ' doubloons '
end
if i > 1 then
if i == # price then
2022-05-29 12:36:27 +01:00
s2 [ # s2 + 1 ] = { ' pirates.separator_2 ' }
2022-05-06 16:16:15 +01:00
else
2022-05-29 12:36:27 +01:00
s2 [ # s2 + 1 ] = { ' pirates.separator_1 ' }
2022-05-06 16:16:15 +01:00
end
end
2022-05-29 12:36:27 +01:00
s2 [ # s2 + 1 ] = p2.amount
s2 [ # s2 + 1 ] = ' '
s2 [ # s2 + 1 ] = p2.name
2022-05-06 16:16:15 +01:00
end
2022-05-29 12:36:27 +01:00
if type == ' sold ' then
Common.notify_force_light ( player.force , { ' pirates.market_event_sell ' , player.name , s2 , s3 } )
elseif type == ' traded away ' then
Common.notify_force_light ( player.force , { ' pirates.market_event_trade ' , player.name , s2 , s3 } )
elseif type == ' bought ' then
Common.notify_force_light ( player.force , { ' pirates.market_event_buy ' , player.name , s3 , s2 } )
2022-05-06 16:16:15 +01:00
end
end
2022-05-07 21:56:16 +01:00
local function purchaseData ( market , player , offer_index )
--a proper rewriting of this function would directly check market entities against saved references to them in memory, but we haven't had time to rewrite it yet
2022-05-06 16:16:15 +01:00
2022-02-26 23:33:19 +00:00
local destination = Common.current_destination ( )
2021-10-13 09:21:53 +01:00
local alloffers = market.get_market_items ( )
local this_offer = alloffers [ offer_index ]
local price = this_offer.price
2022-02-26 18:25:48 +00:00
local offer_type = this_offer.offer . type
local offer_giveitem_name , offer_giveitem_count
if offer_type == ' give-item ' then
offer_giveitem_name = this_offer.offer . item
offer_giveitem_count = this_offer.offer . count
end
2022-03-07 18:41:42 +00:00
-- check for BARTER vs STATIC vs ONE-OFF
2022-02-26 23:33:19 +00:00
-- One-off becomes unavailable after purchase, such as class purchase
-- Static doesn't decay
-- Barter decays
local decay_type
2022-03-03 00:19:20 +00:00
local dock_bool = destination.type == SurfacesCommon.enum . DOCK
2022-03-07 18:41:42 +00:00
local island_bool = destination.type == SurfacesCommon.enum . ISLAND
2022-03-03 00:19:20 +00:00
local purchase_bool = ( price and price [ 1 ] and price [ 1 ] . name and ( price [ 1 ] . name == ' coin ' ) )
local simple_efficiency_trade_bool = ( price and price [ 1 ] and price [ 1 ] . name and ( price [ 1 ] . name == ' pistol ' or price [ 1 ] . name == ' burner-mining-drill ' ) )
2022-03-09 21:39:47 +00:00
local special_purchase_bool = ( offer_giveitem_name == ' rocket-launcher ' )
-- local special_purchase_bool = (offer_giveitem_name and (offer_giveitem_name == 'loader' or offer_giveitem_name == 'fast-loader' or offer_giveitem_name == 'express-loader' or offer_giveitem_name == 'rocket-launcher'))
2022-03-03 00:19:20 +00:00
2022-04-29 23:48:34 +01:00
local surface_name_decoded = SurfacesCommon.decode_surface_name ( player.surface . name )
local type = surface_name_decoded.type
local in_captains_cabin = type and type == SurfacesCommon.enum . CABIN
local dock_upgrades_market = destination.dynamic_data . dock_captains_market and ( destination.dynamic_data . dock_captains_market == market )
local permission_level_fail = ( in_captains_cabin and Roles.player_privilege_level ( player ) < Roles.privilege_levels . OFFICER ) or ( dock_upgrades_market and Roles.player_privilege_level ( player ) < Roles.privilege_levels . OFFICER )
if in_captains_cabin then
decay_type = ' static '
2022-05-06 16:16:15 +01:00
elseif offer_type == ' nothing ' or dock_upgrades_market then
2022-02-26 23:33:19 +00:00
decay_type = ' one-off '
2022-04-29 17:43:46 +01:00
elseif simple_efficiency_trade_bool or special_purchase_bool then
decay_type = ' static '
2022-03-03 00:19:20 +00:00
elseif dock_bool and purchase_bool and ( offer_giveitem_name ) and ( offer_giveitem_name == ' stone ' or offer_giveitem_name == ' iron-ore ' or offer_giveitem_name == ' copper-ore ' or offer_giveitem_name == ' crude-oil-barrel ' ) then
2022-03-14 17:37:18 +00:00
decay_type = ' fast_decay '
2022-03-05 19:56:41 +00:00
elseif dock_bool and purchase_bool and ( offer_giveitem_name ) then
decay_type = ' one-off '
2022-03-08 23:36:03 +00:00
elseif island_bool and ( not ( offer_giveitem_name and offer_giveitem_name == ' rocket ' ) ) then
2022-03-07 18:41:42 +00:00
decay_type = ' one-off '
2022-02-26 23:33:19 +00:00
else
decay_type = ' decay '
end
2022-05-07 21:56:16 +01:00
return {
2022-05-22 23:20:30 +01:00
alloffers = alloffers ,
2022-05-07 21:56:16 +01:00
decay_type = decay_type ,
price = price ,
offer_type = offer_type ,
offer_giveitem_name = offer_giveitem_name ,
offer_giveitem_count = offer_giveitem_count ,
dock_bool = dock_bool ,
island_bool = island_bool ,
purchase_bool = purchase_bool ,
simple_efficiency_trade_bool = simple_efficiency_trade_bool ,
special_purchase_bool = special_purchase_bool ,
in_captains_cabin = in_captains_cabin ,
dock_upgrades_market = dock_upgrades_market ,
permission_level_fail = permission_level_fail ,
}
end
function Public . event_on_market_item_purchased ( event )
local player_index , market , offer_index , trade_count = event.player_index , event.market , event.offer_index , event.count
local player = game.players [ player_index ]
if not ( market and market.valid and offer_index and Common.validate_player ( player ) ) then return end
local crew_id = tonumber ( string.sub ( player.force . name , - 3 , - 1 ) ) or nil
Memory.set_working_id ( crew_id )
local memory = Memory.get_crew_memory ( )
local destination = Common.current_destination ( )
local inv = player.get_inventory ( defines.inventory . character_main )
local thisPurchaseData = purchaseData ( market , player , offer_index )
2022-05-06 13:00:57 +01:00
local refunds = 0
2022-04-29 23:48:34 +01:00
-- Normally we want to disallow multi-purchases in this game (with the exception of static trades for items), so refund any additional purchases:
2022-05-07 21:56:16 +01:00
if ( thisPurchaseData.decay_type ~= ' static ' or thisPurchaseData.offer_type == ' nothing ' ) and player and trade_count and trade_count > 1 then
2022-03-05 14:09:35 +00:00
inv = player.get_inventory ( defines.inventory . character_main )
if not inv then return end
2022-05-07 21:56:16 +01:00
for _ , p in pairs ( thisPurchaseData.price ) do
2022-03-05 14:09:35 +00:00
inv.insert { name = p.name , count = p.amount * ( trade_count - 1 ) }
end
2022-05-07 21:56:16 +01:00
if thisPurchaseData.offer_type == ' give-item ' then
inv.remove { name = thisPurchaseData.offer_giveitem_name , count = thisPurchaseData.offer_giveitem_count * ( trade_count - 1 ) }
2022-03-05 14:09:35 +00:00
end
2022-05-06 13:00:57 +01:00
refunds = refunds + ( trade_count - 1 )
2022-03-05 14:09:35 +00:00
end
2022-05-07 21:56:16 +01:00
if thisPurchaseData.decay_type == ' one-off ' then
2021-10-13 09:21:53 +01:00
local force = player.force
2022-05-07 21:56:16 +01:00
if thisPurchaseData.dock_upgrades_market then
if thisPurchaseData.offer_type == ' give-item ' then
2022-04-29 23:48:34 +01:00
-- this is the dummy artillery purchase
2022-05-07 21:56:16 +01:00
inv.remove { name = thisPurchaseData.offer_giveitem_name , count = thisPurchaseData.offer_giveitem_count }
2022-02-26 23:33:19 +00:00
end
2022-03-04 17:57:58 +00:00
2022-05-07 21:56:16 +01:00
if thisPurchaseData.permission_level_fail then
2022-05-29 12:36:27 +01:00
Common.notify_player_error ( player , { ' pirates.market_error_not_captain ' } )
2022-04-29 23:48:34 +01:00
-- refund:
inv = player.get_inventory ( defines.inventory . character_main )
if not inv then return end
2022-05-07 21:56:16 +01:00
for _ , p in pairs ( thisPurchaseData.price ) do
2022-04-29 23:48:34 +01:00
inv.insert { name = p.name , count = p.amount }
end
2022-05-06 13:00:57 +01:00
refunds = refunds + 1
2022-04-29 23:48:34 +01:00
else
2022-05-07 21:56:16 +01:00
if thisPurchaseData.offer_type == ' give-item ' then
2022-04-29 23:48:34 +01:00
-- heal all cannons:
local cannons = game.surfaces [ destination.surface_name ] . find_entities_filtered ( { type = ' artillery-turret ' } )
for _ , c in pairs ( cannons ) do
2022-05-05 09:55:48 +01:00
local unit_number = c.unit_number
2022-05-07 21:56:16 +01:00
2022-05-07 21:41:45 +01:00
local healthbar = memory.boat . healthbars [ unit_number ]
2022-05-05 09:55:48 +01:00
if healthbar then
healthbar.health = healthbar.max_health
Common.update_healthbar_rendering ( healthbar , healthbar.max_health )
2022-05-07 21:41:45 +01:00
else
log ( ' error: healthbar ' .. unit_number .. ' not found ' )
2022-05-05 09:55:48 +01:00
end
2022-03-04 17:57:58 +00:00
end
2022-05-29 12:36:27 +01:00
Common.notify_force ( force , { ' pirates.repaired_cannons ' , player.name } )
2022-04-29 23:48:34 +01:00
market.remove_market_item ( offer_index )
2022-03-04 17:57:58 +00:00
else
2022-04-29 23:48:34 +01:00
local upgrade_type = Common.current_destination ( ) . static_params.upgrade_for_sale
if upgrade_type then
Upgrades.execute_upgade ( upgrade_type , player )
2022-03-04 17:57:58 +00:00
end
2022-04-29 23:48:34 +01:00
market.remove_market_item ( offer_index )
2022-03-04 17:57:58 +00:00
end
2022-04-29 23:48:34 +01:00
end
2022-03-04 17:57:58 +00:00
2022-04-29 23:48:34 +01:00
else
2022-03-19 21:20:55 +00:00
2022-05-07 21:56:16 +01:00
if thisPurchaseData.offer_type == ' nothing ' and destination.static_params . class_for_sale then
2022-04-29 23:48:34 +01:00
local class_for_sale = destination.static_params . class_for_sale
-- if not class_for_sale then return end
local required_class = Classes.class_purchase_requirement [ class_for_sale ]
2022-05-07 21:56:16 +01:00
2022-04-29 23:48:34 +01:00
local ok = true
-- check if they have the required class to buy it
if required_class then
if not ( memory.classes_table and memory.classes_table [ player.index ] and memory.classes_table [ player.index ] == required_class ) then
ok = false
2022-05-29 12:36:27 +01:00
Common.notify_force_error ( force , { ' pirates.class_purchase_error_prerequisite_class ' , Classes.display_form ( required_class ) } )
2022-04-29 23:48:34 +01:00
end
2022-03-04 17:57:58 +00:00
end
2022-05-07 21:56:16 +01:00
2022-04-29 23:48:34 +01:00
if ok then
if required_class then
if force and force.valid then
2022-05-29 12:36:27 +01:00
local message = { ' pirates.class_upgrade ' , player.name , Classes.display_form ( required_class ) , Classes.display_form ( class_for_sale ) , Classes.explanation ( class_for_sale ) }
Common.notify_force_light ( force , message )
2022-04-29 23:48:34 +01:00
end
else
-- check if they have a role already - renounce it if so
if memory.classes_table and memory.classes_table [ player.index ] then
Classes.try_renounce_class ( player , false )
end
2022-05-07 21:56:16 +01:00
2022-04-29 23:48:34 +01:00
if force and force.valid then
2022-05-29 12:36:27 +01:00
local message = { ' pirates.class_purchase ' , player.name , Classes.display_form ( class_for_sale ) , Classes.explanation ( class_for_sale ) }
Common.notify_force_light ( force , message )
2022-04-29 23:48:34 +01:00
end
end
2022-05-07 21:56:16 +01:00
2022-04-29 23:48:34 +01:00
memory.classes_table [ player.index ] = class_for_sale
2022-05-07 21:56:16 +01:00
2022-04-29 23:48:34 +01:00
memory.available_classes_pool = Utils.ordered_table_with_single_value_removed ( memory.available_classes_pool , class_for_sale )
2022-05-07 21:56:16 +01:00
2022-04-29 23:48:34 +01:00
-- if destination.dynamic_data and destination.dynamic_data.market_class_offer_rendering then
-- rendering.destroy(destination.dynamic_data.market_class_offer_rendering)
-- end
2022-05-07 21:56:16 +01:00
2022-04-29 23:48:34 +01:00
market.remove_market_item ( offer_index )
2022-05-07 21:56:16 +01:00
2022-04-29 23:48:34 +01:00
if Classes.class_unlocks [ class_for_sale ] then
for _ , upgrade in pairs ( Classes.class_unlocks [ class_for_sale ] ) do
memory.available_classes_pool [ # memory.available_classes_pool + 1 ] = upgrade
end
end
else
--refund
inv = player.get_inventory ( defines.inventory . character_main )
if not inv then return end
2022-05-07 21:56:16 +01:00
for _ , p in pairs ( thisPurchaseData.price ) do
2022-04-29 23:48:34 +01:00
inv.insert { name = p.name , count = p.amount }
2022-03-04 17:57:58 +00:00
end
2022-05-06 13:00:57 +01:00
refunds = refunds + 1
2022-03-04 17:57:58 +00:00
end
else
2022-05-29 12:36:27 +01:00
Common.notify_force_light ( player.force , { ' pirates.market_event_buy ' , player.name , thisPurchaseData.offer_giveitem_count .. ' ' .. thisPurchaseData.offer_giveitem_name , thisPurchaseData.price [ 1 ] . amount .. ' ' .. thisPurchaseData.price [ 1 ] . name } )
2022-05-07 21:56:16 +01:00
2022-04-29 23:48:34 +01:00
market.remove_market_item ( offer_index )
2022-02-26 23:33:19 +00:00
end
2021-10-13 09:21:53 +01:00
end
else
2022-05-07 21:56:16 +01:00
if thisPurchaseData.in_captains_cabin and thisPurchaseData.permission_level_fail then
2022-05-29 12:36:27 +01:00
Common.notify_player_error ( player , { ' pirates.market_error_not_captain_or_officer ' } )
2022-04-29 23:48:34 +01:00
-- refund:
inv = player.get_inventory ( defines.inventory . character_main )
if not inv then return end
2022-05-07 21:56:16 +01:00
for _ , p in pairs ( thisPurchaseData.price ) do
2022-04-29 23:48:34 +01:00
inv.insert { name = p.name , count = p.amount }
end
2022-05-07 21:56:16 +01:00
if thisPurchaseData.offer_type == ' give-item ' then
inv.remove { name = thisPurchaseData.offer_giveitem_name , count = thisPurchaseData.offer_giveitem_count }
2022-04-29 23:48:34 +01:00
end
2022-05-06 13:00:57 +01:00
refunds = refunds + 1
2022-04-29 23:48:34 +01:00
else
-- print:
2022-05-07 21:56:16 +01:00
if ( thisPurchaseData.price and thisPurchaseData.price [ 1 ] ) then
if not ( thisPurchaseData.price [ 1 ] . name and thisPurchaseData.price [ 1 ] . name == ' burner-mining-drill ' ) then --this one is too boring to announce
if thisPurchaseData.in_captains_cabin and thisPurchaseData.offer_type == ' nothing ' then
2022-05-29 12:36:27 +01:00
Common.notify_force_light ( player.force , { ' pirates.market_event_buy ' , player.name , { ' pirates.extra_time_at_sea ' } , thisPurchaseData.price [ 1 ] . amount .. ' ' .. thisPurchaseData.price [ 1 ] . name } )
2022-02-28 16:36:46 +00:00
else
2022-05-22 23:11:52 +01:00
Public.print_transaction ( player , thisPurchaseData.offer_giveitem_name , thisPurchaseData.offer_giveitem_count , thisPurchaseData.price )
2022-02-28 16:36:46 +00:00
end
2022-02-27 16:42:25 +00:00
end
2022-02-26 13:55:36 +00:00
end
2022-05-07 21:56:16 +01:00
if thisPurchaseData.in_captains_cabin and thisPurchaseData.offer_type == ' nothing ' then
2022-04-29 23:48:34 +01:00
local success = Crew.try_add_extra_time_at_sea ( 60 * 60 )
if not success then
2022-05-29 12:36:27 +01:00
Common.notify_player_error ( player , { ' pirates.market_error_maximum_loading_time ' } )
2022-04-29 23:48:34 +01:00
-- refund:
inv = player.get_inventory ( defines.inventory . character_main )
if not inv then return end
2022-05-07 21:56:16 +01:00
for _ , p in pairs ( thisPurchaseData.price ) do
2022-04-29 23:48:34 +01:00
inv.insert { name = p.name , count = p.amount }
end
2022-05-06 13:00:57 +01:00
refunds = refunds + 1
2022-04-29 23:48:34 +01:00
end
else
2022-05-07 21:56:16 +01:00
if thisPurchaseData.decay_type == ' static ' then
2022-04-29 23:48:34 +01:00
if not inv then return end
local flying_text_color = { r = 255 , g = 255 , b = 255 }
2022-05-22 23:20:30 +01:00
local text1 = ' [color=1,1,1]+ ' .. thisPurchaseData.offer_giveitem_count .. ' [/color] [item= ' .. thisPurchaseData.offer_giveitem_name .. ' ] '
local text2 = ' [color= ' .. flying_text_color.r .. ' , ' .. flying_text_color.g .. ' , ' .. flying_text_color.b .. ' ]( ' .. inv.get_item_count ( thisPurchaseData.offer_giveitem_name ) .. ' )[/color] '
2022-05-07 21:56:16 +01:00
2022-04-29 23:48:34 +01:00
Common.flying_text ( player.surface , player.position , text1 .. ' [font=count-font] ' .. text2 .. ' [/font] ' )
else
local decay_param = Balance.barter_decay_parameter ( )
2022-05-07 21:56:16 +01:00
if thisPurchaseData.decay_type == ' fast_decay ' then decay_param = Balance.barter_decay_parameter ( ) ^ 3 end
2022-04-29 23:48:34 +01:00
if not inv then return end
local flying_text_color = { r = 255 , g = 255 , b = 255 }
2022-05-22 23:20:30 +01:00
local text1 = ' [color=1,1,1]+ ' .. thisPurchaseData.offer_giveitem_count .. ' [/color] [item= ' .. thisPurchaseData.offer_giveitem_name .. ' ] '
2022-05-22 23:11:52 +01:00
local text2 = ' [color= ' .. flying_text_color.r .. ' , ' .. flying_text_color.g .. ' , ' .. flying_text_color.b .. ' ]( ' .. inv.get_item_count ( thisPurchaseData.offer_giveitem_name ) .. ' )[/color] '
2022-05-07 21:56:16 +01:00
2022-04-29 23:48:34 +01:00
Common.flying_text ( player.surface , player.position , text1 .. ' [font=count-font] ' .. text2 .. ' [/font] ' )
2022-05-07 21:56:16 +01:00
2022-04-29 23:48:34 +01:00
--update market trades:
2022-05-07 21:56:16 +01:00
thisPurchaseData.alloffers [ offer_index ] . offer.count = Math.max ( Math.floor ( thisPurchaseData.alloffers [ offer_index ] . offer.count * decay_param ) , 1 )
2022-04-29 23:48:34 +01:00
market.clear_market_items ( )
2022-05-07 21:56:16 +01:00
for _ , offer in pairs ( thisPurchaseData.alloffers ) do
2022-04-29 23:48:34 +01:00
market.add_market_item ( offer )
end
end
2021-10-13 09:21:53 +01:00
end
end
end
2022-05-06 13:00:57 +01:00
2022-05-22 23:11:52 +01:00
if thisPurchaseData.offer_giveitem_name and thisPurchaseData.offer_giveitem_name == ' coin ' and refunds < trade_count then
memory.playtesting_stats . coins_gained_by_markets = memory.playtesting_stats . coins_gained_by_markets + thisPurchaseData.offer_giveitem_count
2022-05-06 13:00:57 +01:00
end
2021-10-13 09:21:53 +01:00
end
return Public