/* TODO: give money an actual use (QM stuff, vending machines) send money to people (might be worth attaching money to custom database thing for this, instead of being in the ID) 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 name = "NanoTrasen Automatic Teller Machine" desc = "For all your monetary needs!" icon = 'terminals.dmi' icon_state = "atm" 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() ..() machine_id = "[station_name()] RT #[num_financial_terminals++]" /obj/machinery/atm/initialize() ..() reconnect_database() /obj/machinery/atm/process() if(stat & NOPOWER) return if(linked_db && ( (linked_db.stat & NOPOWER) || !linked_db.activated ) ) linked_db = null authenticated_account = null src.visible_message("\red \icon[src] [src] buzzes rudely, \"Connection to remote database lost.\"") updateDialog() 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-- if(ticks_left_locked_down <= 0) number_incorrect_tries = 0 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 machines) if( DB.z == src.z && !(DB.stat & NOPOWER) && DB.activated ) linked_db = DB break /obj/machinery/atm/attackby(obj/item/I as obj, mob/user as mob) 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 if(authenticated_account && held_card.associated_account_number != authenticated_account.account_number) authenticated_account = null else if(authenticated_account) if(istype(I,/obj/item/weapon/spacecash)) //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 << "You insert [I] into [src]." 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) //js replicated from obj/machinery/computer/card var/dat = "

NanoTrasen Automatic Teller Machine

" dat += "For all your monetary needs!
" dat += "This terminal is [machine_id]. Report this code when contacting NanoTrasen IT Support
" dat += "Card: [held_card ? held_card.name : "------"]

" if(ticks_left_locked_down > 0) dat += "Maximum number of pin attempts exceeded! Access to this ATM has been temporarily disabled." else if(authenticated_account) switch(view_screen) if(CHANGE_SECURITY_LEVEL) dat += "Select a new security level for this account:

" var/text = "Zero - Either the 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 = "[text]" dat += "[text]
" text = "One - An account number and pin must be manually entered to access this account and process transactions." if(authenticated_account.security_level != 1) text = "[text]" dat += "[text]
" 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 = "[text]" dat += "[text]

" dat += "Back" if(VIEW_TRANSACTION_LOGS) dat += "Transaction logs
" dat += "Back" dat += "" dat += "" dat += "" dat += "" dat += "" dat += "" dat += "" dat += "" dat += "" for(var/datum/transaction/T in authenticated_account.transaction_log) dat += "" dat += "" dat += "" dat += "" dat += "" dat += "" dat += "" dat += "" dat += "
DateTimeTargetPurposeValueSource terminal ID
[T.date][T.time][T.target_name][T.purpose]$[T.amount][T.source_terminal]
" if(TRANSFER_FUNDS) dat += "Account balance: $[authenticated_account.money]
" dat += "Back

" dat += "
" dat += "" dat += "" dat += "Target account number:
" dat += "Funds to transfer:
" dat += "Transaction purpose:
" dat += "
" dat += "
" else dat += "Welcome, [authenticated_account.owner_name].
" dat += "Account balance: $[authenticated_account.money]" dat += "
" dat += "" dat += "" dat += "
" dat += "
" dat += "Change account security level
" dat += "Make transfer
" dat += "View transaction log
" dat += "Print balance statement
" dat += "Logout
" else if(linked_db) dat += "
" dat += "" dat += "" dat += "Account:
" dat += "PIN:
" dat += "
" dat += "
" else dat += "Unable to connect to accounts database, please retry and if the issue persists contact NanoTrasen IT support." reconnect_database() user << browse(dat,"window=atm;size=550x650") else user << browse(null,"window=atm") /obj/machinery/atm/Topic(var/href, var/href_list) if(href_list["choice"]) switch(href_list["choice"]) if("transfer") if(authenticated_account && linked_db) var/transfer_amount = text2num(href_list["funds_amount"]) if(transfer_amount <= 0) alert("That is not a valid amount.") else if(transfer_amount <= authenticated_account.money) var/target_account_number = text2num(href_list["target_acc_number"]) var/transfer_purpose = href_list["purpose"] if(linked_db.charge_to_account(target_account_number, authenticated_account.owner_name, transfer_purpose, machine_id, transfer_amount)) usr << "\icon[src]Funds transfer successful." 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]Funds transfer failed." else usr << "\icon[src]You don't have enough funds to do that!" 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 && !ticks_left_locked_down) 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) number_incorrect_tries++ if(previous_account_number == tried_account_num) if(number_incorrect_tries > max_pin_attempts) //lock down the atm ticks_left_locked_down = 30 playsound(src, 'buzz-two.ogg', 50, 1) //create an entry in the account transaction log var/datum/money_account/failed_account = linked_db.get_account(tried_account_num) if(failed_account) var/datum/transaction/T = new() T.target_name = failed_account.owner_name T.purpose = "Unauthorised login attempt" T.source_terminal = machine_id T.date = current_date_string T.time = worldtime2text() failed_account.transaction_log.Add(T) else usr << "\red \icon[src] Incorrect pin/account combination entered, [max_pin_attempts - number_incorrect_tries] attempts remaining." previous_account_number = tried_account_num playsound(src, 'buzz-sigh.ogg', 50, 1) else usr << "\red \icon[src] incorrect pin/account combination entered." number_incorrect_tries = 0 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) usr << "\blue \icon[src] Access granted. Welcome user '[authenticated_account.owner_name].'" previous_account_number = tried_account_num if("withdrawal") var/amount = max(text2num(href_list["funds_amount"]),0) if(amount <= 0) alert("That is not a valid amount.") else 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]You don't have enough funds to do that!" 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 = "NT Automated Teller Account Statement

" R.info += "Account holder: [authenticated_account.owner_name]
" R.info += "Account number: [authenticated_account.account_number]
" R.info += "Balance: $[authenticated_account.money]
" R.info += "Date and time: [worldtime2text()], [current_date_string]

" R.info += "Service terminal ID: [machine_id]
" //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 += "
This paper has been stamped by the Automatic Teller Machine." 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 //usr << browse(null,"window=atm") 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(!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) if(authenticated_account) human_user << "\blue \icon[src] Access granted. Welcome user '[authenticated_account.owner_name].'" //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)