From a809609e0c96560fadd6de11f0a10a0d61d6ca01 Mon Sep 17 00:00:00 2001 From: Charlie Nolan Date: Fri, 24 Jan 2025 15:54:36 -0800 Subject: [PATCH] Handheld EFTPOS offering (#27978) * Handheld EFTPOS offering * Apply suggestions from code review Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com> Signed-off-by: Charlie Nolan --------- Signed-off-by: Charlie Nolan Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com> --- code/__DEFINES/status_effects.dm | 1 + code/datums/status_effects/neutral.dm | 23 +++ code/game/objects/items/weapons/cards_ids.dm | 21 +++ .../economy/economy_machinery/eftpos.dm | 26 +++- .../modules/mob/living/carbon/carbon_procs.dm | 5 +- .../mob/living/carbon/human/human_emote.dm | 25 +++ tgui/packages/tgui/interfaces/EFTPOS.js | 10 +- tgui/public/tgui.bundle.js | 144 +++++++++--------- 8 files changed, 172 insertions(+), 83 deletions(-) diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm index ff56ca0501d8..4b652b5265d8 100644 --- a/code/__DEFINES/status_effects.dm +++ b/code/__DEFINES/status_effects.dm @@ -200,6 +200,7 @@ #define STATUS_EFFECT_HIGHFIVE /datum/status_effect/high_five #define STATUS_EFFECT_DAP /datum/status_effect/high_five/dap +#define STATUS_EFFECT_OFFERING_EFTPOS /datum/status_effect/high_five/offering_eftpos #define STATUS_EFFECT_HANDSHAKE /datum/status_effect/high_five/handshake #define STATUS_EFFECT_RPS /datum/status_effect/high_five/rps diff --git a/code/datums/status_effects/neutral.dm b/code/datums/status_effects/neutral.dm index 3e4235a448b2..35604217d511 100644 --- a/code/datums/status_effects/neutral.dm +++ b/code/datums/status_effects/neutral.dm @@ -140,6 +140,29 @@ /datum/status_effect/high_five/dap/get_missed_message() return "sadly can't find anybody to give daps to, and daps [owner.p_themselves()]. Shameful." +/datum/status_effect/high_five/offering_eftpos + id = "offering_eftpos" + request = "holds out an EFTPOS device." + item_path = /obj/item/eftpos + +/datum/status_effect/high_five/offering_eftpos/get_missed_message() + return "pulls back the EFTPOS device." + +/datum/status_effect/high_five/offering_eftpos/on_apply() + owner.custom_emote(EMOTE_VISIBLE, request) + owner.create_point_bubble_from_path(item_path, FALSE) + RegisterSignal(owner, COMSIG_ATOM_RANGED_ATTACKED, PROC_REF(on_ranged_attack)) + return TRUE + +/datum/status_effect/high_five/offering_eftpos/on_remove() + UnregisterSignal(owner, COMSIG_ATOM_RANGED_ATTACKED) + +/datum/status_effect/high_five/offering_eftpos/proc/on_ranged_attack(mob/living/me, mob/living/carbon/human/attacker) + SIGNAL_HANDLER // COMSIG_ATOM_RANGED_ATTACKED + if(get_dist(me, attacker) <= 2) + to_chat(attacker, "You need to have your ID in hand to scan it!") + return COMPONENT_CANCEL_ATTACK_CHAIN + /datum/status_effect/high_five/handshake id = "handshake" critical_success = "give each other an EPIC handshake!" diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm index 0ceb7d17a35e..d1b2605b4b99 100644 --- a/code/game/objects/items/weapons/cards_ids.dm +++ b/code/game/objects/items/weapons/cards_ids.dm @@ -165,6 +165,27 @@ if(can_id_flash) flash_card(user) +/obj/item/card/id/interact_with_atom(atom/target, mob/living/user, list/modifiers) + if(!isliving(target)) + return NONE + return shared_interact(target, user) + +/obj/item/card/id/ranged_interact_with_atom(atom/target, mob/living/user, list/modifiers) + if(isliving(target) && get_dist(target, user) <= 2) + return shared_interact(target, user) + return NONE + +/obj/item/card/id/proc/shared_interact(mob/living/victim, mob/living/user) + if(victim.has_status_effect(STATUS_EFFECT_OFFERING_EFTPOS)) + var/obj/item/eftpos/eftpos = victim.is_holding_item_of_type(/obj/item/eftpos) + if(!eftpos || !eftpos.can_offer) + to_chat(user, "They don't seem to have it in hand anymore.") + return ITEM_INTERACT_COMPLETE + victim.remove_status_effect(STATUS_EFFECT_OFFERING_EFTPOS) + eftpos.scan_card(src, user) + return ITEM_INTERACT_COMPLETE + return NONE + /obj/item/card/id/proc/UpdateName() name = "[registered_name]'s ID Card ([assignment])" diff --git a/code/modules/economy/economy_machinery/eftpos.dm b/code/modules/economy/economy_machinery/eftpos.dm index ef7dd5c83007..0502575529a7 100644 --- a/code/modules/economy/economy_machinery/eftpos.dm +++ b/code/modules/economy/economy_machinery/eftpos.dm @@ -23,6 +23,8 @@ var/datum/money_account_database/main_station/account_database ///Current money account the EFTPOS is depositing to var/datum/money_account/linked_account + ///Is this a portable unit that you can offer with *payme? + var/can_offer = TRUE /obj/item/eftpos/Initialize(mapload) machine_name = "EFTPOS #[rand(101, 999)]" @@ -80,6 +82,7 @@ ) data["available_accounts"] += list(account_data) + data["can_offer"] = can_offer return data @@ -148,21 +151,27 @@ else if(istype(I, /obj/item/card/emag)) access_code = 0 to_chat(user, "[bicon(src)]Access code reset to 0.") + if("offer") + if(can_offer) + offer(user) +/obj/item/eftpos/proc/offer(mob/living/user) + user.apply_status_effect(STATUS_EFFECT_OFFERING_EFTPOS) /obj/item/eftpos/proc/scan_card(obj/item/card/id/C, mob/user, secured = TRUE) - visible_message("[user] swipes a card through [src].") - if(!transaction_locked || transaction_paid || !secured) + visible_message("[user] swipes a card through [src], but nothing happens.") return + visible_message("[user] swipes a card through [src].") + if(!linked_account) - to_chat(user, "[bicon(src)]EFTPOS is not connected to an account.") + visible_message("[bicon(src)][src] buzzes as its display flashes \"EFTPOS is not connected to an account.\"", "You hear something buzz.") return var/datum/money_account/D = GLOB.station_money_database.find_user_account(C.associated_account_number, include_departments = FALSE) if(!D) - to_chat(user, "Your currently in use card is not connected to a money account.") + visible_message("[bicon(src)][src] buzzes as its display flashes \"Card is not connected to an account.\"", "You hear something buzz.") return //if security level high enough, prompt for pin var/attempt_pin @@ -172,19 +181,19 @@ return //given the credentials, can the associated account be accessed right now? if(!GLOB.station_money_database.try_authenticate_login(D, attempt_pin, restricted_bypass = FALSE)) - to_chat(user, "[bicon(src)]Unable to access account, insufficient access.") + visible_message("[bicon(src)][src] buzzes as its display flashes \"Access denied.\"", "You hear something buzz.") return if(tgui_alert(user, "Are you sure you want to pay $[transaction_amount] to: [linked_account.account_name]", "Confirm transaction", list("Yes", "No")) != "Yes") return - if(!Adjacent(user)) + if(!Adjacent(user) && !(can_offer && get_dist(user, src) <= 2)) return //attempt to charge account money if(!GLOB.station_money_database.charge_account(D, transaction_amount, transaction_purpose, machine_name, FALSE, FALSE)) - to_chat(user, "[bicon(src)]Insufficient credits in your account!") + visible_message("[bicon(src)][src] buzzes as its display flashes \"Insufficient funds.\"", "You hear something buzz.") return GLOB.station_money_database.credit_account(linked_account, transaction_amount, transaction_purpose, machine_name, FALSE) playsound(src, transaction_sound, 50, TRUE) - visible_message("[src] chimes!") + visible_message("[bicon(src)][src] chimes as its display reads \"Transaction successful!\"", "You hear something chime.") transaction_paid = TRUE addtimer(VARSET_CALLBACK(src, transaction_paid, FALSE), 5 SECONDS) @@ -232,6 +241,7 @@ pickup_sound = 'sound/items/handling/toolbox_pickup.ogg' transaction_sound = 'sound/machines/checkout.ogg' attack_verb = list("bounced a check off", "checked-out", "tipped") + can_offer = FALSE /obj/item/eftpos/register/examine(mob/user) . = ..() diff --git a/code/modules/mob/living/carbon/carbon_procs.dm b/code/modules/mob/living/carbon/carbon_procs.dm index 60219a1527d3..627462816711 100644 --- a/code/modules/mob/living/carbon/carbon_procs.dm +++ b/code/modules/mob/living/carbon/carbon_procs.dm @@ -234,7 +234,10 @@ return // If it has any of the highfive statuses, dap, handshake, etc var/datum/status_effect/effect = has_status_effect_type(STATUS_EFFECT_HIGHFIVE) - if(effect) + if(istype(effect, STATUS_EFFECT_OFFERING_EFTPOS)) + to_chat(M, "You need to have your ID in hand to scan it!") + return + else if(effect) M.apply_status_effect(effect.type) return // BEGIN HUGCODE - N3X diff --git a/code/modules/mob/living/carbon/human/human_emote.dm b/code/modules/mob/living/carbon/human/human_emote.dm index 3d89e7c0f22b..8d85ec818445 100644 --- a/code/modules/mob/living/carbon/human/human_emote.dm +++ b/code/modules/mob/living/carbon/human/human_emote.dm @@ -404,6 +404,31 @@ status = STATUS_EFFECT_DAP key_third_person = "daps" +/datum/emote/living/carbon/human/highfive/payme + key = "payme" + status = STATUS_EFFECT_OFFERING_EFTPOS + +/datum/emote/living/carbon/human/highfive/payme/run_emote(mob/living/user, params, type_override, intentional) + var/obj/item/eftpos/eftpos = user.is_holding_item_of_type(/obj/item/eftpos) + if(!eftpos) + to_chat(user, "You must be holding an EFTPOS to do that!") + return TRUE + if(!eftpos.can_offer) + to_chat(user, "[eftpos] is too bulky to hold out to someone!") + return TRUE + if(!eftpos.transaction_locked) + to_chat(user, "You must lock [eftpos] before it can accept payments.") + return TRUE + if(user.has_status_effect(status)) + user.visible_message("[user.name] shakes [eftpos] around slightly, impatiently waiting for someone to scan their card.") + return TRUE + + var/datum/result = set_status(user) + if(QDELETED(result)) + return TRUE + + return TRUE + /datum/emote/living/carbon/human/highfive/handshake key = "handshake" key_third_person = "handshakes" diff --git a/tgui/packages/tgui/interfaces/EFTPOS.js b/tgui/packages/tgui/interfaces/EFTPOS.js index d72cb52bf190..2c32259dde4a 100644 --- a/tgui/packages/tgui/interfaces/EFTPOS.js +++ b/tgui/packages/tgui/interfaces/EFTPOS.js @@ -37,7 +37,7 @@ export const EFTPOS = (props, context) => { const LockedView = (props, context) => { const { act, data } = useBackend(context); - const { transaction_amount, transaction_paid } = data; + const { transaction_amount, transaction_paid, can_offer } = data; return ( <> { ? 'This transaction has been processed successfully ' : 'Swipe your card to finish this transaction.'} + {(can_offer && ( + +