mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-17 18:13:34 +01:00
money! re-added atms, created account system / accounts database, whole bunch of options for moving money around, some tweaks to spacecash and icons
Signed-off-by: Cael_Aislinn <cael_aislinn@yahoo.com.au>
This commit is contained in:
@@ -0,0 +1,298 @@
|
||||
var/global/current_date_string
|
||||
var/global/num_financial_terminals = 1
|
||||
var/global/datum/money_account/station_account
|
||||
var/global/next_account_number = 0
|
||||
|
||||
/proc/create_station_account()
|
||||
if(!station_account)
|
||||
next_account_number = rand(111111, 999999)
|
||||
|
||||
station_account = new()
|
||||
station_account.owner_name = "[station_name()] Station Account"
|
||||
station_account.account_number = rand(111111, 999999)
|
||||
station_account.remote_access_pin = rand(1111, 111111)
|
||||
station_account.money = 10000
|
||||
|
||||
//create an entry in the account transaction log for when it was created
|
||||
var/datum/transaction/T = new()
|
||||
T.target_name = station_account.owner_name
|
||||
T.purpose = "Account creation"
|
||||
T.amount = 10000
|
||||
T.date = "2nd April, 2555"
|
||||
T.time = "11:24"
|
||||
T.source_terminal = "Biesel GalaxyNet Terminal #277"
|
||||
|
||||
//add the account
|
||||
station_account.transaction_log.Add(T)
|
||||
for(var/obj/machinery/account_database/A in world)
|
||||
A.accounts.Add(station_account)
|
||||
|
||||
//the current ingame time (hh:mm) can be obtained by calling:
|
||||
//worldtime2text()
|
||||
|
||||
/datum/money_account
|
||||
var/owner_name = ""
|
||||
var/account_number = 0
|
||||
var/remote_access_pin = 0
|
||||
var/money = 0
|
||||
var/list/transaction_log = list()
|
||||
var/security_level = 1 //0 - auto-identify from worn ID, require only account number
|
||||
//1 - require manual login / account number and pin
|
||||
//2 - require card and manual login
|
||||
|
||||
/datum/transaction
|
||||
var/target_name = ""
|
||||
var/purpose = ""
|
||||
var/amount = 0
|
||||
var/date = ""
|
||||
var/time = ""
|
||||
var/source_terminal = ""
|
||||
|
||||
/obj/machinery/account_database
|
||||
name = "Accounts database"
|
||||
desc = "Holds transaction logs, account data and all kinds of other financial records."
|
||||
icon = 'virology.dmi'
|
||||
icon_state = "analyser"
|
||||
density = 1
|
||||
var/list/accounts = list()
|
||||
req_one_access = list(access_hop, access_captain)
|
||||
var/receipt_num
|
||||
var/machine_id = ""
|
||||
var/obj/item/weapon/card/id/held_card
|
||||
var/access_level = 0
|
||||
var/datum/money_account/detailed_account_view
|
||||
var/creating_new_account = 0
|
||||
|
||||
/obj/machinery/account_database/New()
|
||||
..()
|
||||
if(!station_account)
|
||||
create_station_account()
|
||||
|
||||
if(!current_date_string)
|
||||
current_date_string = "[num2text(rand(1,31))] [pick("January","February","March","April","May","June","July","August","September","October","November","December")], 2557"
|
||||
|
||||
machine_id = "[station_name()] Acc. DB #[num_financial_terminals++]"
|
||||
|
||||
/obj/machinery/account_database/attack_hand(mob/user as mob)
|
||||
if(get_dist(src,user) <= 1)
|
||||
var/dat = "<b>Accounts Database</b><br>"
|
||||
dat += "<i>[machine_id]</i><br>"
|
||||
dat += "Confirm identity: <a href='?src=\ref[src];choice=insert_card'>[held_card ? held_card : "-----"]</a><br>"
|
||||
|
||||
if(access_level > 0)
|
||||
dat += "You may not edit accounts at this terminal, only create and view them.<br>"
|
||||
if(creating_new_account)
|
||||
dat += "<br>"
|
||||
dat += "<a href='?src=\ref[src];choice=view_accounts_list;'>Return to accounts list</a>"
|
||||
dat += "<form name='create_account' action='?src=\ref[src]' method='get'>"
|
||||
dat += "<input type='hidden' name='src' value='\ref[src]'>"
|
||||
dat += "<input type='hidden' name='choice' value='finalise_create_account'>"
|
||||
dat += "<b>Holder name:</b> <input type='text' id='holder_name' name='holder_name' style='width:250px; background-color:white;'><br>"
|
||||
dat += "<b>Initial funds:</b> <input type='text' id='starting_funds' name='starting_funds' style='width:250px; background-color:white;'> (subtracted from station account)<br>"
|
||||
dat += "<i>New accounts are automatically assigned a secret number and pin, which are printed separately in a sealed package.</i><br>"
|
||||
dat += "<input type='submit' value='Create'><br>"
|
||||
dat += "</form>"
|
||||
else
|
||||
if(detailed_account_view)
|
||||
dat += "<br>"
|
||||
dat += "<a href='?src=\ref[src];choice=view_accounts_list;'>Return to accounts list</a><hr>"
|
||||
dat += "<b>Account number:</b> #[detailed_account_view.account_number]<br>"
|
||||
dat += "<b>Account holder:</b> [detailed_account_view.owner_name]<br>"
|
||||
dat += "<b>Account balance:</b> $[detailed_account_view.money]<br>"
|
||||
dat += "<table border=1 style='width:100%'>"
|
||||
dat += "<tr>"
|
||||
dat += "<td><b>Date</b></td>"
|
||||
dat += "<td><b>Time</b></td>"
|
||||
dat += "<td><b>Target</b></td>"
|
||||
dat += "<td><b>Purpose</b></td>"
|
||||
dat += "<td><b>Value</b></td>"
|
||||
dat += "<td><b>Source terminal ID</b></td>"
|
||||
dat += "</tr>"
|
||||
for(var/datum/transaction/T in detailed_account_view.transaction_log)
|
||||
dat += "<tr>"
|
||||
dat += "<td>[T.date]</td>"
|
||||
dat += "<td>[T.time]</td>"
|
||||
dat += "<td>[T.target_name]</td>"
|
||||
dat += "<td>[T.purpose]</td>"
|
||||
dat += "<td>$[T.amount]</td>"
|
||||
dat += "<td>[T.source_terminal]</td>"
|
||||
dat += "</tr>"
|
||||
dat += "</table>"
|
||||
else
|
||||
dat += "<a href='?src=\ref[src];choice=create_account;'>Create new account</a> <a href='?src=\ref[src];choice=sync_accounts;'>Sync accounts across databases</a><br><br>"
|
||||
dat += "<table border=1 style='width:100%'>"
|
||||
for(var/i=1, i<=accounts.len, i++)
|
||||
var/datum/money_account/D = accounts[i]
|
||||
dat += "<tr>"
|
||||
dat += "<td>#[D.account_number]</td>"
|
||||
dat += "<td>[D.owner_name]</td>"
|
||||
dat += "<td><a href='?src=\ref[src];choice=view_account_detail;account_index=[i]'>View in detail</a></td>"
|
||||
dat += "</tr>"
|
||||
dat += "</table>"
|
||||
|
||||
user << browse(dat,"window=account_db;size=700x650")
|
||||
else
|
||||
user << browse(null,"window=account_db")
|
||||
|
||||
/obj/machinery/account_database/attackby(O as obj, user as mob)//TODO:SANITY
|
||||
if(istype(O, /obj/item/weapon/card))
|
||||
var/obj/item/weapon/card/id/idcard = O
|
||||
if(!held_card)
|
||||
usr.drop_item()
|
||||
idcard.loc = src
|
||||
held_card = idcard
|
||||
|
||||
if(access_cent_captain in idcard.access)
|
||||
access_level = 2
|
||||
else if(access_hop in idcard.access || access_captain in idcard.access)
|
||||
access_level = 1
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/machinery/account_database/Topic(var/href, var/href_list)
|
||||
if(href_list["choice"])
|
||||
switch(href_list["choice"])
|
||||
if("sync_accounts")
|
||||
for(var/obj/machinery/account_database/A in world)
|
||||
for(var/datum/money_account/M in src.accounts)
|
||||
if(!A.accounts.Find(M))
|
||||
A.accounts.Add(M)
|
||||
usr << "\icon[src] <span class='info'>Accounts synched across all databases in range.</span>"
|
||||
|
||||
if("create_account")
|
||||
creating_new_account = 1
|
||||
if("finalise_create_account")
|
||||
var/account_name = href_list["holder_name"]
|
||||
var/starting_funds = max(text2num(href_list["starting_funds"]), 0)
|
||||
add_account(account_name, starting_funds)
|
||||
if(starting_funds > 0)
|
||||
//subtract the money
|
||||
station_account.money -= starting_funds
|
||||
|
||||
//create a transaction log entry
|
||||
var/datum/transaction/T = new()
|
||||
T.target_name = account_name
|
||||
T.purpose = "New account funds initialisation"
|
||||
T.amount = "([starting_funds])"
|
||||
T.date = current_date_string
|
||||
T.time = worldtime2text()
|
||||
T.source_terminal = machine_id
|
||||
station_account.transaction_log.Add(T)
|
||||
|
||||
creating_new_account = 0
|
||||
if("insert_card")
|
||||
if(held_card)
|
||||
held_card.loc = src.loc
|
||||
|
||||
if(ishuman(usr) && !usr.get_active_hand())
|
||||
usr.put_in_hands(held_card)
|
||||
held_card = null
|
||||
access_level = 0
|
||||
|
||||
else
|
||||
var/obj/item/I = usr.get_active_hand()
|
||||
if (istype(I, /obj/item/weapon/card/id))
|
||||
var/obj/item/weapon/card/id/C = I
|
||||
usr.drop_item()
|
||||
C.loc = src
|
||||
held_card = C
|
||||
|
||||
if(access_cent_captain in C.access)
|
||||
access_level = 2
|
||||
else if(access_hop in C.access || access_captain in C.access)
|
||||
access_level = 1
|
||||
if("view_account_detail")
|
||||
var/index = text2num(href_list["account_index"])
|
||||
if(index && index <= accounts.len)
|
||||
detailed_account_view = accounts[index]
|
||||
if("view_accounts_list")
|
||||
detailed_account_view = null
|
||||
creating_new_account = 0
|
||||
|
||||
src.attack_hand(usr)
|
||||
|
||||
/obj/machinery/account_database/proc/add_account(var/new_owner_name = "Default user", var/starting_funds = 0, var/pre_existing = 0)
|
||||
|
||||
//create a new account
|
||||
var/datum/money_account/M = new()
|
||||
M.owner_name = new_owner_name
|
||||
M.remote_access_pin = rand(1111, 111111)
|
||||
M.money = starting_funds
|
||||
|
||||
//create an entry in the account transaction log for when it was created
|
||||
var/datum/transaction/T = new()
|
||||
T.target_name = new_owner_name
|
||||
T.purpose = "Account creation"
|
||||
T.amount = starting_funds
|
||||
if(pre_existing)
|
||||
//set a random date, time and location some time over the past few decades
|
||||
T.date = "[num2text(rand(1,31))] [pick("January","February","March","April","May","June","July","August","September","October","November","December")], 25[rand(10,56)]"
|
||||
T.time = "[rand(0,24)]:[rand(11,59)]"
|
||||
T.source_terminal = "NTGalaxyNet Terminal #[rand(111,1111)]"
|
||||
|
||||
M.account_number = rand(111111, 999999)
|
||||
else
|
||||
T.date = current_date_string
|
||||
T.time = worldtime2text()
|
||||
T.source_terminal = machine_id
|
||||
|
||||
M.account_number = next_account_number
|
||||
next_account_number += rand(1,25)
|
||||
|
||||
//create a sealed package containing the account details
|
||||
var/obj/item/smallDelivery/P = new(src.loc)
|
||||
|
||||
var/obj/item/weapon/paper/R = new(P)
|
||||
P.wrapped = R
|
||||
R.name = "Account information: [M.owner_name]"
|
||||
R.info = "<b>Account details (confidential)</b><br><hr><br>"
|
||||
R.info += "<i>Account holder:</i> [M.owner_name]<br>"
|
||||
R.info += "<i>Account number:</i> [M.account_number]<br>"
|
||||
R.info += "<i>Account pin:</i> [M.remote_access_pin]<br>"
|
||||
R.info += "<i>Starting balance:</i> $[M.money]<br>"
|
||||
R.info += "<i>Date and time:</i> [worldtime2text()], [current_date_string]<br><br>"
|
||||
R.info += "<i>Creation terminal ID:</i> [machine_id]<br>"
|
||||
R.info += "<i>Authorised NT officer overseeing creation:</i> [held_card.registered_name]<br>"
|
||||
|
||||
//stamp the paper
|
||||
var/image/stampoverlay = image('icons/obj/bureaucracy.dmi')
|
||||
stampoverlay.icon_state = "paper_stamp-cent"
|
||||
if(!R.stamped)
|
||||
R.stamped = new
|
||||
R.stamped += /obj/item/weapon/stamp
|
||||
R.overlays += stampoverlay
|
||||
R.stamps += "<HR><i>This paper has been stamped by the Accounts Database.</i>"
|
||||
|
||||
|
||||
//add the account
|
||||
M.transaction_log.Add(T)
|
||||
accounts.Add(M)
|
||||
|
||||
/obj/machinery/account_database/proc/charge_to_account(var/attempt_account_number, var/source_name, var/purpose, var/terminal_id, var/amount)
|
||||
for(var/datum/money_account/D in accounts)
|
||||
if(D.account_number == attempt_account_number)
|
||||
D.money += amount
|
||||
|
||||
//create a transaction log entry
|
||||
var/datum/transaction/T = new()
|
||||
T.target_name = source_name
|
||||
T.purpose = purpose
|
||||
if(amount < 0)
|
||||
T.amount = "([amount])"
|
||||
else
|
||||
T.amount = "[amount]"
|
||||
T.date = current_date_string
|
||||
T.time = worldtime2text()
|
||||
T.source_terminal = terminal_id
|
||||
D.transaction_log.Add(T)
|
||||
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
//this returns the first account datum that matches the supplied accnum/pin combination, it returns null if the combination did not match any account
|
||||
/obj/machinery/account_database/proc/attempt_account_access(var/attempt_account_number, var/attempt_pin_number, var/security_level_passed = 0)
|
||||
for(var/datum/money_account/D in accounts)
|
||||
if(D.account_number == attempt_account_number)
|
||||
if( D.security_level <= security_level_passed && (!D.security_level || D.remote_access_pin == attempt_pin_number) )
|
||||
return D
|
||||
@@ -0,0 +1,177 @@
|
||||
/obj/item/weapon/eftpos
|
||||
name = "EFTPOS scanner"
|
||||
desc = "Swipe your ID card to pay electronically."
|
||||
icon = 'icons/obj/library.dmi'
|
||||
icon_state = "scanner"
|
||||
var/machine_id = ""
|
||||
var/eftpos_name = "Default EFTPOS scanner"
|
||||
var/transaction_locked = 0
|
||||
var/transaction_paid = 0
|
||||
var/transaction_amount = 0
|
||||
var/transaction_purpose = "Default charge"
|
||||
var/access_code = 0
|
||||
var/obj/machinery/account_database/linked_db
|
||||
var/datum/money_account/linked_account
|
||||
|
||||
/obj/item/weapon/eftpos/New()
|
||||
..()
|
||||
machine_id = "[station_name()] EFTPOS #[num_financial_terminals++]"
|
||||
access_code = rand(1111,111111)
|
||||
reconnect_database()
|
||||
print_reference()
|
||||
|
||||
//by default, connect to the station account
|
||||
//the user of the EFTPOS device can change the target account though, and no-one will be the wiser (except whoever's being charged)
|
||||
linked_account = station_account
|
||||
|
||||
/obj/item/weapon/eftpos/proc/print_reference()
|
||||
var/obj/item/weapon/paper/R = new(get_turf(src))
|
||||
R.name = "Reference: [eftpos_name]"
|
||||
R.info = "<b>[eftpos_name] reference</b><br><br>"
|
||||
R.info += "Access code: [access_code]<br><br>"
|
||||
R.info += "<b>Do not lose this code, or the device will have to be replaced.</b><br>"
|
||||
|
||||
//stamp the paper
|
||||
var/image/stampoverlay = image('icons/obj/bureaucracy.dmi')
|
||||
stampoverlay.icon_state = "paper_stamp-cent"
|
||||
if(!R.stamped)
|
||||
R.stamped = new
|
||||
R.stamped += /obj/item/weapon/stamp
|
||||
R.overlays += stampoverlay
|
||||
R.stamps += "<HR><i>This paper has been stamped by the EFTPOS device.</i>"
|
||||
|
||||
/obj/item/weapon/eftpos/proc/reconnect_database()
|
||||
for(var/obj/machinery/account_database/DB in world)
|
||||
if(DB.z == src.z)
|
||||
linked_db = DB
|
||||
break
|
||||
|
||||
/obj/item/weapon/eftpos/attack_self(mob/user as mob)
|
||||
if(get_dist(src,user) <= 1)
|
||||
var/dat = "<b>[eftpos_name]</b><br>"
|
||||
dat += "<i>This terminal is</i> [machine_id]. <i>Report this code when contacting NanoTrasen IT Support</i><br>"
|
||||
if(transaction_locked)
|
||||
dat += "<a href='?src=\ref[src];choice=toggle_lock'>Reset[transaction_paid ? "" : " (authentication required)"]</a><br><br>"
|
||||
|
||||
dat += "Transaction purpose: <b>[transaction_purpose]</b><br>"
|
||||
dat += "Value: <b>$[transaction_amount]</b><br>"
|
||||
dat += "Linked account: <b>[linked_account ? linked_account.owner_name : "None"]</b><hr>"
|
||||
if(transaction_paid)
|
||||
dat += "<i>This transaction has been processed successfully.</i><hr>"
|
||||
else
|
||||
dat += "<i>Swipe your card below the line to finish this transaction.</i><hr>"
|
||||
dat += "<a href='?src=\ref[src];choice=scan_card'>\[------\]</a>"
|
||||
else
|
||||
dat += "<a href='?src=\ref[src];choice=toggle_lock'>Lock in new transaction</a><br><br>"
|
||||
|
||||
dat += "Transaction purpose: <a href='?src=\ref[src];choice=trans_purpose'>[transaction_purpose]</a><br>"
|
||||
dat += "Value: <a href='?src=\ref[src];choice=trans_value'>$[transaction_amount]</a><br>"
|
||||
dat += "Linked account: <a href='?src=\ref[src];choice=link_account'>[linked_account ? linked_account.owner_name : "None"]</a><hr>"
|
||||
dat += "<a href='?src=\ref[src];choice=change_code'>Change access code</a>"
|
||||
user << browse(dat,"window=eftpos")
|
||||
else
|
||||
user << browse(null,"window=eftpos")
|
||||
|
||||
/obj/item/weapon/eftpos/attackby(O as obj, user as mob)
|
||||
if(istype(O, /obj/item/weapon/card))
|
||||
//attempt to connect to a new db, and if that doesn't work then fail
|
||||
if(!linked_db)
|
||||
reconnect_database()
|
||||
if(linked_db && linked_account)
|
||||
var/obj/item/weapon/card/I = O
|
||||
scan_card(I)
|
||||
else
|
||||
usr << "\icon[src]<span class='warning'>Unable to connect to accounts database.</span>"
|
||||
else
|
||||
..()
|
||||
|
||||
/obj/item/weapon/eftpos/Topic(var/href, var/href_list)
|
||||
if(href_list["choice"])
|
||||
switch(href_list["choice"])
|
||||
if("change_code")
|
||||
var/attempt_code = text2num(input("Re-enter the current EFTPOS access code", "Confirm old EFTPOS code"))
|
||||
if(attempt_code == access_code)
|
||||
access_code = text2num(input("Enter a new access code for this device", "Enter new EFTPOS code"))
|
||||
print_reference()
|
||||
else
|
||||
usr << "\icon[src]<span class='warning'>Incorrect code entered.</span>"
|
||||
if("link_account")
|
||||
if(linked_db)
|
||||
var/attempt_account_num = text2num(input("Enter account number to pay EFTPOS charges into", "New account number"))
|
||||
var/attempt_pin = text2num(input("Enter pin code", "Account pin"))
|
||||
linked_account = linked_db.attempt_account_access(attempt_account_num, attempt_pin, 1)
|
||||
else
|
||||
usr << "<span class='warning'>Unable to connect to accounts database.</span>"
|
||||
if("trans_purpose")
|
||||
transaction_purpose = input("Enter reason for EFTPOS transaction", "Transaction purpose")
|
||||
if("trans_value")
|
||||
transaction_amount = max(text2num(input("Enter amount for EFTPOS transaction", "Transaction amount")),0)
|
||||
if("toggle_lock")
|
||||
if(transaction_locked)
|
||||
var/attempt_code = text2num(input("Enter EFTPOS access code", "Reset Transaction"))
|
||||
if(attempt_code == access_code)
|
||||
transaction_locked = 0
|
||||
transaction_paid = 0
|
||||
else if(linked_account)
|
||||
transaction_locked = 1
|
||||
else
|
||||
usr << "\icon[src] <span class='warning'>No account connected to send transactions to.</span>"
|
||||
if("scan_card")
|
||||
//attempt to connect to a new db, and if that doesn't work then fail
|
||||
if(!linked_db)
|
||||
reconnect_database()
|
||||
if(linked_db && linked_account)
|
||||
var/obj/item/I = usr.get_active_hand()
|
||||
if (istype(I, /obj/item/weapon/card))
|
||||
scan_card(I)
|
||||
else
|
||||
usr << "\icon[src]<span class='warning'>Unable to link accounts.</span>"
|
||||
|
||||
src.attack_self(usr)
|
||||
|
||||
/obj/item/weapon/eftpos/proc/scan_card(var/obj/item/weapon/card/I)
|
||||
if (istype(I, /obj/item/weapon/card/id))
|
||||
var/obj/item/weapon/card/id/C = I
|
||||
visible_message("<span class='info'>[usr] swipes a card through [src].</span>")
|
||||
if(transaction_locked && !transaction_paid)
|
||||
if(linked_account)
|
||||
var/attempt_pin = text2num(input("Enter pin code", "EFTPOS transaction"))
|
||||
var/datum/money_account/D = linked_db.attempt_account_access(C.associated_account_number, attempt_pin, 2)
|
||||
if(D)
|
||||
if(transaction_amount <= D.money)
|
||||
playsound(src, 'chime.ogg', 50, 1)
|
||||
src.visible_message("\icon[src] The [src] chimes.")
|
||||
transaction_paid = 1
|
||||
|
||||
//transfer the money
|
||||
D.money -= transaction_amount
|
||||
linked_account.money += transaction_amount
|
||||
|
||||
//create entries in the two account transaction logs
|
||||
var/datum/transaction/T = new()
|
||||
T.target_name = "[linked_account.owner_name] ([eftpos_name])"
|
||||
T.purpose = transaction_purpose
|
||||
T.amount = "([transaction_amount])"
|
||||
T.source_terminal = machine_id
|
||||
T.date = current_date_string
|
||||
T.time = worldtime2text()
|
||||
D.transaction_log.Add(T)
|
||||
//
|
||||
T = new()
|
||||
T.target_name = D.owner_name
|
||||
T.purpose = transaction_purpose
|
||||
T.amount = "[transaction_amount]"
|
||||
T.source_terminal = machine_id
|
||||
T.date = current_date_string
|
||||
T.time = worldtime2text()
|
||||
linked_account.transaction_log.Add(T)
|
||||
else
|
||||
usr << "\icon[src]<span class='warning'>You don't have that much money!<span>"
|
||||
else
|
||||
usr << "\icon[src]<span class='warning'>EFTPOS is not connected to an account.<span>"
|
||||
else
|
||||
usr << "\icon[src]<span class='warning'>Unable to access account. Check security settings and try again.</span>"
|
||||
else
|
||||
..()
|
||||
|
||||
//emag?
|
||||
+332
-53
@@ -7,6 +7,11 @@ log transactions
|
||||
|
||||
*/
|
||||
|
||||
#define NO_SCREEN 0
|
||||
#define CHANGE_SECURITY_LEVEL 1
|
||||
#define TRANSFER_FUNDS 2
|
||||
#define VIEW_TRANSACTION_LOGS 3
|
||||
|
||||
/obj/item/weapon/card/id/var/money = 2000
|
||||
|
||||
/obj/machinery/atm
|
||||
@@ -17,72 +22,346 @@ log transactions
|
||||
anchored = 1
|
||||
use_power = 1
|
||||
idle_power_usage = 10
|
||||
var/obj/machinery/account_database/linked_db
|
||||
var/datum/money_account/authenticated_account
|
||||
var/number_incorrect_tries = 0
|
||||
var/previous_account_number = 0
|
||||
var/max_pin_attempts = 3
|
||||
var/ticks_left_locked_down = 0
|
||||
var/ticks_left_timeout = 0
|
||||
var/machine_id = ""
|
||||
var/obj/item/weapon/card/held_card
|
||||
var/editing_security_level = 0
|
||||
var/view_screen = NO_SCREEN
|
||||
|
||||
/obj/machinery/atm/New()
|
||||
..()
|
||||
reconnect_database()
|
||||
machine_id = "[station_name()] RT #[num_financial_terminals++]"
|
||||
|
||||
/obj/machinery/atm/process()
|
||||
if(ticks_left_timeout > 0)
|
||||
ticks_left_timeout--
|
||||
if(ticks_left_timeout <= 0)
|
||||
authenticated_account = null
|
||||
if(ticks_left_locked_down > 0)
|
||||
ticks_left_locked_down--
|
||||
|
||||
for(var/obj/item/weapon/spacecash/S in src)
|
||||
S.loc = src.loc
|
||||
if(prob(50))
|
||||
playsound(loc, 'sound/items/polaroid1.ogg', 50, 1)
|
||||
else
|
||||
playsound(loc, 'sound/items/polaroid2.ogg', 50, 1)
|
||||
break
|
||||
|
||||
/obj/machinery/atm/proc/reconnect_database()
|
||||
for(var/obj/machinery/account_database/DB in world)
|
||||
if(DB.z == src.z)
|
||||
linked_db = DB
|
||||
break
|
||||
|
||||
/obj/machinery/atm/attackby(obj/item/I as obj, mob/user as mob)
|
||||
if(ishuman(user))
|
||||
var/obj/item/weapon/card/id/user_id = src.scan_user(user)
|
||||
if(istype(I, /obj/item/weapon/card))
|
||||
var/obj/item/weapon/card/id/idcard = I
|
||||
if(!held_card)
|
||||
usr.drop_item()
|
||||
idcard.loc = src
|
||||
held_card = idcard
|
||||
authenticated_account = null
|
||||
else if(authenticated_account)
|
||||
if(istype(I,/obj/item/weapon/spacecash))
|
||||
user_id.money += I:worth
|
||||
//consume the money
|
||||
authenticated_account.money += I:worth
|
||||
if(prob(50))
|
||||
playsound(loc, 'sound/items/polaroid1.ogg', 50, 1)
|
||||
else
|
||||
playsound(loc, 'sound/items/polaroid2.ogg', 50, 1)
|
||||
|
||||
//create a transaction log entry
|
||||
var/datum/transaction/T = new()
|
||||
T.target_name = authenticated_account.owner_name
|
||||
T.purpose = "Credit deposit"
|
||||
T.amount = I:worth
|
||||
T.source_terminal = machine_id
|
||||
T.date = current_date_string
|
||||
T.time = worldtime2text()
|
||||
authenticated_account.transaction_log.Add(T)
|
||||
|
||||
user << "<span class='info'>You insert [I] into [src].</span>"
|
||||
src.attack_hand(user)
|
||||
del I
|
||||
else ..()
|
||||
|
||||
/obj/machinery/atm/attack_hand(mob/user as mob)
|
||||
if(istype(user, /mob/living/silicon))
|
||||
user << "\red Artificial unit recognized. Artificial units do not currently receive monetary compensation, as per NanoTrasen regulation #1005."
|
||||
return
|
||||
if(get_dist(src,user) <= 1)
|
||||
//check to see if the user has low security enabled
|
||||
scan_user(user)
|
||||
|
||||
var/obj/item/weapon/card/id/user_id = src.scan_user(user)
|
||||
if(..())
|
||||
return
|
||||
var/dat = ""
|
||||
dat += "<h1>NanoTrasen Automatic Teller Machine</h1><br/>"
|
||||
dat += "For all your monetary needs!<br/><br/>"
|
||||
dat += "Welcome, [user_id.registered_name].<br/>"
|
||||
dat += "You have $[user_id.money] in your account.<br/>"
|
||||
dat += "<a href=\"?src=\ref[src]&withdraw=1&id=\ref[user_id]\">Withdraw</a><br/>"
|
||||
user << browse(dat,"window=atm")
|
||||
//js replicated from obj/machinery/computer/card
|
||||
var/dat = "<h1>NanoTrasen Automatic Teller Machine</h1>"
|
||||
dat += "For all your monetary needs!<br>"
|
||||
dat += "<i>This terminal is</i> [machine_id]. <i>Report this code when contacting NanoTrasen IT Support</i><br/>"
|
||||
dat += "Card: <a href='?src=\ref[src];choice=insert_card'>[held_card ? held_card.name : "------"]</a><br><br>"
|
||||
|
||||
if(ticks_left_locked_down > 0)
|
||||
dat += "<span class='alert'>Maximum number of pin attempts exceeded! Access to this ATM has been temporarily disabled.</span>"
|
||||
else if(authenticated_account)
|
||||
switch(view_screen)
|
||||
if(CHANGE_SECURITY_LEVEL)
|
||||
dat += "Select a new security level for this account:<br><hr>"
|
||||
var/text = "Zero - Only account number or card is required to access this account. EFTPOS transactions will require a card and ask for a pin, but not verify the pin is correct."
|
||||
if(authenticated_account.security_level != 0)
|
||||
text = "<A href='?src=\ref[src];choice=change_security_level;new_security_level=0'>[text]</a>"
|
||||
dat += "[text]<hr>"
|
||||
text = "One - Both an account number and pin is required to access this account and process transactions."
|
||||
if(authenticated_account.security_level != 1)
|
||||
text = "<A href='?src=\ref[src];choice=change_security_level;new_security_level=1'>[text]</a>"
|
||||
dat += "[text]<hr>"
|
||||
text = "Two - In addition to account number and pin, a card is required to access this account and process transactions."
|
||||
if(authenticated_account.security_level != 2)
|
||||
text = "<A href='?src=\ref[src];choice=change_security_level;new_security_level=2'>[text]</a>"
|
||||
dat += "[text]<hr><br>"
|
||||
dat += "<A href='?src=\ref[src];choice=view_screen;view_screen=0'>Back</a>"
|
||||
if(VIEW_TRANSACTION_LOGS)
|
||||
dat += "<b>Transaction logs</b><br>"
|
||||
dat += "<A href='?src=\ref[src];choice=view_screen;view_screen=0'>Back</a>"
|
||||
dat += "<table border=1 style='width:100%'>"
|
||||
dat += "<tr>"
|
||||
dat += "<td><b>Date</b></td>"
|
||||
dat += "<td><b>Time</b></td>"
|
||||
dat += "<td><b>Target</b></td>"
|
||||
dat += "<td><b>Purpose</b></td>"
|
||||
dat += "<td><b>Value</b></td>"
|
||||
dat += "<td><b>Source terminal ID</b></td>"
|
||||
dat += "</tr>"
|
||||
for(var/datum/transaction/T in authenticated_account.transaction_log)
|
||||
dat += "<tr>"
|
||||
dat += "<td>[T.date]</td>"
|
||||
dat += "<td>[T.time]</td>"
|
||||
dat += "<td>[T.target_name]</td>"
|
||||
dat += "<td>[T.purpose]</td>"
|
||||
dat += "<td>$[T.amount]</td>"
|
||||
dat += "<td>[T.source_terminal]</td>"
|
||||
dat += "</tr>"
|
||||
dat += "</table>"
|
||||
if(TRANSFER_FUNDS)
|
||||
dat += "<b>Account balance:</b> $[authenticated_account.money]<br>"
|
||||
dat += "<A href='?src=\ref[src];choice=view_screen;view_screen=0'>Back</a><br><br>"
|
||||
dat += "<form name='transfer' action='?src=\ref[src]' method='get'>"
|
||||
dat += "<input type='hidden' name='src' value='\ref[src]'>"
|
||||
dat += "<input type='hidden' name='choice' value='transfer'>"
|
||||
dat += "Target account number: <input type='text' name='target_acc_number' value='' style='width:200px; background-color:white;'><br>"
|
||||
dat += "Funds to transfer: <input type='text' name='funds_amount' value='' style='width:200px; background-color:white;'><br>"
|
||||
dat += "Transaction purpose: <input type='text' name='purpose' value='Funds transfer' style='width:200px; background-color:white;'><br>"
|
||||
dat += "<input type='submit' value='Transfer funds'><br>"
|
||||
dat += "</form>"
|
||||
else
|
||||
dat += "Welcome, <b>[authenticated_account.owner_name].</b><br/>"
|
||||
dat += "<b>Account balance:</b> $[authenticated_account.money]"
|
||||
dat += "<form name='withdrawal' action='?src=\ref[src]' method='get'>"
|
||||
dat += "<input type='hidden' name='src' value='\ref[src]'>"
|
||||
dat += "<input type='hidden' name='choice' value='withdrawal'>"
|
||||
dat += "<input type='text' name='funds_amount' value='' style='width:200px; background-color:white;'><input type='submit' value='Withdraw funds'><br>"
|
||||
dat += "</form>"
|
||||
dat += "<A href='?src=\ref[src];choice=view_screen;view_screen=1'>Change account security level</a><br>"
|
||||
dat += "<A href='?src=\ref[src];choice=view_screen;view_screen=2'>Make transfer</a><br>"
|
||||
dat += "<A href='?src=\ref[src];choice=view_screen;view_screen=3'>View transaction log</a><br>"
|
||||
dat += "<A href='?src=\ref[src];choice=balance_statement'>Print balance statement</a><br>"
|
||||
dat += "<A href='?src=\ref[src];choice=logout'>Logout</a><br>"
|
||||
else if(linked_db)
|
||||
dat += "<form name='atm_auth' action='?src=\ref[src]' method='get'>"
|
||||
dat += "<input type='hidden' name='src' value='\ref[src]'>"
|
||||
dat += "<input type='hidden' name='choice' value='attempt_auth'>"
|
||||
dat += "<b>Account:</b> <input type='text' id='account_num' name='account_num' style='width:250px; background-color:white;'><br>"
|
||||
dat += "<b>PIN:</b> <input type='text' id='account_pin' name='account_pin' style='width:250px; background-color:white;'><br>"
|
||||
dat += "<input type='submit' value='Submit'><br>"
|
||||
dat += "</form>"
|
||||
else
|
||||
dat += "<span class='warning'>Unable to connect to accounts database, please retry and if the issue persists contact NanoTrasen IT support.</span>"
|
||||
reconnect_database()
|
||||
|
||||
user << browse(dat,"window=atm;size=500x650")
|
||||
else
|
||||
user << browse(null,"window=atm")
|
||||
|
||||
/obj/machinery/atm/Topic(var/href, var/href_list)
|
||||
if(href_list["withdraw"] && href_list["id"])
|
||||
var/amount = input("How much would you like to withdraw?", "Amount", 0) in list(1,10,20,50,100,200,500,1000, 0)
|
||||
var/obj/item/weapon/card/id/user_id = locate(href_list["id"])
|
||||
if(amount != 0 && user_id)
|
||||
if(amount <= user_id.money)
|
||||
user_id.money -= amount
|
||||
//hueg switch for giving moneh out
|
||||
switch(amount)
|
||||
if(1)
|
||||
new /obj/item/weapon/spacecash(loc)
|
||||
if(10)
|
||||
new /obj/item/weapon/spacecash/c10(loc)
|
||||
if(20)
|
||||
new /obj/item/weapon/spacecash/c20(loc)
|
||||
if(50)
|
||||
new /obj/item/weapon/spacecash/c50(loc)
|
||||
if(100)
|
||||
new /obj/item/weapon/spacecash/c100(loc)
|
||||
if(200)
|
||||
new /obj/item/weapon/spacecash/c200(loc)
|
||||
if(500)
|
||||
new /obj/item/weapon/spacecash/c500(loc)
|
||||
if(1000)
|
||||
new /obj/item/weapon/spacecash/c1000(loc)
|
||||
else
|
||||
usr << browse("You don't have that much money!<br/><a href=\"?src=\ref[src]\">Back</a>","window=atm")
|
||||
return
|
||||
if(href_list["choice"])
|
||||
switch(href_list["choice"])
|
||||
if("transfer")
|
||||
if(authenticated_account && linked_db)
|
||||
var/target_account_number = text2num(href_list["target_acc_number"])
|
||||
var/transfer_amount = text2num(href_list["funds_amount"])
|
||||
var/transfer_purpose = href_list["purpose"]
|
||||
if(transfer_amount <= authenticated_account.money)
|
||||
if(linked_db.charge_to_account(target_account_number, authenticated_account.owner_name, transfer_purpose, machine_id, transfer_amount))
|
||||
usr << "\icon[src]<span class='info'>Funds transfer successful.</span>"
|
||||
authenticated_account.money -= transfer_amount
|
||||
|
||||
//create an entry in the account transaction log
|
||||
var/datum/transaction/T = new()
|
||||
T.target_name = "Account #[target_account_number]"
|
||||
T.purpose = transfer_purpose
|
||||
T.source_terminal = machine_id
|
||||
T.date = current_date_string
|
||||
T.time = worldtime2text()
|
||||
T.amount = "([transfer_amount])"
|
||||
authenticated_account.transaction_log.Add(T)
|
||||
else
|
||||
usr << "\icon[src]<span class='warning'>Funds transfer failed.</span>"
|
||||
|
||||
else
|
||||
usr << "\icon[src]<span class='warning'>You don't have enough funds to do that!</span>"
|
||||
if("view_screen")
|
||||
view_screen = text2num(href_list["view_screen"])
|
||||
if("change_security_level")
|
||||
if(authenticated_account)
|
||||
var/new_sec_level = max( min(text2num(href_list["new_security_level"]), 2), 0)
|
||||
authenticated_account.security_level = new_sec_level
|
||||
if("attempt_auth")
|
||||
if(linked_db)
|
||||
var/tried_account_num = text2num(href_list["account_num"])
|
||||
if(!tried_account_num)
|
||||
tried_account_num = held_card.associated_account_number
|
||||
var/tried_pin = text2num(href_list["account_pin"])
|
||||
|
||||
authenticated_account = linked_db.attempt_account_access(tried_account_num, tried_pin, held_card && held_card.associated_account_number == tried_account_num ? 2 : 1)
|
||||
if(!authenticated_account)
|
||||
if(previous_account_number == tried_account_num)
|
||||
if(++number_incorrect_tries > max_pin_attempts)
|
||||
//lock down the atm
|
||||
number_incorrect_tries = 0
|
||||
ticks_left_locked_down = 10
|
||||
playsound(src, 'buzz-two.ogg', 50, 1)
|
||||
|
||||
//create an entry in the account transaction log
|
||||
var/datum/transaction/T = new()
|
||||
T.target_name = authenticated_account.owner_name
|
||||
T.purpose = "Unauthorised login attempt"
|
||||
T.source_terminal = machine_id
|
||||
T.date = current_date_string
|
||||
T.time = worldtime2text()
|
||||
authenticated_account.transaction_log.Add(T)
|
||||
else
|
||||
previous_account_number = tried_account_num
|
||||
number_incorrect_tries = 1
|
||||
playsound(src, 'buzz-sigh.ogg', 50, 1)
|
||||
else
|
||||
playsound(src, 'twobeep.ogg', 50, 1)
|
||||
ticks_left_timeout = 120
|
||||
view_screen = NO_SCREEN
|
||||
|
||||
//create a transaction log entry
|
||||
var/datum/transaction/T = new()
|
||||
T.target_name = authenticated_account.owner_name
|
||||
T.purpose = "Remote terminal access"
|
||||
T.source_terminal = machine_id
|
||||
T.date = current_date_string
|
||||
T.time = worldtime2text()
|
||||
authenticated_account.transaction_log.Add(T)
|
||||
if("withdrawal")
|
||||
var/amount = max(text2num(href_list["funds_amount"]),0)
|
||||
if(authenticated_account && amount > 0)
|
||||
if(amount <= authenticated_account.money)
|
||||
playsound(src, 'chime.ogg', 50, 1)
|
||||
|
||||
//remove the money
|
||||
authenticated_account.money -= amount
|
||||
withdraw_arbitrary_sum(amount)
|
||||
|
||||
//create an entry in the account transaction log
|
||||
var/datum/transaction/T = new()
|
||||
T.target_name = authenticated_account.owner_name
|
||||
T.purpose = "Credit withdrawal"
|
||||
T.amount = "([amount])"
|
||||
T.source_terminal = machine_id
|
||||
T.date = current_date_string
|
||||
T.time = worldtime2text()
|
||||
authenticated_account.transaction_log.Add(T)
|
||||
else
|
||||
usr << "\icon[src]<span class='warning'>You don't have enough funds to do that!</span>"
|
||||
if("balance_statement")
|
||||
if(authenticated_account)
|
||||
var/obj/item/weapon/paper/R = new(src.loc)
|
||||
R.name = "Account balance: [authenticated_account.owner_name]"
|
||||
R.info = "<b>NT Automated Teller Account Statement</b><br><br>"
|
||||
R.info += "<i>Account holder:</i> [authenticated_account.owner_name]<br>"
|
||||
R.info += "<i>Account number:</i> [authenticated_account.account_number]<br>"
|
||||
R.info += "<i>Balance:</i> $[authenticated_account.money]<br>"
|
||||
R.info += "<i>Date and time:</i> [worldtime2text()], [current_date_string]<br><br>"
|
||||
R.info += "<i>Service terminal ID:</i> [machine_id]<br>"
|
||||
|
||||
//stamp the paper
|
||||
var/image/stampoverlay = image('icons/obj/bureaucracy.dmi')
|
||||
stampoverlay.icon_state = "paper_stamp-cent"
|
||||
if(!R.stamped)
|
||||
R.stamped = new
|
||||
R.stamped += /obj/item/weapon/stamp
|
||||
R.overlays += stampoverlay
|
||||
R.stamps += "<HR><i>This paper has been stamped by the Automatic Teller Machine.</i>"
|
||||
|
||||
if(prob(50))
|
||||
playsound(loc, 'sound/items/polaroid1.ogg', 50, 1)
|
||||
else
|
||||
playsound(loc, 'sound/items/polaroid2.ogg', 50, 1)
|
||||
if("insert_card")
|
||||
if(held_card)
|
||||
held_card.loc = src.loc
|
||||
authenticated_account = null
|
||||
|
||||
if(ishuman(usr) && !usr.get_active_hand())
|
||||
usr.put_in_hands(held_card)
|
||||
held_card = null
|
||||
|
||||
else
|
||||
var/obj/item/I = usr.get_active_hand()
|
||||
if (istype(I, /obj/item/weapon/card/id))
|
||||
usr.drop_item()
|
||||
I.loc = src
|
||||
held_card = I
|
||||
if("logout")
|
||||
authenticated_account = null
|
||||
src.attack_hand(usr)
|
||||
|
||||
//create the most effective combination of notes to make up the requested amount
|
||||
/obj/machinery/atm/proc/withdraw_arbitrary_sum(var/arbitrary_sum)
|
||||
while(arbitrary_sum >= 1000)
|
||||
arbitrary_sum -= 1000
|
||||
new /obj/item/weapon/spacecash/c1000(src)
|
||||
while(arbitrary_sum >= 500)
|
||||
arbitrary_sum -= 500
|
||||
new /obj/item/weapon/spacecash/c500(src)
|
||||
while(arbitrary_sum >= 200)
|
||||
arbitrary_sum -= 200
|
||||
new /obj/item/weapon/spacecash/c200(src)
|
||||
while(arbitrary_sum >= 100)
|
||||
arbitrary_sum -= 100
|
||||
new /obj/item/weapon/spacecash/c100(src)
|
||||
while(arbitrary_sum >= 50)
|
||||
arbitrary_sum -= 50
|
||||
new /obj/item/weapon/spacecash/c50(src)
|
||||
while(arbitrary_sum >= 20)
|
||||
arbitrary_sum -= 20
|
||||
new /obj/item/weapon/spacecash/c20(src)
|
||||
while(arbitrary_sum >= 10)
|
||||
arbitrary_sum -= 10
|
||||
new /obj/item/weapon/spacecash/c10(src)
|
||||
while(arbitrary_sum >= 1)
|
||||
arbitrary_sum -= 1
|
||||
new /obj/item/weapon/spacecash(src)
|
||||
|
||||
//stolen wholesale and then edited a bit from newscasters, which are awesome and by Agouri
|
||||
/obj/machinery/atm/proc/scan_user(mob/living/carbon/human/human_user as mob)
|
||||
if(human_user.wear_id)
|
||||
if(istype(human_user.wear_id, /obj/item/device/pda) )
|
||||
var/obj/item/device/pda/P = human_user.wear_id
|
||||
if(P.id)
|
||||
return P.id
|
||||
else
|
||||
return null
|
||||
else if(istype(human_user.wear_id, /obj/item/weapon/card/id) )
|
||||
return human_user.wear_id
|
||||
else
|
||||
return null
|
||||
else
|
||||
return null
|
||||
if(!authenticated_account && linked_db)
|
||||
if(human_user.wear_id)
|
||||
var/obj/item/weapon/card/id/I
|
||||
if(istype(human_user.wear_id, /obj/item/weapon/card/id) )
|
||||
I = human_user.wear_id
|
||||
else if(istype(human_user.wear_id, /obj/item/device/pda) )
|
||||
var/obj/item/device/pda/P = human_user.wear_id
|
||||
I = P.id
|
||||
if(I)
|
||||
authenticated_account = linked_db.attempt_account_access(I.associated_account_number)
|
||||
|
||||
Reference in New Issue
Block a user