diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index be832e901aca..94c0f2e21ad5 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -17940,7 +17940,7 @@ /obj/effect/landmark/start/hangover, /obj/structure/table/wood, /obj/machinery/door/firedoor, -/obj/structure/displaycase/forsale/kitchen{ +/obj/structure/tipjar/prefilled{ pixel_y = 6 }, /turf/open/floor/iron/dark/smooth_half{ @@ -72330,7 +72330,7 @@ id = "cafe_counter"; name = "Kitchen Counter Shutters" }, -/obj/structure/displaycase/forsale/kitchen, +/obj/structure/tipjar/prefilled, /turf/open/floor/iron/white/smooth_corner{ dir = 8 }, diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index d8f1548a7f26..7f8f106f73ad 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -79857,7 +79857,7 @@ id = "kitchencounter"; name = "Kitchen Counter Shutters" }, -/obj/structure/displaycase/forsale/kitchen, +/obj/structure/tipjar/prefilled, /turf/open/floor/iron/white/smooth_large, /area/station/service/kitchen) "xEE" = ( @@ -81791,7 +81791,7 @@ /obj/structure/sign/picture_frame/portrait/bar{ pixel_x = 32 }, -/obj/structure/displaycase/forsale/kitchen{ +/obj/structure/tipjar/prefilled{ pixel_y = 8 }, /turf/open/floor/iron, diff --git a/_maps/map_files/KiloStation/KiloStation.dmm b/_maps/map_files/KiloStation/KiloStation.dmm index 6618b6e42b34..1a78eeabe303 100644 --- a/_maps/map_files/KiloStation/KiloStation.dmm +++ b/_maps/map_files/KiloStation/KiloStation.dmm @@ -7936,7 +7936,7 @@ /area/station/hallway/primary/central/fore) "aSq" = ( /obj/structure/table/wood, -/obj/structure/displaycase/forsale/kitchen{ +/obj/structure/tipjar/prefilled{ pixel_y = 4 }, /obj/structure/sign/picture_frame/portrait/bar{ @@ -61959,7 +61959,7 @@ /area/station/cargo/storage) "pLA" = ( /obj/structure/table/reinforced, -/obj/structure/displaycase/forsale/kitchen{ +/obj/structure/tipjar/prefilled{ pixel_y = 4 }, /obj/machinery/door/firedoor, diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index a5af6667bc51..765bc4435979 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -8800,7 +8800,7 @@ dir = 4; id = "abandoned_kitchen" }, -/obj/structure/displaycase/forsale/kitchen{ +/obj/structure/tipjar{ pixel_y = 8 }, /turf/open/floor/plating, @@ -18326,7 +18326,7 @@ /area/station/engineering/atmos) "eSv" = ( /obj/structure/table/reinforced, -/obj/structure/displaycase/forsale/kitchen{ +/obj/structure/tipjar/prefilled{ pixel_y = 8 }, /obj/machinery/computer/security/telescreen/entertainment/directional/west, @@ -49209,7 +49209,7 @@ }, /obj/effect/turf_decal/tile/bar/opposingcorners, /obj/structure/table/reinforced, -/obj/structure/displaycase/forsale/kitchen{ +/obj/structure/tipjar/prefilled{ pixel_y = 8 }, /obj/effect/turf_decal/siding/wood{ diff --git a/_maps/map_files/NebulaStation/NebulaStation.dmm b/_maps/map_files/NebulaStation/NebulaStation.dmm index 617853c5aadf..240fa2aac04b 100644 --- a/_maps/map_files/NebulaStation/NebulaStation.dmm +++ b/_maps/map_files/NebulaStation/NebulaStation.dmm @@ -56700,7 +56700,7 @@ /obj/machinery/light_switch/directional/west, /obj/machinery/status_display/evac/directional/north, /obj/structure/table/wood/fancy/red, -/obj/structure/displaycase/forsale/kitchen{ +/obj/structure/tipjar/prefilled{ pixel_y = 8 }, /turf/open/floor/wood/large, @@ -120892,7 +120892,7 @@ /area/space/nearstation) "rVX" = ( /obj/structure/table/wood/fancy/red, -/obj/structure/displaycase/forsale/kitchen{ +/obj/structure/tipjar/prefilled{ pixel_y = 8 }, /obj/machinery/newscaster/directional/south, diff --git a/_maps/map_files/NorthStar/north_star.dmm b/_maps/map_files/NorthStar/north_star.dmm index d065d3b3172b..64036b890c1b 100644 --- a/_maps/map_files/NorthStar/north_star.dmm +++ b/_maps/map_files/NorthStar/north_star.dmm @@ -12870,7 +12870,7 @@ /obj/effect/turf_decal/siding/wood{ dir = 8 }, -/obj/structure/displaycase/forsale/kitchen{ +/obj/structure/tipjar/prefilled{ pixel_y = 8 }, /turf/open/floor/iron/dark/smooth_large, @@ -78561,7 +78561,7 @@ /area/station/engineering/atmos) "umZ" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/displaycase/forsale/kitchen, +/obj/structure/tipjar/prefilled, /obj/structure/table/reinforced, /turf/open/floor/iron/kitchen/herringbone, /area/station/service/kitchen) diff --git a/_maps/map_files/PubbyStation/PubbyStation.dmm b/_maps/map_files/PubbyStation/PubbyStation.dmm index 3c9c17c3f63f..abd1ba051ccf 100644 --- a/_maps/map_files/PubbyStation/PubbyStation.dmm +++ b/_maps/map_files/PubbyStation/PubbyStation.dmm @@ -43350,7 +43350,7 @@ dir = 4 }, /obj/machinery/door/firedoor, -/obj/structure/displaycase/forsale/kitchen, +/obj/structure/tipjar/prefilled, /turf/open/floor/iron/dark, /area/station/service/bar) "lMm" = ( @@ -52569,7 +52569,7 @@ /obj/effect/turf_decal/tile/red{ dir = 8 }, -/obj/structure/displaycase/forsale/kitchen, +/obj/structure/tipjar/prefilled, /obj/machinery/door/firedoor, /obj/machinery/door/poddoor/shutters/preopen{ id = "kitchenshutters"; diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm index dce6579cd926..43d9ceaf6667 100644 --- a/_maps/map_files/tramstation/tramstation.dmm +++ b/_maps/map_files/tramstation/tramstation.dmm @@ -25109,7 +25109,7 @@ id = "playerscantreadthis"; name = "Kitchen Counter Shutters" }, -/obj/structure/displaycase/forsale/kitchen{ +/obj/structure/tipjar/prefilled{ pixel_y = 8 }, /turf/open/floor/iron/checker, @@ -28146,7 +28146,7 @@ /area/station/solars/starboard/fore) "jgn" = ( /obj/structure/table/reinforced, -/obj/structure/displaycase/forsale/kitchen{ +/obj/structure/tipjar/prefilled{ pixel_y = 8 }, /obj/machinery/light/warm/directional/east, @@ -53585,7 +53585,7 @@ "sct" = ( /obj/structure/table/reinforced, /obj/structure/window/spawner/directional/north, -/obj/structure/displaycase/forsale/kitchen{ +/obj/structure/tipjar/prefilled{ pixel_y = 8 }, /obj/machinery/light/warm/directional/west, diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm index e523fe8350b0..0200cf5f3e28 100644 --- a/code/game/objects/items/cards_ids.dm +++ b/code/game/objects/items/cards_ids.dm @@ -1,9 +1,6 @@ /// Fallback time if none of the config entries are set for USE_LOW_LIVING_HOUR_INTERN #define INTERN_THRESHOLD_FALLBACK_HOURS 15 -/// Max time interval between projecting holopays -#define HOLOPAY_PROJECTION_INTERVAL (7 SECONDS) - /* Cards * Contains: * DATA CARD @@ -73,27 +70,6 @@ /// Linked bank account. var/datum/bank_account/registered_account - /// Linked holopay. - var/obj/structure/holopay/my_store - /// Cooldown between projecting holopays - COOLDOWN_DECLARE(last_holopay_projection) - /// List of logos available for holopay customization - via font awesome 5 - var/static/list/available_logos = list("angry", "ankh", "bacon", "band-aid", "cannabis", "cat", "cocktail", "coins", "comments-dollar", - "cross", "cut", "dog", "donate", "dna", "fist-raised", "flask", "glass-cheers", "glass-martini-alt", "hamburger", "hand-holding-usd", - "hat-wizard", "head-side-cough-slash", "heart", "heart-broken", "laugh-beam", "leaf", "money-check-alt", "music", "piggy-bank", - "pizza-slice", "prescription-bottle-alt", "radiation", "robot", "smile", "skull-crossbones", "smoking", "space-shuttle", "tram", - "trash", "user-ninja", "utensils", "wrench") - /// Replaces the "pay whatever" functionality with a set amount when non-zero. - var/holopay_fee = 0 - /// The holopay icon chosen by the user - var/holopay_logo = "donate" - /// Maximum forced fee. It's unlikely for a user to encounter this type of money, much less pay it willingly. - var/holopay_max_fee = 5000 - /// Minimum forced fee for holopay stations. Registers as "pay what you want." - var/holopay_min_fee = 0 - /// The holopay name chosen by the user - var/holopay_name = "holographic pay stand" - /// Registered owner's age. var/registered_age = 30 @@ -153,8 +129,6 @@ /obj/item/card/id/Destroy() if (registered_account) registered_account.bank_cards -= src - if (my_store) - QDEL_NULL(my_store) return ..() /obj/item/card/id/equipped(mob/user, slot, initial = FALSE) @@ -481,24 +455,9 @@ user.visible_message(span_notice("[user] shows you: [icon2html(src, viewers(user))] [src.name][minor]."), span_notice("You show \the [src.name][minor].")) add_fingerprint(user) -/obj/item/card/id/interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers) - if(!check_allowed_items(interacting_with) || !isfloorturf(interacting_with)) - return NONE - try_project_paystand(user, interacting_with) - return ITEM_INTERACT_SUCCESS - -/obj/item/card/id/attack_self_secondary(mob/user, modifiers) - . = ..() - if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN) - return - try_project_paystand(user) - return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN - /obj/item/card/id/add_context(atom/source, list/context, obj/item/held_item, mob/user) . = ..() - context[SCREENTIP_CONTEXT_LMB] = "Show ID" - context[SCREENTIP_CONTEXT_RMB] = "Project pay stand" if(isnull(registered_account) || registered_account.replaceable) //Same check we use when we check if we can assign an account context[SCREENTIP_CONTEXT_ALT_RMB] = "Assign account" if(!registered_account.replaceable || registered_account.account_balance > 0) @@ -507,98 +466,6 @@ context[SCREENTIP_CONTEXT_CTRL_LMB] = "Toggle honorific" return CONTEXTUAL_SCREENTIP_SET -/obj/item/card/id/proc/try_project_paystand(mob/user, turf/target) - if(!COOLDOWN_FINISHED(src, last_holopay_projection)) - balloon_alert(user, "still recharging") - return - if(!registered_account || !registered_account.account_job) - balloon_alert(user, "no account") - to_chat(user, span_warning("You need a valid bank account to do this.")) - return - /// Determines where the holopay will be placed based on tile contents - var/turf/projection - var/turf/step_ahead = get_step(user, user.dir) - var/turf/user_loc = user.loc - if(target && can_proj_holopay(target)) - projection = target - else if(can_proj_holopay(step_ahead)) - projection = step_ahead - else if(can_proj_holopay(user_loc)) - projection = user_loc - if(!projection) - balloon_alert(user, "no space") - to_chat(user, span_warning("You need to be standing on or near an open tile to do this.")) - return - /// Success: Valid tile for holopay placement - if(my_store) - my_store.dissipate() - var/obj/structure/holopay/new_store = new(projection) - if(new_store?.assign_card(projection, src)) - COOLDOWN_START(src, last_holopay_projection, HOLOPAY_PROJECTION_INTERVAL) - playsound(projection, 'sound/effects/empulse.ogg', 40, TRUE) - my_store = new_store - -/** - * Determines whether a new holopay can be placed on the given turf. - * Checks if there are dense contents, too many contents, or another - * holopay already exists on the turf. - * - * Arguments: - * * turf/target - The target turf to be checked for dense contents - * Returns: - * * TRUE if the target is a valid holopay location, FALSE otherwise. - */ -/obj/item/card/id/proc/can_proj_holopay(turf/target) - if(!isfloorturf(target)) - return FALSE - if(target.density) - return FALSE - if(length(target.contents) > 5) - return FALSE - for(var/obj/checked_obj in target.contents) - if(checked_obj.density) - return FALSE - if(istype(checked_obj, /obj/structure/holopay)) - return FALSE - return TRUE - -/** - * Setter for the shop logo on linked holopays - * - * Arguments: - * * new_logo - The new logo to be set. - */ -/obj/item/card/id/proc/set_holopay_logo(new_logo) - if(!available_logos.Find(new_logo)) - CRASH("User input a holopay shop logo that didn't exist.") - holopay_logo = new_logo - -/** - * Setter for changing the force fee on a holopay. - * - * Arguments: - * * new_fee - The new fee to be set. - */ -/obj/item/card/id/proc/set_holopay_fee(new_fee) - if(!isnum(new_fee)) - CRASH("User input a non number into the holopay fee field.") - if(new_fee < holopay_min_fee || new_fee > holopay_max_fee) - CRASH("User input a number outside of the valid range into the holopay fee field.") - holopay_fee = new_fee - -/** - * Setter for changing the holopay name. - * - * Arguments: - * * new_name - The new name to be set. - */ -/obj/item/card/id/proc/set_holopay_name(name) - if(length(name) < 3 || length(name) > MAX_NAME_LEN) - to_chat(usr, span_warning("Must be between 3 - 42 characters.")) - else - holopay_name = html_encode(trim(name, MAX_NAME_LEN)) - - /obj/item/card/id/vv_edit_var(var_name, var_value) . = ..() if(.) @@ -1881,7 +1748,6 @@ icon_state = "ctf_green" #undef INTERN_THRESHOLD_FALLBACK_HOURS -#undef HOLOPAY_PROJECTION_INTERVAL #define INDEX_NAME_COLOR 1 #define INDEX_ASSIGNMENT_COLOR 2 diff --git a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm index de24082a31ba..ea1ac6007845 100644 --- a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm +++ b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm @@ -1344,13 +1344,6 @@ greyscale_colors = CIRCUIT_COLOR_SERVICE build_path = /obj/machinery/rnd/production/techfab/department/service -/obj/item/circuitboard/machine/vendatray - name = "Vend-A-Tray" - greyscale_colors = CIRCUIT_COLOR_SERVICE - build_path = /obj/structure/displaycase/forsale - req_components = list( - /datum/stock_part/card_reader = 1) - /obj/item/circuitboard/machine/fishing_portal_generator name = "Fishing Portal Generator" greyscale_colors = CIRCUIT_COLOR_SERVICE diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm index beb0fdbf6d8c..4ce8e7d09d50 100644 --- a/code/game/objects/items/stacks/sheets/glass.dm +++ b/code/game/objects/items/stacks/sheets/glass.dm @@ -12,7 +12,8 @@ GLOBAL_LIST_INIT(glass_recipes, list ( \ new/datum/stack_recipe("directional window", /obj/structure/window/unanchored, time = 0.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_CHECK_DIRECTION, category = CAT_WINDOWS), \ new/datum/stack_recipe("fulltile window", /obj/structure/window/fulltile/unanchored, 2, time = 1 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_IS_FULLTILE, category = CAT_WINDOWS), \ new/datum/stack_recipe("glass shard", /obj/item/shard, time = 0, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND, category = CAT_MISC), \ - new/datum/stack_recipe("glass tile", /obj/item/stack/tile/glass, 1, 4, 20, category = CAT_TILES) \ + new/datum/stack_recipe("glass tile", /obj/item/stack/tile/glass, 1, 4, 20, category = CAT_TILES), \ + new/datum/stack_recipe("tip jar", /obj/structure/tipjar, req_amount = 2, time = 3 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ )) /obj/item/stack/sheet/glass @@ -88,7 +89,8 @@ GLOBAL_LIST_INIT(pglass_recipes, list ( \ new/datum/stack_recipe("directional window", /obj/structure/window/plasma/unanchored, time = 0.5 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_CHECK_DIRECTION, category = CAT_WINDOWS), \ new/datum/stack_recipe("fulltile window", /obj/structure/window/plasma/fulltile/unanchored, 2, time = 2 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND | CRAFT_IS_FULLTILE, category = CAT_WINDOWS), \ new/datum/stack_recipe("plasma glass shard", /obj/item/shard/plasma, time = 20, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND, category = CAT_MISC), \ - new/datum/stack_recipe("plasma glass tile", /obj/item/stack/tile/glass/plasma, 1, 4, 20, category = CAT_TILES) \ + new/datum/stack_recipe("plasma glass tile", /obj/item/stack/tile/glass/plasma, 1, 4, 20, category = CAT_TILES), \ + new/datum/stack_recipe("tip jar", /obj/structure/tipjar/plasma, req_amount = 2, time = 3 SECONDS, crafting_flags = CRAFT_CHECK_DENSITY | CRAFT_ON_SOLID_GROUND, category = CAT_FURNITURE), \ )) /obj/item/stack/sheet/plasmaglass diff --git a/code/game/objects/structures/displaycase.dm b/code/game/objects/structures/displaycase.dm index a4f6b59a3e06..170f336c0866 100644 --- a/code/game/objects/structures/displaycase.dm +++ b/code/game/objects/structures/displaycase.dm @@ -280,14 +280,6 @@ balloon_alert(user, "electronics installed") return - if(istype(attacking_item, /obj/item/stock_parts/card_reader)) - var/obj/item/stock_parts/card_reader/card_reader = attacking_item - balloon_alert(user, "adding [card_reader]...") - if(do_after(user, 2 SECONDS, target = src)) - qdel(card_reader) - make_final_result(display_type = /obj/structure/displaycase/forsale) - return - if(istype(attacking_item, /obj/item/stack/sheet/glass)) var/obj/item/stack/sheet/glass/glass_sheets = attacking_item if(glass_sheets.get_amount() < 10) @@ -464,219 +456,3 @@ desc = initial(item_path.desc) icon = initial(item_path.icon) icon_state = initial(item_path.icon_state) - -/obj/structure/displaycase/forsale - name = "vend-a-tray" - icon = 'icons/obj/machines/display.dmi' - icon_state = "laserbox" - custom_glass_overlay = TRUE - desc = "A display case with an ID-card swiper. Use your ID to purchase the contents." - density = FALSE - max_integrity = 100 - req_access = null - alert = FALSE //No, we're not calling the fire department because someone stole your cookie. - glass_fix = FALSE //Fixable with tools instead. - pass_flags = PASSTABLE ///Can be placed and moved onto a table. - autoexamine_while_closed = FALSE - ///The price of the item being sold. Altered by grab intent ID use. - var/sale_price = 20 - ///The Account which will receive payment for purchases. Set by the first ID to swipe the tray. - var/datum/bank_account/payments_acc = null - -/obj/structure/displaycase/forsale/update_icon_state() - icon_state = "[initial(icon_state)][broken ? "_broken" : (open ? "_open" : (!showpiece ? "_empty" : null))]" - return ..() - -/obj/structure/displaycase/forsale/update_overlays() - . = ..() - if(!broken && !open) - . += "[initial(icon_state)]_overlay" - -/obj/structure/displaycase/forsale/insert_showpiece(obj/item/new_showpiece, mob/user) - if(..()) - return TRUE - update_static_data_for_all_viewers() - -/obj/structure/displaycase/forsale/dump() - ..() - update_static_data_for_all_viewers() - -/obj/structure/displaycase/forsale/toggle_lock() - ..() - SStgui.update_uis(src) - -/obj/structure/displaycase/forsale/ui_interact(mob/user, datum/tgui/ui) - ui = SStgui.try_update_ui(user, src, ui) - if(!ui) - ui = new(user, src, "Vendatray", name) - ui.set_autoupdate(FALSE) - ui.open() - -/obj/structure/displaycase/forsale/ui_data(mob/user) - var/list/data = list() - data["owner_name"] = payments_acc ? payments_acc.account_holder : null - data["product_name"] = showpiece ?capitalize(format_text(showpiece.name)) : null - data["registered"] = payments_acc ? TRUE : FALSE - data["product_cost"] = sale_price - data["tray_open"] = open - return data - -/obj/structure/displaycase/forsale/ui_static_data(mob/user) - var/list/data = list() - data["product_icon"] = showpiece ? icon2base64(getFlatIcon(showpiece, no_anim=TRUE)) : null - return data - -/obj/structure/displaycase/forsale/ui_act(action, params) - . = ..() - if(.) - return - var/obj/item/card/id/potential_acc - if(isliving(usr)) - var/mob/living/L = usr - potential_acc = L.get_idcard(hand_first = TRUE) - switch(action) - if("Buy") - if(!showpiece) - to_chat(usr, span_notice("There's nothing for sale.")) - return TRUE - if(broken) - to_chat(usr, span_notice("[src] appears to be broken.")) - return TRUE - if(!payments_acc) - to_chat(usr, span_notice("[src] hasn't been registered yet.")) - return TRUE - if(!usr.can_perform_action(src, FORBID_TELEKINESIS_REACH)) - return TRUE - if(!potential_acc) - to_chat(usr, span_notice("No ID card detected.")) - return - var/datum/bank_account/account = potential_acc.registered_account - if(!account) - to_chat(usr, span_notice("[potential_acc] has no account registered!")) - return - if(!account.has_money(sale_price)) - to_chat(usr, span_notice("You do not possess the funds to purchase this.")) - return TRUE - else - account.adjust_money(-sale_price, "Display Case: [capitalize(showpiece.name)]") - if(payments_acc) - payments_acc.adjust_money(sale_price, "Display Case: [capitalize(showpiece.name)]") - usr.put_in_hands(showpiece) - to_chat(usr, span_notice("You purchase [showpiece] for [sale_price] credits.")) - playsound(src, 'sound/effects/cashregister.ogg', 40, TRUE) - flick("[initial(icon_state)]_vend", src) - showpiece = null - update_appearance() - update_static_data_for_all_viewers() - return TRUE - if("Open") - if(!payments_acc) - to_chat(usr, span_notice("[src] hasn't been registered yet.")) - return TRUE - if(!potential_acc || !potential_acc.registered_account) - return - if(!check_access(potential_acc)) - playsound(src, 'sound/machines/buzz-sigh.ogg', 50, TRUE) - return - toggle_lock() - if("Register") - if(payments_acc) - return - if(!potential_acc || !potential_acc.registered_account) - return - if(!check_access(potential_acc)) - playsound(src, 'sound/machines/buzz-sigh.ogg', 50, TRUE) - return - payments_acc = potential_acc.registered_account - playsound(src, 'sound/machines/click.ogg', 20, TRUE) - if("Adjust") - if(!check_access(potential_acc) || potential_acc.registered_account != payments_acc) - playsound(src, 'sound/machines/buzz-sigh.ogg', 50, TRUE) - return - - var/new_price_input = tgui_input_number(usr, "Sale price for this vend-a-tray", "New Price", 10, 1000) - if(!new_price_input || QDELETED(usr) || QDELETED(src)) - return - if(payments_acc != potential_acc.registered_account) - to_chat(usr, span_warning("[src] rejects your new price.")) - return - if(!usr.can_perform_action(src, FORBID_TELEKINESIS_REACH)) - to_chat(usr, span_warning("You need to get closer!")) - return - sale_price = new_price_input - to_chat(usr, span_notice("The cost is now set to [sale_price].")) - SStgui.update_uis(src) - return TRUE - . = TRUE - -/obj/structure/displaycase/forsale/attackby(obj/item/attacking_item, mob/user, list/modifiers, list/attack_modifiers) - if(isidcard(attacking_item)) - //Card Registration - var/obj/item/card/id/potential_acc = attacking_item - if(!potential_acc.registered_account) - to_chat(user, span_warning("This ID card has no account registered!")) - return - if(payments_acc == potential_acc.registered_account) - toggle_lock() - return - if(istype(attacking_item, /obj/item/modular_computer)) - return TRUE - SStgui.update_uis(src) - return ..() - -/obj/structure/displaycase/forsale/multitool_act(mob/living/user, obj/item/I) - . = ..() - if(atom_integrity <= (integrity_failure * max_integrity)) - to_chat(user, span_notice("You start recalibrating [src]'s hover field...")) - if(do_after(user, 2 SECONDS, target = src)) - broken = FALSE - atom_integrity = max_integrity - update_appearance() - return TRUE - -/obj/structure/displaycase/forsale/wrench_act(mob/living/user, obj/item/I) - . = ..() - if(open && !user.combat_mode) - if(anchored) - to_chat(user, span_notice("You start unsecuring [src]...")) - else - to_chat(user, span_notice("You start securing [src]...")) - if(I.use_tool(src, user, 16, volume=50)) - if(QDELETED(I)) - return - if(anchored) - to_chat(user, span_notice("You unsecure [src].")) - else - to_chat(user, span_notice("You secure [src].")) - set_anchored(!anchored) - return TRUE - else if(!open && !user.combat_mode) - to_chat(user, span_notice("[src] must be open to move it.")) - return - -/obj/structure/displaycase/forsale/emag_act(mob/user, obj/item/card/emag/emag_card) - . = ..() - payments_acc = null - req_access = list() - balloon_alert(user, "account owner reset") - to_chat(user, span_warning("[src]'s card reader fizzles and smokes.")) - return TRUE - -/obj/structure/displaycase/forsale/examine(mob/user) - . = ..() - if(showpiece && !open) - . += span_notice("[showpiece] is for sale for [sale_price] credits.") - if(broken) - . += span_notice("[src] is sparking and the hover field generator seems to be overloaded. Use a multitool to fix it.") - -/obj/structure/displaycase/forsale/atom_break(damage_flag) - . = ..() - if(!broken) - broken = TRUE - playsound(src, SFX_SHATTER, 70, TRUE) - update_appearance() - trigger_alarm() //In case it's given an alarm anyway. - -/obj/structure/displaycase/forsale/kitchen - desc = "A display case with an ID-card swiper. Use your ID to purchase the contents. Meant for the bartender and chef." - req_one_access = list(ACCESS_KITCHEN, ACCESS_BAR) diff --git a/code/modules/economy/holopay.dm b/code/modules/economy/holopay.dm deleted file mode 100644 index 52219bb61aa1..000000000000 --- a/code/modules/economy/holopay.dm +++ /dev/null @@ -1,299 +0,0 @@ -/obj/structure/holopay - name = "holographic pay stand" - desc = "an unregistered pay stand" - icon = 'icons/obj/economy.dmi' - icon_state = "card_scanner" - alpha = 150 - anchored = TRUE - armor_type = /datum/armor/structure_holopay - max_integrity = 15 - layer = FLY_LAYER - /// ID linked to the holopay - var/obj/item/card/id/linked_card - /// Max range at which the hologram can be projected before it deletes - var/max_holo_range = 4 - /// The holopay shop icon displayed in the UI - var/shop_logo = "donate" - /// Replaces the "pay whatever" functionality with a set amount when non-zero. - var/force_fee = 0 - -/datum/armor/structure_holopay - bullet = 50 - laser = 50 - energy = 50 - fire = 20 - acid = 20 - -/obj/structure/holopay/examine(mob/user) - . = ..() - if(force_fee) - . += span_boldnotice("This holopay forces a payment of [force_fee] credit\s per swipe instead of a variable amount.") - -/obj/structure/holopay/Initialize(mapload) - . = ..() - AddComponent(/datum/component/holographic_nature) - register_context() - -/obj/structure/holopay/add_context(atom/source, list/context, obj/item/held_item, mob/user) - . = ..() - - if(isidcard(held_item)) - context[SCREENTIP_CONTEXT_LMB] = "Pay" - var/obj/item/card/id/held_id = held_item - if(held_id.my_store && held_id.my_store == src) - context[SCREENTIP_CONTEXT_RMB] = "Dissipate pay stand" - return CONTEXTUAL_SCREENTIP_SET - - else if(istype(held_item, /obj/item/holochip)) - context[SCREENTIP_CONTEXT_LMB] = "Pay" - return CONTEXTUAL_SCREENTIP_SET - -/obj/structure/holopay/attack_hand(mob/living/user, list/modifiers) - . = ..() - if(.) - return - if(!user.combat_mode) - ui_interact(user) - return . - user.do_attack_animation(src, ATTACK_EFFECT_PUNCH) - user.changeNext_move(CLICK_CD_MELEE) - take_damage(5, BRUTE, MELEE, 1) - -/obj/structure/holopay/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0) - switch(damage_type) - if(BRUTE) - playsound(loc, 'sound/weapons/egloves.ogg', 80, TRUE) - if(BURN) - playsound(loc, 'sound/weapons/egloves.ogg', 80, TRUE) - -/obj/structure/holopay/atom_deconstruct(dissambled = TRUE) - dissipate() - -/obj/structure/holopay/Destroy() - linked_card?.my_store = null - linked_card = null - return ..() - -/obj/structure/holopay/attackby(obj/item/held_item, mob/item_holder, list/modifiers, list/attack_modifiers) - var/mob/living/user = item_holder - if(!isliving(user)) - return ..() - /// Users can pay with an ID to skip the UI - if(isidcard(held_item)) - if(force_fee && tgui_alert(item_holder, "This holopay has a [force_fee] cr fee. Confirm?", "Holopay Fee", list("Pay", "Cancel")) != "Pay") - return TRUE - process_payment(user) - return TRUE - /// Users can also pay by holochip - if(istype(held_item, /obj/item/holochip)) - /// Account checks - var/obj/item/holochip/chip = held_item - if(!chip.credits) - balloon_alert(user, "holochip is empty") - to_chat(user, span_warning("There doesn't seem to be any credits here.")) - return FALSE - /// Charges force fee or uses pay what you want - var/cash_deposit = force_fee || tgui_input_number(user, "How much? (Max: [chip.credits])", "Patronage", max_value = chip.credits) - /// Exit sanity checks - if(!cash_deposit) - return TRUE - if(QDELETED(held_item) || QDELETED(user) || QDELETED(src) || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) - return FALSE - if(!chip.spend(cash_deposit, FALSE)) - balloon_alert(user, "insufficient credits") - to_chat(user, span_warning("You don't have enough credits to pay with this chip.")) - return FALSE - /// Success: Alert buyer - alert_buyer(user, cash_deposit) - return TRUE - /// Throws errors if they try to use space cash - if(istype(held_item, /obj/item/stack/spacecash)) - to_chat(user, "What is this, the 2000s? We only take card here.") - return TRUE - if(istype(held_item, /obj/item/coin)) - to_chat(user, "What is this, the 1800s? We only take card here.") - return TRUE - return ..() - -/obj/structure/holopay/attackby_secondary(obj/item/weapon, mob/user, list/modifiers, list/attack_modifiers) - /// Can kill it by right-clicking with ID because it seems useful and intuitive, to me, at least - if(!isidcard(weapon)) - return ..() - var/obj/item/card/id/attacking_id = weapon - if(!attacking_id.my_store || attacking_id.my_store != src) - return ..() - dissipate() - return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN - -/obj/structure/holopay/ui_interact(mob/user, datum/tgui/ui) - . = ..() - if(.) - return FALSE - var/mob/living/interactor = user - if(isliving(interactor) && interactor.combat_mode) - return FALSE - ui = SStgui.try_update_ui(user, src, ui) - if(!ui) - ui = new(user, src, "HoloPay") - ui.open() - -/obj/structure/holopay/ui_status(mob/user, datum/ui_state/state) - . = ..() - if(!in_range(user, src) && !isobserver(user)) - return UI_CLOSE - -/obj/structure/holopay/ui_static_data(mob/user) - . = list() - .["available_logos"] = linked_card.available_logos - .["description"] = desc - .["max_fee"] = linked_card.holopay_max_fee - .["owner"] = linked_card.registered_account?.account_holder || null - .["shop_logo"] = shop_logo - -/obj/structure/holopay/ui_data(mob/user) - . = list() - .["force_fee"] = force_fee - .["name"] = name - if(!isliving(user)) - return . - var/mob/living/card_holder = user - var/obj/item/card/id/id_card = card_holder.get_idcard(TRUE) - var/datum/bank_account/account = id_card?.registered_account || null - if(account) - .["user"] = list() - .["user"]["name"] = account.account_holder - .["user"]["balance"] = account.account_balance - -/obj/structure/holopay/ui_act(action, list/params, datum/tgui/ui) - . = ..() - if(.) - return FALSE - switch(action) - if("done") - ui.send_full_update() - return TRUE - if("fee") - linked_card.set_holopay_fee(params["amount"]) - force_fee = linked_card.holopay_fee - if("logo") - linked_card.set_holopay_logo(params["logo"]) - shop_logo = linked_card.holopay_logo - if("pay") - ui.close() - process_payment(usr) - return TRUE - if("rename") - linked_card.set_holopay_name(params["name"]) - name = linked_card.holopay_name - return FALSE - -/** - * Links the source card to the holopay. Begins checking if its in range. - * - * Parameters: - * * turf/target - The tile to project the holopay onto - * * obj/item/card/id/card - The card to link to the holopay - * Returns: - * * TRUE - the card was linked - */ -/obj/structure/holopay/proc/assign_card(turf/target, obj/item/card/id/card) - linked_card = card - desc = "Pays directly into [card.registered_account.account_holder]'s bank account." - force_fee = card.holopay_fee - shop_logo = card.holopay_logo - name = card.holopay_name - add_atom_colour("#77abff", FIXED_COLOUR_PRIORITY) - set_light(2) - visible_message(span_notice("A holographic pay stand appears.")) - /// Start checking if the source projection is in range - track(linked_card) - return TRUE - -/obj/structure/holopay/proc/track(atom/movable/thing) - RegisterSignal(thing, COMSIG_MOVABLE_MOVED, PROC_REF(handle_move)) - var/list/locations = get_nested_locs(thing, include_turf = FALSE) - for(var/atom/movable/location in locations) - RegisterSignal(location, COMSIG_MOVABLE_MOVED, PROC_REF(handle_move)) - -/obj/structure/holopay/proc/untrack(atom/movable/thing) - UnregisterSignal(thing, COMSIG_MOVABLE_MOVED) - var/list/locations = get_nested_locs(thing, include_turf = FALSE) - for(var/atom/movable/location in locations) - UnregisterSignal(location, COMSIG_MOVABLE_MOVED) - -/** - * A periodic check to see if the projecting card is nearby. - * Deletes the holopay if not. - */ -/obj/structure/holopay/proc/handle_move(atom/movable/source, atom/old_loc, dir, forced, list/old_locs) - if(ismovable(old_loc)) - untrack(old_loc) - if(!IN_GIVEN_RANGE(src, linked_card, max_holo_range)) - dissipate() - return - if(ismovable(source.loc)) - track(source.loc) - -/** - * Creates holopay vanishing effects. - * Deletes the holopay thereafter. - */ -/obj/structure/holopay/proc/dissipate() - playsound(loc, 'sound/effects/empulse.ogg', 40, TRUE) - visible_message(span_notice("The pay stand vanishes.")) - qdel(src) - -/** - * Initiates a transaction between accounts. - * - * Parameters: - * * mob/living/user - The user who initiated the transaction. - * Returns: - * * TRUE - transaction was successful - */ -/obj/structure/holopay/proc/process_payment(mob/living/user) - /// Account checks - var/obj/item/card/id/id_card - id_card = user.get_idcard(TRUE) - if(!id_card || !id_card.registered_account || !id_card.registered_account.account_job) - balloon_alert(user, "invalid account") - to_chat(user, span_warning("You don't have a valid account.")) - return FALSE - var/datum/bank_account/payee = id_card.registered_account - if(payee == linked_card?.registered_account) - balloon_alert(user, "invalid transaction") - to_chat(user, span_warning("You can't pay yourself.")) - return FALSE - /// If the user has enough money, ask them the amount or charge the force fee - var/amount = force_fee || tgui_input_number(user, "How much? (Max: [payee.account_balance])", "Patronage", max_value = payee.account_balance) - /// Exit checks in case the user cancelled or entered an invalid amount - if(!amount || QDELETED(user) || QDELETED(src) || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) - return FALSE - if(!payee.adjust_money(-amount, "Holopay: [capitalize(name)]")) - balloon_alert(user, "insufficient credits") - to_chat(user, span_warning("You don't have the money to pay for this.")) - return FALSE - /// Success: Alert the buyer - alert_buyer(user, amount) - return TRUE - -/** - * Alerts the owner of the transaction. - * - * Parameters: - * * payee - The user who initiated the transaction. - * * amount - The amount of money that was paid. - * Returns: - * * TRUE - alert was successful. - */ -/obj/structure/holopay/proc/alert_buyer(payee, amount) - /// Pay the owner - linked_card.registered_account.adjust_money(amount, "Holopay: [name]") - /// Make alerts - linked_card.registered_account.bank_card_talk("[payee] has deposited [amount] cr at your holographic pay stand.") - say("Thank you for your patronage, [payee]!") - playsound(src, 'sound/effects/cashregister.ogg', 20, TRUE) - /// Log the event - log_econ("[amount] credits were transferred from [payee]'s transaction to [linked_card.registered_account.account_holder]") - SSblackbox.record_feedback("amount", "credits_transferred", amount) - return TRUE diff --git a/code/modules/religion/religion_sects.dm b/code/modules/religion/religion_sects.dm index 6318443fa642..df6d7cda22a9 100644 --- a/code/modules/religion/religion_sects.dm +++ b/code/modules/religion/religion_sects.dm @@ -269,7 +269,7 @@ tgui_icon = "dollar-sign" altar_icon_state = "convertaltar-yellow" alignment = ALIGNMENT_EVIL //greed is not good wtf - rites_list = list(/datum/religion_rites/greed/vendatray, /datum/religion_rites/greed/custom_vending) + rites_list = list(/datum/religion_rites/greed/custom_vending) altar_icon_state = "convertaltar-yellow" /datum/religion_sect/greed/tool_examine(mob/living/holy_creature) //display money policy diff --git a/code/modules/religion/rites.dm b/code/modules/religion/rites.dm index d6725692c724..c20427de817c 100644 --- a/code/modules/religion/rites.dm +++ b/code/modules/religion/rites.dm @@ -178,24 +178,11 @@ account.adjust_money(-money_cost, "Church Donation: Rite") . = ..() -/datum/religion_rites/greed/vendatray - name = "Purchase Vend-a-tray" - desc = "Summons a Vend-a-tray. You can use it to sell items!" - invoke_msg = "I need a vend-a-tray to make some more money!" - money_cost = 300 - -/datum/religion_rites/greed/vendatray/invoke_effect(mob/living/user, atom/movable/religious_tool) - ..() - var/altar_turf = get_turf(religious_tool) - new /obj/structure/displaycase/forsale(altar_turf) - playsound(get_turf(religious_tool), 'sound/effects/cashregister.ogg', 60, TRUE) - return TRUE - /datum/religion_rites/greed/custom_vending name = "Purchase Personal Vending Machine" desc = "Summons a custom vending machine. You can use it to sell MANY items!" invoke_msg = "If I get a custom vending machine for my products, I can be RICH!" - money_cost = 1000 //quite a step up from vendatray + money_cost = 1000 /datum/religion_rites/greed/custom_vending/invoke_effect(mob/living/user, atom/movable/religious_tool) ..() diff --git a/code/modules/research/designs/machine_designs.dm b/code/modules/research/designs/machine_designs.dm index 16da1d229eb1..3859cbc62b39 100644 --- a/code/modules/research/designs/machine_designs.dm +++ b/code/modules/research/designs/machine_designs.dm @@ -987,16 +987,6 @@ ) departmental_flags = DEPARTMENT_BITFLAG_SERVICE -/datum/design/board/vendatray - name = "Vend-a-Tray Board" - desc = "The circuit board for a Vend-a-Tray." - id = "vendatray" - build_path = /obj/item/circuitboard/machine/vendatray - category = list( - RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_SERVICE - ) - departmental_flags = DEPARTMENT_BITFLAG_SERVICE - /datum/design/board/bountypad name = "Civilian Bounty Pad Board" desc = "The circuit board for a Civilian Bounty Pad." diff --git a/code/modules/research/techweb/nodes/engi_nodes.dm b/code/modules/research/techweb/nodes/engi_nodes.dm index 065a74fd4c16..27592cb8acb9 100644 --- a/code/modules/research/techweb/nodes/engi_nodes.dm +++ b/code/modules/research/techweb/nodes/engi_nodes.dm @@ -187,7 +187,6 @@ "holobarrier_jani", "holobarrier_med", "holopad", - "vendatray", "holodisk", "modular_shield_generator", "modular_shield_node", diff --git a/maplestation.dme b/maplestation.dme index 34ac970125f3..65b6c9d42ca6 100644 --- a/maplestation.dme +++ b/maplestation.dme @@ -3963,7 +3963,6 @@ #include "code\modules\discord\toggle_notify.dm" #include "code\modules\economy\_economy.dm" #include "code\modules\economy\account.dm" -#include "code\modules\economy\holopay.dm" #include "code\modules\emoji\emoji_parse.dm" #include "code\modules\emote_panel\emote_panel.dm" #include "code\modules\error_handler\error_handler.dm" @@ -6429,6 +6428,7 @@ #include "maplestation_modules\code\game\objects\structures\static_plaques.dm" #include "maplestation_modules\code\game\objects\structures\surgery_table.dm" #include "maplestation_modules\code\game\objects\structures\tables_racks.dm" +#include "maplestation_modules\code\game\objects\structures\tipjar.dm" #include "maplestation_modules\code\game\objects\structures\vital_floor_scanner.dm" #include "maplestation_modules\code\game\objects\structures\crate_lockers\crates.dm" #include "maplestation_modules\code\game\objects\structures\crate_lockers\closets\secure\asset_protection.dm" diff --git a/maplestation_modules/code/game/objects/structures/tipjar.dm b/maplestation_modules/code/game/objects/structures/tipjar.dm new file mode 100644 index 000000000000..69e2bbbbd2d4 --- /dev/null +++ b/maplestation_modules/code/game/objects/structures/tipjar.dm @@ -0,0 +1,205 @@ +/obj/structure/tipjar + name = "tip jar" + desc = "I can't believe tipping culture made its way to the stars." + icon = 'maplestation_modules/icons/obj/tipjar.dmi' + icon_state = "jar" + density = TRUE + anchored = FALSE + resistance_flags = ACID_PROOF + max_integrity = 100 + custom_materials = list(/datum/material/glass = SHEET_MATERIAL_AMOUNT * 2) + material_flags = MATERIAL_EFFECTS | MATERIAL_ADD_PREFIX | MATERIAL_COLOR + + var/static/list/tippable_typecache = typecacheof(list( + /obj/item/card, + /obj/item/cigarette, + /obj/item/cigbutt, // jerk! + /obj/item/coin, + /obj/item/documents, + /obj/item/folder, + /obj/item/food/candy_trash, + /obj/item/holochip, + /obj/item/match, + /obj/item/paper, + /obj/item/paperwork, + /obj/item/pen, + /obj/item/photo, + /obj/item/stack/spacecash, + /obj/item/toy/crayon, + /obj/item/trash, // jerk! + )) + + var/static/alist/pos_map = alist( + 1 = list(-3, -7), + 2 = list( 3, -7), + 3 = list( 0, -6), + 4 = list(-3, -5), + 5 = list( 3, -5), + 6 = list( 0, -4), + 7 = list(-3, -3), + 8 = list( 3, -3), + 9 = list( 0, -2), + ) + + var/static/list/crack_states = list() + + var/prefilled = FALSE + + var/glass_type = /obj/item/stack/sheet/glass + var/shard_type = /obj/item/shard + +/obj/structure/tipjar/Initialize(mapload) + . = ..() + if(!length(crack_states)) + for(var/i in 1 to 9) + crack_states += "crack[i]" + + if(mapload) + set_anchored(TRUE) + if(prefilled) + if(prob(8)) + for(var/i in 1 to rand(1, 4)) + new /obj/effect/spawner/random/entertainment/coin(src) + if(prob(4)) + for(var/i in 1 to rand(1, 3)) + new /obj/effect/spawner/random/entertainment/money_small(src) + if(prob(1)) + for(var/i in 1 to rand(1, 2)) + new /obj/effect/spawner/random/entertainment/money(src) + + AddElement(/datum/element/crackable, 'icons/obj/pipes_n_cables/stationary_canisters.dmi', crack_states) + update_appearance() + +/obj/structure/tipjar/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + if(is_type_in_typecache(tool, tippable_typecache)) + // while we only visually show the first pos_map items, we can store some extra... + if(length(contents) >= length(pos_map) * 3) + balloon_alert(user, "it's full!") + return ITEM_INTERACT_BLOCKING + if(user.transferItemToLoc(tool, src)) + balloon_alert_to_viewers("deposited \a [tool]") + return ITEM_INTERACT_SUCCESS + return ITEM_INTERACT_BLOCKING + + return NONE + +/obj/structure/tipjar/examine(mob/user) + . = ..() + var/list/all_things = list() + for(var/obj/item/thing in src) + all_things["\A [thing]"] += 1 + + for(var/thing_name in all_things) + if(all_things[thing_name] > 1) + // we have to remove the "an" or "some" and pluralize it ourselves + var/list/split_name = splittext(thing_name, " ") + var/reformatted_name = jointext(split_name, " ", 2) + all_things += "[all_things[thing_name]] [reformatted_name][plural_s(reformatted_name)]" + all_things -= thing_name + + . += span_info("Inside, you can see: [english_list(all_things)].") + +/obj/structure/tipjar/attack_hand(mob/living/user, list/modifiers) + . = ..() + if(.) + return + if(!user.CanReach(src)) + return + + . = TRUE + if(!length(contents)) + user.visible_message( + span_notice("[user] sticks [user.p_their()] hand in the empty [name], like a fool."), + span_warning("There's nothing to fish out of [src]!"), + ) + return + + user.visible_message( + span_notice("[user] starts fishing around in [src]..."), + span_notice("You start fishing around in [src]..."), + ) + Shake(1, 1, 5 SECONDS, 0.1 SECONDS) + if(!do_after(user, 5 SECONDS, src) || !length(contents)) + animate(src) + pixel_x = base_pixel_x + pixel_y = base_pixel_y + return + + var/obj/item/fished_out = pick(contents) + user.visible_message( + span_notice("[user] pulls [fished_out] out of [src]!"), + span_notice("You pull [fished_out] out of [src]."), + ) + user.put_in_hands(fished_out) + +/obj/structure/tipjar/dump_contents() + for(var/obj/item/thing in src) + thing.forceMove(drop_location()) + thing.pixel_x += rand(-4, 4) + thing.pixel_y += rand(-4, 4) + +/obj/structure/tipjar/handle_deconstruct(disassembled) + . = ..() + dump_contents() + +/obj/structure/tipjar/atom_deconstruct(disassembled = TRUE) + if(disassembled) + new glass_type(drop_location(), SHEET_MATERIAL_AMOUNT * 2) + playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE) + else + for(var/i in 1 to 2) + new shard_type(drop_location()) + playsound(src, SFX_SHATTER, 50, TRUE) + +/obj/structure/tipjar/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0) + playsound(src, 'sound/effects/hit_on_shattered_glass.ogg', 70, TRUE) + +/obj/structure/tipjar/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs) + . = ..() + update_appearance() + RegisterSignal(arrived, COMSIG_STACK_CAN_MERGE, PROC_REF(block_merging)) + +/obj/structure/tipjar/Exited(atom/movable/gone, direction) + . = ..() + update_appearance() + UnregisterSignal(gone, COMSIG_STACK_CAN_MERGE) + +/obj/structure/tipjar/proc/block_merging(mob/living/user, atom/movable/other) + SIGNAL_HANDLER + return CANCEL_STACK_MERGE + +/obj/structure/tipjar/wrench_act(mob/living/user, obj/item/tool) + switch(default_unfasten_wrench(user, tool, 5 SECONDS)) + if(CANT_UNFASTEN) + return NONE + if(FAILED_UNFASTEN) + return ITEM_INTERACT_BLOCKING + if(SUCCESSFUL_UNFASTEN) + return ITEM_INTERACT_SUCCESS + return NONE + +/obj/structure/tipjar/update_overlays() + . = ..() + underlays.Cut() + for(var/i in 1 to min(length(contents), length(pos_map))) + var/obj/item/thing = contents[i] + var/image/content_overlay = image(thing, src) + + content_overlay.transform = content_overlay.transform.Scale(0.5) + content_overlay.pixel_x = 0 + content_overlay.pixel_y = 0 + content_overlay.pixel_w = pos_map[i][1] + content_overlay.pixel_z = pos_map[i][2] + content_overlay.layer = FLOAT_LAYER + content_overlay.plane = FLOAT_PLANE + + underlays += content_overlay + +/obj/structure/tipjar/prefilled + prefilled = TRUE + +/obj/structure/tipjar/plasma + max_integrity = 300 + custom_materials = list(/datum/material/alloy/plasmaglass = SHEET_MATERIAL_AMOUNT * 2) + glass_type = /obj/item/stack/sheet/plasmaglass + shard_type = /obj/item/shard/plasma diff --git a/maplestation_modules/icons/obj/tipjar.dmi b/maplestation_modules/icons/obj/tipjar.dmi new file mode 100644 index 000000000000..a5d5cfcf0786 Binary files /dev/null and b/maplestation_modules/icons/obj/tipjar.dmi differ