mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-21 20:20:33 +01:00
## About The Pull Request I'm giving all the credits of this PR to the creator of #82153. The reason I'm making this PR is because, while the other fix work too, I believe this one is perhaps better so that we won't have to call `SSjob.GetJobType(jobtype)` everytime we want to access or make use of the `bank_accounts_by_job` variable. ## Why It's Good For The Game See title, also the other PR if you want a more indepth explaination of relatively simple stuff. ## Changelog 🆑 00-Steven fix: Fixed patronizing paintings not giving a cut to the curators. /🆑
237 lines
11 KiB
Plaintext
237 lines
11 KiB
Plaintext
SUBSYSTEM_DEF(economy)
|
|
name = "Economy"
|
|
wait = 5 MINUTES
|
|
init_order = INIT_ORDER_ECONOMY
|
|
runlevels = RUNLEVEL_GAME
|
|
///How many paychecks should players start out the round with?
|
|
var/roundstart_paychecks = 5
|
|
///How many credits does the in-game economy have in circulation at round start? Divided up by 6 of the 7 department budgets evenly, where cargo starts with nothing.
|
|
var/budget_pool = 35000
|
|
var/list/department_accounts = list(ACCOUNT_CIV = ACCOUNT_CIV_NAME,
|
|
ACCOUNT_ENG = ACCOUNT_ENG_NAME,
|
|
ACCOUNT_SCI = ACCOUNT_SCI_NAME,
|
|
ACCOUNT_MED = ACCOUNT_MED_NAME,
|
|
ACCOUNT_SRV = ACCOUNT_SRV_NAME,
|
|
ACCOUNT_CAR = ACCOUNT_CAR_NAME,
|
|
ACCOUNT_SEC = ACCOUNT_SEC_NAME)
|
|
var/list/departmental_accounts = list()
|
|
/**
|
|
* Enables extra money charges for things that normally would be free, such as sleepers/cryo/beepsky.
|
|
* Take care when enabling, as players will NOT respond well if the economy is set up for low cash flows.
|
|
*/
|
|
var/full_ancap = FALSE
|
|
|
|
/// Departmental cash provided to science when a node is researched in specific configs.
|
|
var/techweb_bounty = 250
|
|
/**
|
|
* List of normal (no department ones) accounts' identifiers with associated datum accounts, for big O performance.
|
|
* A list of sole account datums can be obtained with flatten_list(), another variable would be redundant rn.
|
|
*/
|
|
var/list/bank_accounts_by_id = list()
|
|
/// A list of bank accounts indexed by their assigned job typepath.
|
|
var/list/bank_accounts_by_job = list()
|
|
///List of the departmental budget cards in existance.
|
|
var/list/dep_cards = list()
|
|
/// A var that collects the total amount of credits owned in player accounts on station, reset and recounted on fire()
|
|
var/station_total = 0
|
|
/// A var that tracks how much money is expected to be on station at a given time. If less than station_total prices go up in vendors.
|
|
var/station_target = 1
|
|
/// A passively increasing buffer to help alliviate inflation later into the shift, but to a lesser degree.
|
|
var/station_target_buffer = 0
|
|
/// A var that displays the result of inflation_value for easier debugging and tracking.
|
|
var/inflation_value = 1
|
|
/// How many civilain bounties have been completed so far this shift? Affects civilian budget payout values.
|
|
var/civ_bounty_tracker = 0
|
|
/// Contains the message to send to newscasters about price inflation and earnings, updated on price_update()
|
|
var/earning_report
|
|
///The modifier multiplied to the value of bounties paid out.
|
|
var/bounty_modifier = 1
|
|
///The modifier multiplied to the value of cargo pack prices.
|
|
var/pack_price_modifier = 1
|
|
/**
|
|
* A list of strings containing a basic transaction history of purchases on the station.
|
|
* Added to any time when player accounts purchase something.
|
|
*/
|
|
var/list/audit_log = list()
|
|
|
|
/// Number of mail items generated.
|
|
var/mail_waiting = 0
|
|
/// Mail Holiday: AKA does mail arrive today? Always blocked on Sundays.
|
|
var/mail_blocked = FALSE
|
|
/// List used to track partially completed processing steps
|
|
/// Allows for proper yielding
|
|
var/list/cached_processing
|
|
/// Tracks what bit of processing we're on, so we can resume post yield in the right place
|
|
var/processing_part
|
|
/// Tracks a temporary sum of all money in the system
|
|
/// We need this on the subsystem because of yielding and such
|
|
var/temporary_total = 0
|
|
|
|
/datum/controller/subsystem/economy/Initialize()
|
|
//removes cargo from the split
|
|
var/budget_to_hand_out = round(budget_pool / department_accounts.len -1)
|
|
if(time2text(world.timeofday, "DDD") == SUNDAY)
|
|
mail_blocked = TRUE
|
|
for(var/dep_id in department_accounts)
|
|
if(dep_id == ACCOUNT_CAR) //cargo starts with NOTHING
|
|
new /datum/bank_account/department(dep_id, 0, player_account = FALSE)
|
|
continue
|
|
new /datum/bank_account/department(dep_id, budget_to_hand_out, player_account = FALSE)
|
|
return SS_INIT_SUCCESS
|
|
|
|
/datum/controller/subsystem/economy/Recover()
|
|
departmental_accounts = SSeconomy.departmental_accounts
|
|
bank_accounts_by_id = SSeconomy.bank_accounts_by_id
|
|
dep_cards = SSeconomy.dep_cards
|
|
|
|
/// Processing step defines, to track what we've done so far
|
|
#define ECON_DEPARTMENT_STEP "econ_dpt_stp"
|
|
#define ECON_ACCOUNT_STEP "econ_act_stp"
|
|
#define ECON_PRICE_UPDATE_STEP "econ_prc_stp"
|
|
|
|
/datum/controller/subsystem/economy/fire(resumed = 0)
|
|
var/seconds_per_tick = wait / (5 MINUTES)
|
|
|
|
if(!resumed)
|
|
temporary_total = 0
|
|
processing_part = ECON_DEPARTMENT_STEP
|
|
cached_processing = department_accounts.Copy()
|
|
|
|
if(processing_part == ECON_DEPARTMENT_STEP)
|
|
if(!departmental_payouts())
|
|
return
|
|
|
|
processing_part = ECON_ACCOUNT_STEP
|
|
cached_processing = bank_accounts_by_id.Copy()
|
|
station_total = 0
|
|
station_target_buffer += STATION_TARGET_BUFFER
|
|
|
|
if(processing_part == ECON_ACCOUNT_STEP)
|
|
if(!issue_paydays())
|
|
return
|
|
|
|
processing_part = ECON_PRICE_UPDATE_STEP
|
|
station_target = max(round(temporary_total / max(bank_accounts_by_id.len * 2, 1)) + station_target_buffer, 1)
|
|
|
|
if(processing_part == ECON_PRICE_UPDATE_STEP)
|
|
if(!HAS_TRAIT(SSeconomy, TRAIT_MARKET_CRASHING) && !price_update())
|
|
return
|
|
|
|
var/effective_mailcount = round(living_player_count()/(inflation_value - 0.5)) //More mail at low inflation, and vis versa.
|
|
mail_waiting += clamp(effective_mailcount, 1, MAX_MAIL_PER_MINUTE * seconds_per_tick)
|
|
|
|
SSstock_market.news_string = ""
|
|
|
|
/**
|
|
* Handy proc for obtaining a department's bank account, given the department ID, AKA the define assigned for what department they're under.
|
|
*/
|
|
/datum/controller/subsystem/economy/proc/get_dep_account(dep_id)
|
|
for(var/datum/bank_account/department/D in departmental_accounts)
|
|
if(D.department_id == dep_id)
|
|
return D
|
|
|
|
/**
|
|
* Departmental income payments are kept static and linear for every department, and paid out once every 5 minutes, as determined by MAX_GRANT_DPT.
|
|
* Iterates over every department account for the same payment.
|
|
*/
|
|
/datum/controller/subsystem/economy/proc/departmental_payouts()
|
|
// son sonic speed? cache? hot over in cold food why? (datum var accesses are slow, cache lists for sonic speed)
|
|
var/list/cached_processing = src.cached_processing
|
|
for(var/i in 1 to length(cached_processing))
|
|
var/datum/bank_account/dept_account = get_dep_account(cached_processing[i])
|
|
if(!dept_account)
|
|
continue
|
|
dept_account.adjust_money(MAX_GRANT_DPT)
|
|
if(MC_TICK_CHECK)
|
|
cached_processing.Cut(1, i + 1)
|
|
return FALSE
|
|
return TRUE
|
|
|
|
/**
|
|
* Issues all our bank-accounts paydays, and gets an idea of how much money is in circulation
|
|
*/
|
|
/datum/controller/subsystem/economy/proc/issue_paydays()
|
|
var/list/cached_processing = src.cached_processing
|
|
for(var/i in 1 to length(cached_processing))
|
|
var/datum/bank_account/bank_account = cached_processing[cached_processing[i]]
|
|
if(bank_account?.account_job && !ispath(bank_account.account_job))
|
|
temporary_total += (bank_account.account_job.paycheck * STARTING_PAYCHECKS)
|
|
bank_account.payday(1)
|
|
station_total += bank_account.account_balance
|
|
if(MC_TICK_CHECK)
|
|
cached_processing.Cut(1, i + 1)
|
|
return FALSE
|
|
return TRUE
|
|
|
|
/**
|
|
* Updates the the inflation_value, effecting newscaster alerts and the mail system.
|
|
**/
|
|
/datum/controller/subsystem/economy/proc/price_update()
|
|
var/fluff_string = ""
|
|
if(!HAS_TRAIT(SSeconomy, TRAIT_MARKET_CRASHING))
|
|
fluff_string = ", but company countermeasures protect <b>YOU</b> from being affected!"
|
|
else
|
|
fluff_string = ", and company countermeasures are failing to protect <b>YOU</b> from being affected. We're all doomed!"
|
|
earning_report = "<b>Sector Economic Report</b><br><br> Sector vendor prices is currently at <b>[SSeconomy.inflation_value()*100]%</b>[fluff_string]<br><br> The station spending power is currently <b>[station_total] Credits</b>, and the crew's targeted allowance is at <b>[station_target] Credits</b>.<br><br>[SSstock_market.news_string] That's all from the <i>Nanotrasen Economist Division</i>."
|
|
GLOB.news_network.submit_article(earning_report, "Station Earnings Report", "Station Announcements", null, update_alert = FALSE)
|
|
return TRUE
|
|
|
|
/**
|
|
* Proc that returns a value meant to shift inflation values in vendors, based on how much money exists on the station.
|
|
*
|
|
* If crew are somehow aquiring far too much money, this value will dynamically cause vendables across the station to skyrocket in price until some money is spent.
|
|
* Additionally, civilain bounties will cost less, and cargo goodies will increase in price as well.
|
|
* The goal here is that if you want to spend money, you'll have to get it, and the most efficient method is typically from other players.
|
|
**/
|
|
/datum/controller/subsystem/economy/proc/inflation_value()
|
|
if(!bank_accounts_by_id.len)
|
|
return 1
|
|
if(HAS_TRAIT(SSeconomy, TRAIT_MARKET_CRASHING))
|
|
return inflation_value //early return instead of the actual check
|
|
inflation_value = max(round(((station_total / bank_accounts_by_id.len) / station_target), 0.1), 1.0)
|
|
return inflation_value
|
|
|
|
/**
|
|
* Proc that adds a set of strings and ints to the audit log, tracked by the economy SS.
|
|
*
|
|
* * account: The bank account of the person purchasing the item.
|
|
* * price_to_use: The cost of the purchase made for this transaction.
|
|
* * vendor: The object or structure medium that is charging the user. For Vending machines that's the machine, for payment component that's the parent, cargo that's the crate, etc.
|
|
*/
|
|
/datum/controller/subsystem/economy/proc/track_purchase(datum/bank_account/account, price_to_use, vendor)
|
|
if(!account || isnull(price_to_use) || !vendor)
|
|
CRASH("Track purchases was missing an argument! (Account, Price, or Vendor.)")
|
|
|
|
audit_log += list(list(
|
|
"account" = "[account.account_holder]",
|
|
"cost" = price_to_use,
|
|
"vendor" = "[vendor]",
|
|
))
|
|
|
|
/**
|
|
* Iterates over the machines list for vending machines, resets their regular and premium product prices (Not contraband), and sends a message to the newscaster network.
|
|
*/
|
|
/datum/controller/subsystem/economy/proc/update_vending_prices()
|
|
var/list/obj/machinery/vending/prices_to_update = list()
|
|
// Assoc list of "z level" -> if it's on the station
|
|
// Hack, is station z level is too expensive to do for each machine, I hate this place
|
|
var/list/station_z_status = list()
|
|
for(var/obj/machinery/vending/vending_lad as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/vending))
|
|
if(istype(vending_lad, /obj/machinery/vending/custom))
|
|
continue
|
|
var/vending_level = vending_lad.z
|
|
var/station_status = station_z_status["[vending_level]"]
|
|
if(station_status == null)
|
|
station_status = is_station_level(vending_level)
|
|
station_z_status["[vending_level]"] = station_status
|
|
if(!station_status)
|
|
continue
|
|
prices_to_update += vending_lad
|
|
for(var/i in 1 to length(prices_to_update))
|
|
var/obj/machinery/vending/V = prices_to_update[i]
|
|
V.reset_prices(V.product_records, V.coin_records)
|
|
|
|
#undef ECON_DEPARTMENT_STEP
|
|
#undef ECON_ACCOUNT_STEP
|
|
#undef ECON_PRICE_UPDATE_STEP
|