mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-25 06:00:16 +01:00
375 lines
16 KiB
Plaintext
375 lines
16 KiB
Plaintext
#define DUMPTIME 3000
|
|
///Amount of money you need to lose to get the negative moodlet.
|
|
#define NO_MY_MONEY 10000
|
|
|
|
/datum/bank_account
|
|
///Name listed on the account, reflected on the ID card.
|
|
var/account_holder = "Rusty Venture"
|
|
///How many credits are currently held in the bank account.
|
|
var/account_balance = 0
|
|
///How many mining points (shaft miner credits) is held in the bank account, used for mining vendors.
|
|
var/mining_points = 0
|
|
/// Points for bit runner's vendor. Awarded for completing virtual domains.
|
|
var/bitrunning_points = 0
|
|
///Debt. If higher than 0, A portion of the credits is earned (or the whole debt, whichever is lower) will go toward paying it off.
|
|
var/account_debt = 0
|
|
///If there are things effecting how much income a player will get, it's reflected here 1 is standard for humans.
|
|
var/payday_modifier
|
|
///The job datum of the account owner.
|
|
var/datum/job/account_job
|
|
///List of the physical ID card objects that are associated with this bank_account
|
|
var/list/bank_cards
|
|
///Should this ID be added to the global list of accounts? If true, will be subject to station-bound economy effects as well as income.
|
|
var/add_to_accounts = TRUE
|
|
///The Unique ID number code associated with the owner's bank account, assigned at round start.
|
|
var/account_id
|
|
///Amount of money that's been crabbed, if you lose enough from one series of CRAB-17's, you get a negative moodlet.
|
|
var/money_crabbed
|
|
///Lazylist of CRAB 17s on the station draining funds. Prevents manual fund transfer. pink levels are rising
|
|
var/list/being_dumped
|
|
///Reference to the current civilian bounty that the account is working on.
|
|
var/datum/bounty/civilian_bounty
|
|
///If player is currently picking a civilian bounty to do, these options are held here to prevent soft-resetting through the UI.
|
|
var/list/datum/bounty/bounties
|
|
///Can this account be replaced? Set to true for default IDs not recognized by the station.
|
|
var/replaceable = FALSE
|
|
///Cooldown timer on replacing a civilain bounty. Bounties can only be replaced once every 5 minutes.
|
|
COOLDOWN_DECLARE(bounty_timer)
|
|
///A special semi-tandom token for tranfering money from NT pay app
|
|
var/pay_token
|
|
///List with a transaction history for NT pay app
|
|
var/list/transaction_history
|
|
///A lazylist of coupons redeemed with the Coupon Master pda app associated with this account.
|
|
var/list/redeemed_coupons
|
|
/// How many paychecks to skip when payday is called.
|
|
var/paydays_to_skip = 0
|
|
|
|
/datum/bank_account/New(newname, job, modifier = 1, player_account = TRUE)
|
|
account_holder = newname
|
|
account_job = job
|
|
payday_modifier = modifier
|
|
add_to_accounts = player_account
|
|
setup_unique_account_id()
|
|
update_account_job_lists(job)
|
|
pay_token = uppertext("[copytext(newname, 1, 2)][copytext(newname, -1)]-[random_capital_letter()]-[rand(1111,9999)]")
|
|
|
|
/datum/bank_account/Destroy()
|
|
if(add_to_accounts)
|
|
SSeconomy.bank_accounts_by_id -= "[account_id]"
|
|
SSeconomy.bank_accounts_by_job[account_job.type] -= src
|
|
QDEL_LIST(redeemed_coupons)
|
|
return ..()
|
|
|
|
/**
|
|
* Proc guarantees the account_id possesses a unique number.
|
|
* If it doesn't, it tries to find a unique alternative.
|
|
* It then adds it to the `SSeconomy.bank_accounts_by_id` global list.
|
|
*/
|
|
/datum/bank_account/proc/setup_unique_account_id()
|
|
if (!add_to_accounts)
|
|
return
|
|
if(account_id && !SSeconomy.bank_accounts_by_id["[account_id]"])
|
|
SSeconomy.bank_accounts_by_id["[account_id]"] = src
|
|
return //Already unique
|
|
for(var/i in 1 to 1000)
|
|
account_id = rand(111111, 999999)
|
|
if(!SSeconomy.bank_accounts_by_id["[account_id]"])
|
|
break
|
|
if(SSeconomy.bank_accounts_by_id["[account_id]"])
|
|
stack_trace("Unable to find a unique account ID, substituting currently existing account of id [account_id].")
|
|
SSeconomy.bank_accounts_by_id["[account_id]"] = src
|
|
|
|
/**
|
|
* Proc places this account into the right place in the `SSeconomy.bank_accounts_by_job` list, if needed.
|
|
* If an old job is given, it removes it from its previous place first.
|
|
*/
|
|
/datum/bank_account/proc/update_account_job_lists(datum/job/new_job, datum/job/old_job)
|
|
if(!add_to_accounts)
|
|
return
|
|
|
|
if(old_job)
|
|
SSeconomy.bank_accounts_by_job[old_job.type] -= src
|
|
if(new_job)
|
|
LAZYADD(SSeconomy.bank_accounts_by_job[new_job.type], src)
|
|
|
|
/datum/bank_account/vv_edit_var(var_name, var_value) // just so you don't have to do it manually
|
|
var/old_id = account_id
|
|
var/datum/job/old_job = account_job
|
|
var/old_balance = account_balance
|
|
. = ..()
|
|
switch(var_name)
|
|
if(NAMEOF(src, account_id))
|
|
if(add_to_accounts)
|
|
SSeconomy.bank_accounts_by_id -= "[old_id]"
|
|
setup_unique_account_id()
|
|
if(NAMEOF(src, account_job))
|
|
update_account_job_lists(account_job, old_job)
|
|
if(NAMEOF(src, add_to_accounts))
|
|
if(add_to_accounts)
|
|
setup_unique_account_id()
|
|
update_account_job_lists(account_job)
|
|
else
|
|
SSeconomy.bank_accounts_by_id -= "[account_id]"
|
|
SSeconomy.bank_accounts_by_job[account_job.type] -= src
|
|
if(NAMEOF(src, account_balance))
|
|
add_log_to_history(var_value - old_balance, "Nanotrasen: Moderator Action")
|
|
|
|
/**
|
|
* Sets the bank_account to behave as though a CRAB-17 event is happening.
|
|
*/
|
|
/datum/bank_account/proc/dumpeet(obj/structure/checkoutmachine/dump_machine)
|
|
LAZYADD(being_dumped, dump_machine)
|
|
money_crabbed = 0
|
|
|
|
/**
|
|
* Stops the dumping of the bank account.
|
|
*/
|
|
/datum/bank_account/proc/stop_dump(obj/structure/checkoutmachine/dump_machine)
|
|
LAZYREMOVE(being_dumped, dump_machine)
|
|
if(money_crabbed < NO_MY_MONEY)
|
|
return
|
|
for(var/obj/card as anything in bank_cards)
|
|
var/mob/living/card_holder = recursive_loc_check(card, /mob/living)
|
|
if(!isliving(card_holder)) //If on a mob
|
|
continue
|
|
//overwrite the slots event.
|
|
card_holder.add_mood_event(SLOTS_MOOD_CATEGORY, /datum/mood_event/slots/all_gone)
|
|
|
|
/**
|
|
* Returns TRUE if a bank account has more than or equal to the amount, amt.
|
|
* Otherwise returns false.
|
|
* Arguments:
|
|
* * amount - the quantity of credits that will be reconciled with the account balance.
|
|
*/
|
|
/datum/bank_account/proc/has_money(amount)
|
|
return account_balance >= amount
|
|
|
|
/**
|
|
* Adjusts the balance of a bank_account as well as sanitizes the numerical input.
|
|
* Arguments:
|
|
* * amount - the quantity of credits that will be written off if the value is negative, or added if it is positive.
|
|
* * reason - the reason for the appearance or loss of money
|
|
*/
|
|
/datum/bank_account/proc/adjust_money(amount, reason)
|
|
if((amount < 0 && has_money(-amount)) || amount > 0)
|
|
var/debt_collected = 0
|
|
if(account_debt > 0 && amount > 0)
|
|
debt_collected = min(ceil(amount*DEBT_COLLECTION_COEFF), account_debt)
|
|
account_balance += amount - debt_collected
|
|
if(reason)
|
|
add_log_to_history(amount, reason)
|
|
if(debt_collected)
|
|
pay_debt(debt_collected, FALSE)
|
|
return TRUE
|
|
return FALSE
|
|
|
|
///Called when a portion of a debt is to be paid. It'll return the amount of credits put forwards to extinguish the debt.
|
|
/datum/bank_account/proc/pay_debt(amount, is_payment = TRUE)
|
|
var/amount_to_pay = min(amount, account_debt)
|
|
if(is_payment)
|
|
if(!adjust_money(-amount, "Other: Debt Payment"))
|
|
return 0
|
|
else
|
|
add_log_to_history(-amount, "Other: Debt Collection")
|
|
log_econ("[amount_to_pay] [MONEY_NAME] were removed from [account_holder]'s bank account to pay a debt of [account_debt]")
|
|
account_debt -= amount_to_pay
|
|
SEND_SIGNAL(src, COMSIG_BANK_ACCOUNT_DEBT_PAID)
|
|
return amount_to_pay
|
|
|
|
/**
|
|
* Performs a transfer of credits to the bank_account datum from another bank account.
|
|
* Arguments:
|
|
* * datum/bank_account/from - The bank account that is sending the credits to this bank_account datum.
|
|
* * amount - the quantity of credits that are being moved between bank_account datums.
|
|
* * transfer_reason - override for adjust_money reason. Use if no default reason(Transfer to/from Name Surname).
|
|
*/
|
|
/datum/bank_account/proc/transfer_money(datum/bank_account/from, amount, transfer_reason)
|
|
if(from.has_money(amount))
|
|
var/reason_to = "Transfer: From [from.account_holder]"
|
|
var/reason_from = "Transfer: To [account_holder]"
|
|
|
|
if(IS_DEPARTMENTAL_ACCOUNT(from))
|
|
reason_to = "Nanotrasen: Salary"
|
|
reason_from = ""
|
|
|
|
if(transfer_reason)
|
|
reason_to = IS_DEPARTMENTAL_ACCOUNT(src) ? "" : transfer_reason
|
|
reason_from = transfer_reason
|
|
|
|
adjust_money(amount, reason_to)
|
|
from.adjust_money(-amount, reason_from)
|
|
SSblackbox.record_feedback("amount", "credits_transferred", amount)
|
|
log_econ("[amount] [MONEY_NAME] were transferred from [from.account_holder]'s account to [src.account_holder]")
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/**
|
|
* This proc handles passive income gain for players, using their job's paycheck value.
|
|
* Funds are taken from the parent department account to hand out to players. This can result in payment brown-outs if too many people are in one department.
|
|
* Arguments:
|
|
* * amount_of_paychecks - literally the number of salaries, 1 for issuing one salary, 5 for issuing five salaries.
|
|
* * free - issuance of free funds, if TRUE then takes funds from the void, if FALSE (default) tries to send from the department's account.
|
|
* * skippable - if TRUE, this proc may pay out nothing if the account has paydays_to_skip
|
|
* * event - the name of the event that is being processed, used for bank card messages.
|
|
*/
|
|
/datum/bank_account/proc/payday(amount_of_paychecks, free = FALSE, skippable = FALSE, event = "Payday")
|
|
if(!account_job)
|
|
return FALSE
|
|
|
|
if(skippable && !free)
|
|
while(paydays_to_skip > 0 && amount_of_paychecks > 0)
|
|
amount_of_paychecks -= 1
|
|
paydays_to_skip -= 1
|
|
|
|
if(amount_of_paychecks <= 0)
|
|
return FALSE
|
|
|
|
var/money_to_transfer = round(account_job.paycheck * payday_modifier * amount_of_paychecks)
|
|
if(amount_of_paychecks == 1)
|
|
money_to_transfer = clamp(money_to_transfer, 0, PAYCHECK_CREW) //We want to limit single, passive paychecks to regular crew income.
|
|
if(free)
|
|
adjust_money(money_to_transfer, "Nanotrasen: Shift Payment")
|
|
SSblackbox.record_feedback("amount", "free_income", money_to_transfer)
|
|
SSeconomy.station_target += money_to_transfer
|
|
log_econ("[money_to_transfer] [MONEY_NAME] were given to [src.account_holder]'s account from income.")
|
|
return TRUE
|
|
var/datum/bank_account/department_account = SSeconomy.get_dep_account(account_job.paycheck_department)
|
|
if(isnull(department_account))
|
|
bank_card_talk("ERROR: [event] aborted, unable to contact departmental account.")
|
|
return FALSE
|
|
if(!transfer_money(department_account, money_to_transfer))
|
|
bank_card_talk("ERROR: [event] aborted, departmental funds insufficient.")
|
|
return FALSE
|
|
bank_card_talk("[event] processed, account now holds [account_balance] [MONEY_SYMBOL].")
|
|
return TRUE
|
|
|
|
/**
|
|
* This sends a local chat message to the owner of a bank account, on all ID cards registered to the bank_account.
|
|
* If not held, sends out a message to all nearby players.
|
|
* Arguments:
|
|
* * message - text that will be sent to listeners after the id card icon
|
|
* * force - if TRUE ignore checks on client and client prefernces.
|
|
*/
|
|
/datum/bank_account/proc/bank_card_talk(message, force)
|
|
if(!message || !LAZYLEN(bank_cards))
|
|
return
|
|
for(var/obj/card in bank_cards)
|
|
var/icon_source = card
|
|
if(isidcard(card))
|
|
var/obj/item/card/id/id_card = card
|
|
icon_source = id_card.get_cached_flat_icon()
|
|
var/mob/card_holder = recursive_loc_check(card, /mob)
|
|
if(ismob(card_holder)) //If on a mob
|
|
if(!card_holder.client || (!(get_chat_toggles(card_holder.client) & CHAT_BANKCARD) && !force))
|
|
return
|
|
|
|
if(!HAS_TRAIT(card_holder, TRAIT_DEAF))
|
|
card_holder.playsound_local(get_turf(card_holder), 'sound/machines/beep/twobeep_high.ogg', 50, TRUE)
|
|
to_chat(card_holder, "[icon2html(icon_source, card_holder)] [span_notice("[message]")]")
|
|
else if(isturf(card.loc)) //If on the ground
|
|
var/turf/card_location = card.loc
|
|
for(var/mob/potential_hearer in hearers(1,card_location))
|
|
if(!potential_hearer.client || (!(get_chat_toggles(potential_hearer.client) & CHAT_BANKCARD) && !force))
|
|
continue
|
|
if(!HAS_TRAIT(potential_hearer, TRAIT_DEAF))
|
|
potential_hearer.playsound_local(card_location, 'sound/machines/beep/twobeep_high.ogg', 50, TRUE)
|
|
to_chat(potential_hearer, "[icon2html(icon_source, potential_hearer)] [span_notice("[message]")]")
|
|
else
|
|
var/atom/sound_atom
|
|
for(var/mob/potential_hearer in card.loc) //If inside a container with other mobs (e.g. locker)
|
|
if(!potential_hearer.client || (!(get_chat_toggles(potential_hearer.client) & CHAT_BANKCARD) && !force))
|
|
continue
|
|
if(!sound_atom)
|
|
sound_atom = card.drop_location() //in case we're inside a bodybag in a crate or something. doing this here to only process it if there's a valid mob who can hear the sound.
|
|
if(!HAS_TRAIT(potential_hearer, TRAIT_DEAF))
|
|
potential_hearer.playsound_local(get_turf(sound_atom), 'sound/machines/beep/twobeep_high.ogg', 50, TRUE)
|
|
to_chat(potential_hearer, "[icon2html(icon_source, potential_hearer)] [span_notice("[message]")]")
|
|
|
|
/**
|
|
* Returns a string with the civilian bounty's description on it.
|
|
*/
|
|
/datum/bank_account/proc/bounty_text()
|
|
if(!civilian_bounty)
|
|
return FALSE
|
|
return civilian_bounty.description
|
|
|
|
|
|
/**
|
|
* Returns the required item count, or required chemical units required to submit a bounty.
|
|
*/
|
|
/datum/bank_account/proc/bounty_num()
|
|
return civilian_bounty?.print_required() || "N/A"
|
|
|
|
/**
|
|
* Produces the value of the account's civilian bounty reward, if able.
|
|
*/
|
|
/datum/bank_account/proc/bounty_value()
|
|
return civilian_bounty?.get_bounty_reward() || 0
|
|
|
|
/datum/bank_account/proc/set_bounty(datum/bounty/new_bounty, obj/item/id_card)
|
|
if(civilian_bounty)
|
|
reset_bounty(id_card)
|
|
|
|
civilian_bounty = new_bounty
|
|
civilian_bounty.on_selected(id_card)
|
|
|
|
/**
|
|
* Performs house-cleaning on variables when a civilian bounty is replaced, or, when a bounty is claimed.
|
|
*/
|
|
/datum/bank_account/proc/reset_bounty(obj/item/id_card)
|
|
if(civilian_bounty)
|
|
civilian_bounty.on_reset(id_card)
|
|
civilian_bounty = null
|
|
|
|
COOLDOWN_RESET(src, bounty_timer)
|
|
|
|
/datum/bank_account/department
|
|
account_holder = "Guild Credit Agency"
|
|
var/department_id = "REPLACE_ME"
|
|
add_to_accounts = FALSE
|
|
|
|
/datum/bank_account/department/New(dep_id, budget, player_account = FALSE)
|
|
department_id = dep_id
|
|
account_balance = budget
|
|
account_holder = SSeconomy.department_accounts[dep_id]
|
|
SSeconomy.departmental_accounts += src
|
|
|
|
/datum/bank_account/department/adjust_money(amount, reason)
|
|
. = ..()
|
|
|
|
SSblackbox.record_feedback("amount", "[department_id]_balance", account_balance, world.time) //Provides the cargo balance alongside a timestamp for comparison afterwards.
|
|
if(department_id != ACCOUNT_CAR)
|
|
return
|
|
|
|
// If we're under (or equal) 3 crates woth of money (600?) in the cargo department, we unlock the scrapheap, which gives us a buncha money. Useful in an emergency?
|
|
if(account_balance >= CARGO_CRATE_VALUE * 3)
|
|
return
|
|
// We only allow people to actually buy the shuttle once the round gets going - otherwise you'd just be able to do it roundstart (Not really intended)
|
|
var/minimum_allowed_purchase_time = (CONFIG_GET(number/shuttle_refuel_delay) * 0.6)
|
|
if((world.time - SSticker.round_start_time) > minimum_allowed_purchase_time)
|
|
SSshuttle.shuttle_purchase_requirements_met[SHUTTLE_UNLOCK_SCRAPHEAP] = TRUE
|
|
else
|
|
SSshuttle.shuttle_purchase_requirements_met[SHUTTLE_UNLOCK_SCRAPHEAP] = FALSE
|
|
|
|
/datum/bank_account/remote // Bank account not belonging to the local station
|
|
add_to_accounts = FALSE
|
|
|
|
/**
|
|
* Add log to transactions history. Deletes the oldest log when the history has more than 20 entries.
|
|
* Main format: Category: Reason in Reason. Example: Vending: Machinery Using
|
|
* Arguments:
|
|
* * adjusted_money - How much was added, negative values removing cash.
|
|
* * reason - The reason of interact with balance, for example, "Bought chips" or "Payday".
|
|
*/
|
|
/datum/bank_account/proc/add_log_to_history(adjusted_money, reason)
|
|
if(LAZYLEN(transaction_history) >= 20)
|
|
transaction_history.Cut(1,2)
|
|
|
|
LAZYADD(transaction_history, list(list(
|
|
"adjusted_money" = adjusted_money,
|
|
"reason" = reason,
|
|
)))
|
|
|
|
#undef DUMPTIME
|
|
#undef NO_MY_MONEY
|