/* 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 = "Automatic Teller Machine" desc = "For all your monetary needs!" icon = 'icons/obj/terminals.dmi' icon_state = "atm" anchored = 1 use_power = 1 idle_power_usage = 10 circuit = /obj/item/weapon/circuitboard/atm 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 var/datum/effect/effect/system/spark_spread/spark_system /obj/machinery/atm/New() ..() machine_id = "[station_name()] RT #[num_financial_terminals++]" spark_system = new /datum/effect/effect/system/spark_spread spark_system.set_up(5, 0, src) spark_system.attach(src) /obj/machinery/atm/process() if(stat & NOPOWER) return 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/emag_act(var/remaining_charges, var/mob/user) if(!emagged) return //short out the machine, shoot sparks, spew money! emagged = 1 spark_system.start() spawn_money(rand(100,500),src.loc) //we don't want to grief people by locking their id in an emagged ATM release_held_id(user) //display a message to the user var/response = pick("Initiating withdraw. Have a nice day!", "CRITICAL ERROR: Activating cash chamber panic siphon.","PIN Code accepted! Emptying account balance.", "Jackpot!") user << "\icon[src] The [src] beeps: \"[response]\"" return 1 /obj/machinery/atm/attackby(obj/item/I as obj, mob/user as mob) if(istype(I, /obj/item/weapon/screwdriver) && circuit) user << "You start disconnecting the monitor." playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) if(do_after(user, 20)) var/obj/structure/frame/A = new /obj/structure/frame( src.loc ) var/obj/item/weapon/circuitboard/M = new circuit( A ) A.frame_type = "atm" A.pixel_x = pixel_x A.pixel_y = pixel_y A.circuit = M A.anchored = 1 for (var/obj/C in src) C.forceMove(loc) user << "You disconnect the monitor." A.state = 4 A.icon_state = "atm_4" M.deconstruct(src) qdel(src) return if(istype(I, /obj/item/weapon/card)) if(emagged > 0) //prevent inserting id into an emagged ATM user << "\red \icon[src] CARD READER ERROR. This system has been compromised!" return else if(istype(I,/obj/item/weapon/card/emag)) I.resolve_attackby(src, user) return 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) qdel(I) else ..() /obj/machinery/atm/attack_hand(mob/user as mob) if(istype(user, /mob/living/silicon)) user << "\red \icon[src] Artificial unit recognized. Artificial units do not currently receive monetary compensation, as per system banking regulation #1005." return if(get_dist(src,user) <= 1) //js replicated from obj/machinery/computer/card var/dat = "

Automatic Teller Machine

" dat += "For all your monetary needs!
" dat += "This terminal is [machine_id]. Report this code when contacting IT Support
" if(emagged > 0) dat += "Card: LOCKED

Unauthorized terminal access detected! This ATM has been locked. Please contact IT Support." else 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) if(authenticated_account.suspended) dat += "\redAccess to this account has been suspended, and the funds within frozen." else 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]
" dat += "Print
" 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 += " Cash Chargecard
" dat += "" dat += "
" dat += "Change account security level
" dat += "Make transfer
" dat += "View transaction log
" dat += "Print balance statement
" dat += "Logout
" else dat += "
" dat += "" dat += "" dat += "Account:
" dat += "PIN:
" dat += "
" dat += "
" 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) var/transfer_amount = text2num(href_list["funds_amount"]) transfer_amount = round(transfer_amount, 0.01) 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(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") // check if they have low security enabled scan_user(usr) if(!ticks_left_locked_down && held_card) 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 = 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, 'sound/machines/buzz-two.ogg', 50, 1) //create an entry in the account transaction log var/datum/money_account/failed_account = 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, 'sound/machines/buzz-sigh.ogg', 50, 1) else usr << "\red \icon[src] incorrect pin/account combination entered." number_incorrect_tries = 0 else playsound(src, 'sound/machines/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("e_withdrawal") var/amount = max(text2num(href_list["funds_amount"]),0) amount = round(amount, 0.01) if(amount <= 0) alert("That is not a valid amount.") else if(authenticated_account && amount > 0) if(amount <= authenticated_account.money) playsound(src, 'sound/machines/chime.ogg', 50, 1) //remove the money authenticated_account.money -= amount // spawn_money(amount,src.loc) spawn_ewallet(amount,src.loc,usr) //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("withdrawal") var/amount = max(text2num(href_list["funds_amount"]),0) amount = round(amount, 0.01) if(amount <= 0) alert("That is not a valid amount.") else if(authenticated_account && amount > 0) if(amount <= authenticated_account.money) playsound(src, 'sound/machines/chime.ogg', 50, 1) //remove the money authenticated_account.money -= amount spawn_money(amount,src.loc,usr) //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 ("print_transaction") if(authenticated_account) var/obj/item/weapon/paper/R = new(src.loc) R.name = "Transaction logs: [authenticated_account.owner_name]" R.info = "Transaction logs
" R.info += "Account holder: [authenticated_account.owner_name]
" R.info += "Account number: [authenticated_account.account_number]
" R.info += "Date and time: [worldtime2text()], [current_date_string]

" R.info += "Service terminal ID: [machine_id]
" R.info += "" R.info += "" R.info += "" R.info += "" R.info += "" R.info += "" R.info += "" R.info += "" R.info += "" for(var/datum/transaction/T in authenticated_account.transaction_log) R.info += "" R.info += "" R.info += "" R.info += "" R.info += "" R.info += "" R.info += "" R.info += "" R.info += "
DateTimeTargetPurposeValueSource terminal ID
[T.date][T.time][T.target_name][T.purpose]$[T.amount][T.source_terminal]
" //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) //this might happen if the user had the browser window open when somebody emagged it if(emagged > 0) usr << "\red \icon[src] The ATM card reader rejected your ID because this machine has been sabotaged!" 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 else release_held_id(usr) if("logout") authenticated_account = null //usr << browse(null,"window=atm") src.attack_hand(usr) //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) 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 = 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) view_screen = NO_SCREEN // put the currently held id on the ground or in the hand of the user /obj/machinery/atm/proc/release_held_id(mob/living/carbon/human/human_user as mob) if(!held_card) return held_card.loc = src.loc authenticated_account = null if(ishuman(human_user) && !human_user.get_active_hand()) human_user.put_in_hands(held_card) held_card = null /obj/machinery/atm/proc/spawn_ewallet(var/sum, loc, mob/living/carbon/human/human_user as mob) var/obj/item/weapon/spacecash/ewallet/E = new /obj/item/weapon/spacecash/ewallet(loc) if(ishuman(human_user) && !human_user.get_active_hand()) human_user.put_in_hands(E) E.worth = sum E.owner_name = authenticated_account.owner_name