[TGUI] Space Credit Economy Overhaul + Supply Point -> Space Cash (#19209)

* initial edits

* initial edits

* converting shit over to machinery/economy

* vending and mapping fixes

* vending fix pt.2

* Converts Supply Economy to Use Space Credits instead of Supply Points

* Job Payment, NanoBank, and Paychecks

* clothing type path fixes (damn merge conflicts)

* fixes map typepath issues

* adjusts supply prices

* Vendor Price Adjustments

* account uplink terminal tweaks

* please pass tests

* Apply suggestions from code review

Co-authored-by: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com>

* reviews and bug fixes

* Review Suggestions/Fixes and Request Console Rewrite

* edits

* vending changes for merge

* typepath fix

* final tweaks

* proc ref fixes

* Fixes and Tweaks from 2nd TM

* rebuild TGUI

* final tweaks

* Apply suggestions from code review

Co-authored-by: Farie82 <farie82@users.noreply.github.com>

* requested reviews

* tweaks

* updates slot machine winnings

* fixes

* GC fixes

* fixes

* oops. still need to deconflict this

* Apply suggestions from code review

Co-authored-by: Farie82 <farie82@users.noreply.github.com>
Co-authored-by: Henri215 <77684085+Henri215@users.noreply.github.com>
Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com>

* requested changes and bug fixes

* atm runtime fix

* requested reviews

* vend act stuff

* attempt to pass tests

* supply packs fix

* user tochat -> debug log

* FINAL FIXES

* removes CC db stuff

* Apply suggestions from code review

Co-authored-by: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com>

Co-authored-by: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com>
Co-authored-by: Farie82 <farie82@users.noreply.github.com>
Co-authored-by: Henri215 <77684085+Henri215@users.noreply.github.com>
Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com>
This commit is contained in:
Sirryan2002
2022-11-21 23:30:50 +00:00
committed by GitHub
co-authored by AffectedArc07 Farie82 Henri215 Luc
parent ae8accb766
commit 61145a02f8
151 changed files with 9392 additions and 7423 deletions
+310
View File
@@ -0,0 +1,310 @@
SUBSYSTEM_DEF(economy)
name = "Economy"
flags = SS_BACKGROUND
init_order = INIT_ORDER_ECONOMY //needs to init AFTER SSjobs
wait = 30 SECONDS
runlevels = RUNLEVEL_GAME
offline_implications = "Crew wont get their paychecks. No immediate action is needed." // money go down
///List of all money account databases existing in the round
var/list/money_account_databases = list()
///Total amount of account created during the round, neccesary for generating unique account ids
var/account_counter = 0
///The absolute total amount of space cash (not to be confused with credits) in the round, does not count space credits in money accounts
var/total_space_cash = 0
///The absolute total amount of space credits in various economy systems, does not count space cash
var/total_space_credits = 0
///The amount of space credits that have been irreversibly deleted/removed from the round
var/space_credits_destroyed = 0
///The amount of space credits that have been created out of thin air, does not include credits created at round-start
var/space_credits_created = 0
///The amount of transfers (that are worth more than a few credits) that have been accepted during the round
var/total_credit_transfers = 0
///the amount of venor purchases during the round
var/total_vendor_transactions = 0
///amount of money spent in this 15 minute slot during the round
var/current_10_minute_spending = 0
///list of vars that will be tracked throughout the round (a new entry for each key list will be added every 15 minutes)
var/list/economy_data = list(
"totalcash" = list(), //how much space cash is in circulation
"totalcredits" = list(), //How many space credits are in circulation
"creditsdestroyed" = list(), //How many space credits have been removed from the round
"totaltransfers" = list(), //How many transfers have been accped (above $4) this round
"moneyvelocity" = list(), //What is the money velocity of this 10 minute period GDP/MS
"totalvends" = list(), //How many purchases have been made from vendors this round
"stagnant_accounts" = list(), //How many accounts have not made any transactions this round
"stagnant_cash" = list(), //How many credits are sitting in stagnant accounts this round
"non_stagnant_cash" = list() //How many credits are in active accounts this round
)
///time to next stats check
var/next_data_check = 0
//////CARGO VARIABLES/////
///the department account tethered to this supply console, we keep a ref here for shuttle operations
var/datum/money_account/cargo_account
///Current Order number
var/ordernum = 1
/// points gained per slip returned
var/credits_per_manifest = 5
/// points gained per crate returned
var/credits_per_crate = 15
/// points gained per intel returned
var/credits_per_intel = 750
/// points gained per plasma returned
var/credits_per_plasma = 10
/// points gained per research design returned
var/credits_per_design = 20
/// Remarks from Centcom on how well you checked the last order.
var/centcom_message
/// Typepaths for unusual plants we've already sent CentComm, associated with their potencies
var/list/discovered_plants = list()
var/list/tech_levels = list()
var/list/research_designs = list()
///Requested crates, waiting for approval by department heads
var/list/request_list = list()
///Approved Crates, waiting to be delivered
var/list/shopping_list = list()
///Crates that will be on next shuttle
var/list/delivery_list = list()
///Full list of all available supply packs to purchase
var/list/supply_packs = list()
var/sold_atoms = ""
var/list/all_supply_groups = list(
SUPPLY_EMERGENCY,
SUPPLY_SECURITY,
SUPPLY_ENGINEER,
SUPPLY_MEDICAL,
SUPPLY_SCIENCE,
SUPPLY_ORGANIC,
SUPPLY_MATERIALS,
SUPPLY_MISC,
SUPPLY_VEND
)
//////Paycheck Variables/////
/// time to next payday
var/next_paycheck_delay = 0
/// total paydays this round
var/payday_count = 0
var/global_paycheck_bonus = 0
var/global_paycheck_deducation = 0
/datum/controller/subsystem/economy/vv_edit_var(var_name, var_value)
switch(var_name)
//These are all things that admins should not be touching during production, these are either used for logging
//or economy critical things that should not be touched
if("payday_count")
return FALSE //fuck off, used for logging
if("sold_atoms")
return FALSE //fuck off, used for logging
if("cargo_account")
if(!istype(var_value, /datum/money_account))
return FALSE //really fuck off, you're vv editing something to a value that will break the economy
return ..()
/datum/controller/subsystem/economy/Initialize()
///create main station accounts
if(!GLOB.current_date_string)
GLOB.current_date_string = "[time2text(world.timeofday, "DD Month")], [GLOB.game_year]"
if(GLOB.station_money_database)
populate_station_database()
cargo_account = GLOB.station_money_database.get_account_by_department(DEPARTMENT_SUPPLY)
if(!cargo_account)
WARNING("SSeconomy could not locate the supply department account")
//need to set this back to 0 due to how this is tracked (and so we have a clean slate for roundstart)
current_10_minute_spending = 0
ordernum = rand(1, 9000)
for(var/typepath in subtypesof(/datum/supply_packs))
var/datum/supply_packs/P = typepath
if(initial(P.name) == "HEADER")
continue // To filter out group headers
P = new typepath()
supply_packs["[P.type]"] = P
centcom_message = "<center>---[station_time_timestamp()]---</center><br>Remember to stamp and send back the supply manifests.<hr>"
next_paycheck_delay = 30 MINUTES + world.time
return ..()
/datum/controller/subsystem/economy/fire()
if(next_paycheck_delay <= world.time)
next_paycheck_delay = 30 MINUTES + world.time
payday()
if(next_data_check <= world.time)
next_data_check = 10 MINUTES + world.time
record_economy_data()
process_job_tasks()
/datum/controller/subsystem/economy/proc/record_economy_data()
economy_data["totalcash"] += total_space_cash
economy_data["totalcredits"] += total_space_credits
economy_data["creditsdestroyed"] += space_credits_destroyed - listgetindex(economy_data["creditsdestroyed"], length(economy_data["creditsdestroyed"]))
economy_data["totaltransfers"] += total_credit_transfers - listgetindex(economy_data["totaltransfers"], length(economy_data["totaltransfers"]))
economy_data["totalvends"] += total_vendor_transactions - listgetindex(economy_data["totalvends"], length(economy_data["totalvends"]))
economy_data["moneyvelocity"] += round((current_10_minute_spending / total_space_cash), 0.001)
var/stagnant_count = 0
var/stagnant_cash = 0
for(var/datum/money_account/account as anything in GLOB.station_money_database.user_accounts)
if(length(account.account_log) <= payday_count)
stagnant_count++
stagnant_cash += account.credit_balance
economy_data["stagnant_accounts"] += stagnant_count
economy_data["stagnant_cash"] = stagnant_cash
economy_data["non_stagnant_cash"] = total_space_credits - stagnant_cash
current_10_minute_spending = 0
/*
* # generate_account_number()
*
* SS proc that will generate a mostly random seven digit account number.
* This will allow up to 1000 guaranteed unique account numbers
*/
/datum/controller/subsystem/economy/proc/generate_account_number()
account_counter++
return (rand(1000, 9999) * 1000) + account_counter
/datum/controller/subsystem/economy/proc/populate_station_database()
var/datum/money_account_database/main_station/station_db = GLOB.station_money_database
money_account_databases += station_db
for(var/datum/station_department/department as anything in SSjobs.station_departments)
station_db.create_department_account(department.department_name, department.account_base_pay, department.account_starting_balance)
department.department_account = station_db.get_account_by_department(department.department_name)
//some crates ordered outside of cargo members still need QM explicit approval
station_db.create_vendor_account()
////////////////////////////
/// Supply Stuff /////////
////////////////////////
/datum/controller/subsystem/economy/proc/generate_supply_order(packID, orderedby, occupation, comment)
if(!packID)
return FALSE
var/datum/supply_packs/pack = locateUID(packID)
if(!pack)
return FALSE
var/datum/supply_order/order = new()
order.ordernum = ordernum++
order.object = pack
order.orderedby = orderedby
order.orderedbyRank = occupation
order.comment = comment
return order
/datum/controller/subsystem/economy/proc/process_supply_order(datum/supply_order/order, paid_for)
if(!order)
CRASH("process_supply_order() called with a null datum/supply_order")
if(!paid_for && !(order in request_list))
request_list += order //submit a request but do not finalize it
return TRUE
if(order.requires_head_approval || order.requires_qm_approval)
return TRUE
//if purchaser has already paid it means it's fully approved, finalize order
if(paid_for)
finalize_supply_order(order) //if payment was succesful, add order to shoppinglist
return TRUE
log_debug("process_supply_order() called on Crate [order.ordernum] ordered by [order.orderedby] but isn't paid for and doesn't need approval, deleting")
qdel(order) //only the strong will survive
return FALSE
/datum/controller/subsystem/economy/proc/finalize_supply_order(datum/supply_order/order)
if(!order)
CRASH("finalize_supply_order() called with a null datum/supply_order")
if(order in request_list)
request_list -= order
if(SSshuttle.supply.getDockedId() == "supply_away" && SSshuttle.supply.mode == SHUTTLE_IDLE)
delivery_list += order
else
shopping_list += order
////////////////////////////
/// Paycheck Stuff /////////
////////////////////////
/datum/controller/subsystem/economy/proc/payday()
payday_count++
var/total_payout = 0
var/total_accounts = 0
var/datum/money_account_database/main_station/station_db = GLOB.station_money_database
var/list/all_station_accounts = station_db.user_accounts + station_db.get_all_department_accounts()
for(var/datum/money_account/account in all_station_accounts)
var/amount_to_pay = account.payday_amount + global_paycheck_bonus - global_paycheck_deducation
if(LAZYLEN(account.pay_check_bonuses))
for(var/bonus in account.pay_check_bonuses)
amount_to_pay += bonus
account.pay_check_bonuses = null
for(var/deduction in account.pay_check_deductions)
amount_to_pay -= deduction
amount_to_pay = max(amount_to_pay, 0)
account.pay_check_deductions = null
station_db.credit_account(account, amount_to_pay, "Payday", "NAS Trurl Payroll", FALSE)
if(account.account_type == ACCOUNT_TYPE_PERSONAL)
if(LAZYLEN(account.associated_nanobank_programs))
for(var/datum/data/pda/app/nanobank/program as anything in account.associated_nanobank_programs)
program.announce_payday(amount_to_pay)
total_accounts++
total_payout += amount_to_pay
//reset global paycheck modifiers to 0
global_paycheck_bonus = 0
global_paycheck_deducation = 0
//update space credit statistics
space_credits_created += total_payout
total_space_credits += total_payout
//alert admins and c*ders alike
log_debug("Payday Count: [payday_count] - [total_payout] credits paid out to [total_accounts] accounts")
//Called by the gameticker
/datum/controller/subsystem/economy/proc/process_job_tasks()
for(var/mob/M in GLOB.player_list) //why not just make a global list of players with job objectives???? someone else fix this ~sirryan
if(!M.mind)
continue
for(var/datum/job_objective/objective as anything in M.mind.job_objectives)
if(objective.completed && objective.payout_given)
continue //objective is completed and we've already given out award
if(!objective.is_completed())
continue //object is not completed, do not proceed
if(objective.completion_payment == 0)
objective.payout_given = TRUE
continue //objective doesn't giveout payout
if(objective.owner_account)
objective.owner_account.modify_payroll(objective.completion_payment, TRUE, "Job Objective \"[objective.objective_name]\" completed, award will be included in next paycheck")
objective.payout_given = TRUE
break
//
// The NanoCoin Economy is booming
// My Parabuck Stocks are Rising
// God Bless John Nanotrasen
//
// __-----__
// ..;;;--'~~~`--;;;..
// /; -~IN NANOTRASEN ;.
// // WE TRUST~- \\
// // ,-------, \\
// .// | ;;; ~ \ \\.
// || |;;;( /.| ||
// || |;; _\ ||
// || '. '=== ||
// || PROFIT | ''\ ;;;/ ||
// \\ ,| '\ '|><| 2223 //
// \\ | | \ AD//
// `;.,|. | '\.-'/
// ~~;;;,._|___.,-;;;~'
// ''=--'
//
+47 -26
View File
@@ -17,9 +17,14 @@ SUBSYSTEM_DEF(jobs)
//Debug info
var/list/job_debug = list()
///list of station departments and their associated roles and economy payments
var/list/station_departments = list()
/datum/controller/subsystem/jobs/Initialize(timeofday)
if(!occupations.len)
SetupOccupations()
for(var/department_type in subtypesof(/datum/station_department))
station_departments += new department_type()
LoadJobs(FALSE)
return ..()
@@ -92,11 +97,6 @@ SUBSYSTEM_DEF(jobs)
for(var/objectiveType in job.required_objectives)
new objectiveType(player.mind)
// 50/50 chance of getting optional objectives.
for(var/objectiveType in job.optional_objectives)
if(prob(50))
new objectiveType(player.mind)
unassigned -= player
job.current_positions++
return 1
@@ -574,36 +574,57 @@ SUBSYSTEM_DEF(jobs)
SSblackbox.record_feedback("nested tally", "job_preferences", young, list("[job.title]", "young"))
SSblackbox.record_feedback("nested tally", "job_preferences", disabled, list("[job.title]", "disabled"))
//fuck
/datum/controller/subsystem/jobs/proc/CreateMoneyAccount(mob/living/H, rank, datum/job/job)
var/datum/money_account/M = create_account(H.real_name, rand(50,500)*10, null)
var/starting_balance = job?.department_account_access ? COMMAND_MEMBER_STARTING_BALANCE : CREW_MEMBER_STARTING_BALANCE
var/datum/money_account/account = GLOB.station_money_database.create_account(H.real_name, starting_balance, ACCOUNT_SECURITY_ID, "NAS Trurl Accounting", TRUE)
for(var/datum/job_objective/objective as anything in H.mind.job_objectives)
objective.owner_account = account
var/remembered_info = ""
remembered_info += "<b>Your account number is:</b> #[account.account_number]<br>"
remembered_info += "<b>Your account pin is:</b> [account.account_pin]<br>"
remembered_info += "<b>Your account number is:</b> #[M.account_number]<br>"
remembered_info += "<b>Your account pin is:</b> [M.remote_access_pin]<br>"
remembered_info += "<b>Your account funds are:</b> $[M.money]<br>"
if(M.transaction_log.len)
var/datum/transaction/T = M.transaction_log[1]
remembered_info += "<b>Your account was created:</b> [T.time], [T.date] at [T.source_terminal]<br>"
H.mind.store_memory(remembered_info)
H.mind.set_initial_account(account)
//add them to their department datum, (this relates a lot to money account I promise)
var/list/users_departments = get_departments_from_job(job.title)
for(var/datum/station_department/department as anything in users_departments)
var/datum/department_member/member = new
member.name = H.real_name
member.role = job.title
member.member_account = account
member.can_approve_crates = job?.department_account_access
department.members += member
to_chat(H, "<span class='boldnotice'>As an employee of Nanotrasen you will receive a paycheck of $[account.payday_amount] credits every 30 minutes</span>")
to_chat(H, "<span class='boldnotice'>Your account number is: [account.account_number], your account pin is: [account.account_pin]</span>")
// If they're head, give them the account info for their department
if(job && job.head_position)
remembered_info = ""
var/datum/money_account/department_account = GLOB.department_accounts[job.department]
if(!job?.department_account_access)
return
if(department_account)
remembered_info += "<b>Your department's account number is:</b> #[department_account.account_number]<br>"
remembered_info += "<b>Your department's account pin is:</b> [department_account.remote_access_pin]<br>"
remembered_info += "<b>Your department's account funds are:</b> $[department_account.money]<br>"
announce_department_accounts(users_departments, H, job)
/datum/controller/subsystem/jobs/proc/announce_department_accounts(users_departments, mob/living/H, datum/job/job)
var/remembered_info = ""
for(var/datum/station_department/department as anything in users_departments)
if(job.title != department.head_of_staff && job.title != "Quartermaster")
continue
var/datum/money_account/department_account = department.department_account
if(!department_account)
return
remembered_info += "As a head of staff you have access to your department's money account through your PDA's NanoBank or a station ATM<br>"
remembered_info += "<b>The [department.department_name] department's account number is:</b> #[department_account.account_number]<br>"
remembered_info += "<b>The [department.department_name] department's account pin is:</b> [department_account.account_pin]<br>"
remembered_info += "<b>Your department's account funds are:</b> $[department_account.credit_balance]<br>"
H.mind.store_memory(remembered_info)
H.mind.initial_account = M
spawn(0)
to_chat(H, "<span class='boldnotice'>Your account number is: [M.account_number], your account pin is: [M.remote_access_pin]</span>")
to_chat(H, "<span class='boldnotice'>Your department will receive a $[department_account.payday_amount] credit stipend every 30 minutes</span>")
to_chat(H, "<span class='boldnotice'>The [department.department_name] department's account number is: #[department_account.account_number], Your department's account pin is: [department_account.account_pin]</span>")
/datum/controller/subsystem/jobs/proc/format_jobs_for_id_computer(obj/item/card/id/tgtcard)
var/list/jobs_to_formats = list()
+4 -48
View File
@@ -5,12 +5,12 @@ SUBSYSTEM_DEF(shuttle)
init_order = INIT_ORDER_SHUTTLE
flags = SS_KEEP_TIMING|SS_NO_TICK_CHECK
runlevels = RUNLEVEL_SETUP | RUNLEVEL_GAME
offline_implications = "Shuttles will no longer function and cargo will not generate points. Immediate server restart recommended."
offline_implications = "Shuttles will no longer function. Immediate server restart recommended."
var/list/mobile = list()
var/list/stationary = list()
var/list/transit = list()
//emergency shuttle stuff
//emergency shuttle stuff
var/obj/docking_port/mobile/emergency/emergency
var/obj/docking_port/mobile/emergency/backup/backup_shuttle
var/emergencyCallTime = SHUTTLE_CALLTIME //time taken for emergency shuttle to reach the station when called (in deciseconds)
@@ -20,32 +20,15 @@ SUBSYSTEM_DEF(shuttle)
var/area/emergencyLastCallLoc
var/emergencyNoEscape
//supply shuttle stuff
//supply shuttle stuff
var/obj/docking_port/mobile/supply/supply
var/ordernum = 1 //order number given to next order
var/points = 50 //number of trade-points we have
var/points_per_decisecond = 0.005 //points gained every decisecond
var/points_per_slip = 2 //points gained per slip returned
var/points_per_crate = 5 //points gained per crate returned
var/points_per_intel = 250 //points gained per intel returned
var/points_per_plasma = 5 //points gained per plasma returned
var/points_per_design = 25 //points gained per research design returned
var/centcom_message = null //Remarks from Centcom on how well you checked the last order.
var/list/discoveredPlants = list() //Typepaths for unusual plants we've already sent CentComm, associated with their potencies
var/list/techLevels = list()
var/list/researchDesigns = list()
var/list/shoppinglist = list()
var/list/requestlist = list()
var/list/supply_packs = list()
var/sold_atoms = ""
var/list/hidden_shuttle_turfs = list() //all turfs hidden from navigation computers associated with a list containing the image hiding them and the type of the turf they are pretending to be
var/list/hidden_shuttle_turf_images = list() //only the images from the above list
/// Default refuel delay
var/refuel_delay = 20 MINUTES
/datum/controller/subsystem/shuttle/Initialize(start_timeofday)
ordernum = rand(1,9000)
if(!emergency)
WARNING("No /obj/docking_port/mobile/emergency placed on the map!")
if(!backup_shuttle)
@@ -54,15 +37,8 @@ SUBSYSTEM_DEF(shuttle)
WARNING("No /obj/docking_port/mobile/supply placed on the map!")
initial_load()
for(var/typepath in subtypesof(/datum/supply_packs))
var/datum/supply_packs/P = new typepath()
if(P.name == "HEADER") continue // To filter out group headers
supply_packs["[P.type]"] = P
initial_move()
centcom_message = "<center>---[station_time_timestamp()]---</center><br>Remember to stamp and send back the supply manifests.<hr>"
return ..()
/datum/controller/subsystem/shuttle/get_stat_details()
@@ -74,7 +50,6 @@ SUBSYSTEM_DEF(shuttle)
CHECK_TICK
/datum/controller/subsystem/shuttle/fire(resumed = FALSE)
points += points_per_decisecond * wait
for(var/thing in mobile)
if(thing)
var/obj/docking_port/mobile/P = thing
@@ -247,25 +222,6 @@ SUBSYSTEM_DEF(shuttle)
continue
M.dockRoundstart()
/datum/controller/subsystem/shuttle/proc/generateSupplyOrder(packId, _orderedby, _orderedbyRank, _comment, _crates)
if(!packId)
return
var/datum/supply_packs/P = locateUID(packId)
if(!P)
return
var/datum/supply_order/O = new()
O.ordernum = ordernum++
O.object = P
O.orderedby = _orderedby
O.orderedbyRank = _orderedbyRank
O.comment = _comment
O.crates = _crates
requestlist += O
return O
/datum/controller/subsystem/shuttle/proc/get_dock_overlap(x0, y0, x1, y1, z)
. = list()
var/list/stationary_cache = stationary
-1
View File
@@ -115,7 +115,6 @@ SUBSYSTEM_DEF(ticker)
if(GAME_STATE_PLAYING)
delay_end = FALSE // reset this in case round start was delayed
mode.process()
mode.process_job_tasks()
if(world.time > next_autotransfer)
SSvote.start_vote(new /datum/vote/crew_transfer)