diff --git a/code/__DEFINES/economy.dm b/code/__DEFINES/economy.dm index 7b619b274f5..32408e4f538 100644 --- a/code/__DEFINES/economy.dm +++ b/code/__DEFINES/economy.dm @@ -70,6 +70,7 @@ #define PAYMENT_CLINICAL "clinical" #define PAYMENT_FRIENDLY "friendly" #define PAYMENT_ANGRY "angry" +#define PAYMENT_VENDING "vending" #define MARKET_TREND_UPWARD 1 #define MARKET_TREND_DOWNWARD -1 diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 07fd4e2d560..651336fd12e 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -285,3 +285,10 @@ GLOBAL_LIST_INIT(WALLITEMS_EXTERIOR, typecacheof(list( /obj/structure/camera_assembly, /obj/structure/light_construct, ))) + +/// A static typecache of all the money-based items that can be actively used as currency. +GLOBAL_LIST_INIT(allowed_money, typecacheof(list( + /obj/item/coin, + /obj/item/holochip, + /obj/item/stack/spacecash, +))) diff --git a/code/datums/components/payment.dm b/code/datums/components/payment.dm index 1220614e9c3..5e79b28fd57 100644 --- a/code/datums/components/payment.dm +++ b/code/datums/components/payment.dm @@ -19,11 +19,6 @@ var/datum/bank_account/target_acc ///Does this payment component respect same-department-discount? var/department_discount = FALSE - ///A static typecache of all the money-based items that can be actively used as currency. - var/static/list/allowed_money = typecacheof(list( - /obj/item/stack/spacecash, - /obj/item/holochip, - /obj/item/coin)) /datum/component/payment/Initialize(_cost, _target, _style) target_acc = _target @@ -80,13 +75,13 @@ //Here is all the possible non-ID payment methods. var/list/counted_money = list() var/physical_cash_total = 0 - for(var/obj/item/credit in typecache_filter_list(user.get_all_contents(), allowed_money)) //Coins, cash, and credits. + for(var/obj/item/credit in typecache_filter_list(user.get_all_contents(), GLOB.allowed_money)) //Coins, cash, and credits. if(physical_cash_total > total_cost) break physical_cash_total += credit.get_item_credit_value() counted_money += credit - if(is_type_in_typecache(user.pulling, allowed_money) && (physical_cash_total < total_cost)) //Coins(Pulled). + if(is_type_in_typecache(user.pulling, GLOB.allowed_money) && (physical_cash_total < total_cost)) //Coins(Pulled). var/obj/item/counted_credit = user.pulling physical_cash_total += counted_credit.get_item_credit_value() counted_money += counted_credit @@ -134,9 +129,11 @@ * Attempts to charge a mob, user, an integer number of credits, total_cost, directly from an ID card/bank account. */ /datum/component/payment/proc/handle_card(mob/living/user, obj/item/card/id/idcard, total_cost) - var/atom/atom_parent = parent + var/atom/movable/atom_parent = parent if(!idcard) + if(transaction_style == PAYMENT_VENDING) + to_chat(user, span_warning("No card found.")) return FALSE if(!idcard?.registered_account) switch(transaction_style) @@ -146,6 +143,13 @@ to_chat(user, span_warning("ARE YOU JOKING. YOU DON'T HAVE A BANK ACCOUNT ON YOUR ID YOU IDIOT.")) if(PAYMENT_CLINICAL) to_chat(user, span_warning("ID Card lacks a bank account. Advancing.")) + if(PAYMENT_VENDING) + to_chat(user, span_warning("No account found.")) + + return FALSE + + if(!idcard.registered_account.account_job) + atom_parent.say("Departmental accounts have been blacklisted from personal expenses due to embezzlement.") return FALSE if(!(idcard.registered_account.has_money(total_cost))) @@ -156,6 +160,8 @@ to_chat(user, span_warning("YOU MORON. YOU ABSOLUTE BAFOON. YOU INSUFFERABLE TOOL. YOU ARE POOR.")) if(PAYMENT_CLINICAL) to_chat(user, span_warning("ID Card lacks funds. Aborting.")) + if(PAYMENT_VENDING) + to_chat(user, span_warning("You do not possess the funds to purchase that.")) atom_parent.balloon_alert(user, "needs [total_cost] credit\s!") return FALSE target_acc.transfer_money(idcard.registered_account, total_cost, "Nanotrasen: Usage of Corporate Machinery") diff --git a/code/game/objects/items/vending_items.dm b/code/game/objects/items/vending_items.dm index 0383767ce66..7084b313dff 100644 --- a/code/game/objects/items/vending_items.dm +++ b/code/game/objects/items/vending_items.dm @@ -19,8 +19,10 @@ w_class = WEIGHT_CLASS_BULKY armor_type = /datum/armor/item_vending_refill - // Built automatically from the corresponding vending machine. - // If null, considered to be full. Otherwise, is list(/typepath = amount). + /** + * Built automatically from the corresponding vending machine. + * If null, considered to be full. Otherwise, is list(/typepath = amount). + */ var/list/products var/list/product_categories var/list/contraband diff --git a/code/modules/cargo/exports/parts.dm b/code/modules/cargo/exports/parts.dm index 840d40f1837..fc8c9656fea 100644 --- a/code/modules/cargo/exports/parts.dm +++ b/code/modules/cargo/exports/parts.dm @@ -33,3 +33,9 @@ unit_name = "data disk" export_types = list(/obj/item/computer_disk) include_subtypes = TRUE + +/datum/export/refill_canister + cost = CARGO_CRATE_VALUE * 0.5 //If someone want to make this worth more as it empties, go ahead + unit_name = "vending refill canister" + message = "Thank you for restocking the station!" + export_types = list(/obj/item/vending_refill) diff --git a/code/modules/cargo/markets/market_uplink.dm b/code/modules/cargo/markets/market_uplink.dm index 19c1a049a1b..a82218082e9 100644 --- a/code/modules/cargo/markets/market_uplink.dm +++ b/code/modules/cargo/markets/market_uplink.dm @@ -150,6 +150,7 @@ icon_state = "uplink" //The original black market uplink accessible_markets = list(/datum/market/blackmarket) + custom_premium_price = PAYCHECK_CREW * 2.5 /datum/crafting_recipe/blackmarket_uplink diff --git a/code/modules/cargo/packs/vending_restock.dm b/code/modules/cargo/packs/vending_restock.dm index cfe9961cc3a..10ae874d5d6 100644 --- a/code/modules/cargo/packs/vending_restock.dm +++ b/code/modules/cargo/packs/vending_restock.dm @@ -4,7 +4,7 @@ /datum/supply_pack/vending/bartending name = "Booze-o-mat and Coffee Supply Crate" desc = "Bring on the booze and coffee vending machine refills." - cost = CARGO_CRATE_VALUE * 4 + cost = CARGO_CRATE_VALUE * 2 contains = list(/obj/item/vending_refill/boozeomat, /obj/item/vending_refill/coffee, ) @@ -14,7 +14,7 @@ name = "Cigarette Supply Crate" desc = "Don't believe the reports - smoke today! Contains a \ cigarette vending machine refill." - cost = CARGO_CRATE_VALUE * 3 + cost = CARGO_CRATE_VALUE * 2 contains = list(/obj/item/vending_refill/cigarette) crate_name = "cigarette supply crate" crate_type = /obj/structure/closet/crate @@ -62,7 +62,7 @@ /datum/supply_pack/vending/imported name = "Imported Vending Machines" desc = "Vending machines famous in other parts of the galaxy." - cost = CARGO_CRATE_VALUE * 8 + cost = CARGO_CRATE_VALUE * 5 contains = list(/obj/item/vending_refill/sustenance, /obj/item/vending_refill/robotics, /obj/item/vending_refill/sovietsoda, @@ -74,7 +74,7 @@ name = "Medical Vending Crate" desc = "Contains one NanoMed Plus refill, one NanoDrug Plus refill, \ and one wall-mounted NanoMed refill." - cost = CARGO_CRATE_VALUE * 5 + cost = CARGO_CRATE_VALUE * 3.5 contains = list(/obj/item/vending_refill/medical, /obj/item/vending_refill/drugs, /obj/item/vending_refill/wallmed, @@ -85,7 +85,7 @@ name = "PTech Supply Crate" desc = "Not enough cartridges after half the crew lost their PDA \ to explosions? This may fix it." - cost = CARGO_CRATE_VALUE * 3 + cost = CARGO_CRATE_VALUE * 2.5 contains = list(/obj/item/vending_refill/cart) crate_name = "\improper PTech supply crate" @@ -103,7 +103,7 @@ name = "Snack Supply Crate" desc = "One vending machine refill of cavity-bringin' goodness! \ The number one dentist recommended order!" - cost = CARGO_CRATE_VALUE * 3 + cost = CARGO_CRATE_VALUE * 2 contains = list(/obj/item/vending_refill/snack) crate_name = "snacks supply crate" @@ -111,14 +111,14 @@ name = "Softdrinks Supply Crate" desc = "Got whacked by a toolbox, but you still have those pesky teeth? \ Get rid of those pearly whites with this soda machine refill, today!" - cost = CARGO_CRATE_VALUE * 3 + cost = CARGO_CRATE_VALUE * 2 contains = list(/obj/item/vending_refill/cola) crate_name = "soft drinks supply crate" /datum/supply_pack/vending/vendomat name = "Part-Mart & YouTool Supply Crate" desc = "More tools for your IED testing facility." - cost = CARGO_CRATE_VALUE * 2 + cost = CARGO_CRATE_VALUE * 3 contains = list(/obj/item/vending_refill/assist, /obj/item/vending_refill/youtool, ) @@ -138,7 +138,7 @@ name = "Autodrobe Supply Crate" desc = "Autodrobe missing your favorite dress? Solve that issue today \ with this autodrobe refill." - cost = CARGO_CRATE_VALUE * 3 + cost = CARGO_CRATE_VALUE * 2 contains = list(/obj/item/vending_refill/autodrobe) crate_name = "autodrobe supply crate" @@ -200,7 +200,7 @@ name = "Science Wardrobe Supply Crate" desc = "This crate contains refills for the SciDrobe, \ GeneDrobe, and RoboDrobe." - cost = CARGO_CRATE_VALUE * 3 + cost = CARGO_CRATE_VALUE * 4.5 contains = list(/obj/item/vending_refill/wardrobe/robo_wardrobe, /obj/item/vending_refill/wardrobe/gene_wardrobe, /obj/item/vending_refill/wardrobe/science_wardrobe, diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 16a6eaf021e..551c900983e 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -2722,3 +2722,20 @@ GLOBAL_LIST_EMPTY(fire_appearances) end_look_down() else look_down() + +/** + * Totals the physical cash on the mob and returns the total. + */ +/mob/living/verb/tally_physical_credits() + //Here is all the possible non-ID payment methods. + var/list/counted_money = list() + var/physical_cash_total = 0 + for(var/obj/item/credit as anything in typecache_filter_list(get_all_contents(), GLOB.allowed_money)) //Coins, cash, and credits. + physical_cash_total += credit.get_item_credit_value() + counted_money += credit + + if(is_type_in_typecache(pulling, GLOB.allowed_money)) //Coins(Pulled). + var/obj/item/counted_credit = pulling + physical_cash_total += counted_credit.get_item_credit_value() + counted_money += counted_credit + return round(physical_cash_total) diff --git a/code/modules/modular_computers/computers/item/disks/role_disks.dm b/code/modules/modular_computers/computers/item/disks/role_disks.dm index da52ee76281..f7f20efb70b 100644 --- a/code/modules/modular_computers/computers/item/disks/role_disks.dm +++ b/code/modules/modular_computers/computers/item/disks/role_disks.dm @@ -98,6 +98,7 @@ starting_programs = list( /datum/computer_file/program/shipping, /datum/computer_file/program/budgetorders, + /datum/computer_file/program/restock_tracker, ) /** @@ -123,6 +124,6 @@ /datum/computer_file/program/alarm_monitor, /datum/computer_file/program/atmosscan, /datum/computer_file/program/supermatter_monitor, - + ) diff --git a/code/modules/modular_computers/computers/item/role_tablet_presets.dm b/code/modules/modular_computers/computers/item/role_tablet_presets.dm index 339def50add..9d42ec8c554 100644 --- a/code/modules/modular_computers/computers/item/role_tablet_presets.dm +++ b/code/modules/modular_computers/computers/item/role_tablet_presets.dm @@ -114,6 +114,7 @@ /datum/computer_file/program/robocontrol, /datum/computer_file/program/budgetorders, /datum/computer_file/program/shipping, + /datum/computer_file/program/restock_tracker, ) /** @@ -264,6 +265,7 @@ /datum/computer_file/program/shipping, /datum/computer_file/program/budgetorders, /datum/computer_file/program/robocontrol, + /datum/computer_file/program/restock_tracker, ) /obj/item/modular_computer/pda/shaftminer diff --git a/code/modules/modular_computers/file_system/programs/restock_tracker.dm b/code/modules/modular_computers/file_system/programs/restock_tracker.dm new file mode 100644 index 00000000000..46462c0c6b5 --- /dev/null +++ b/code/modules/modular_computers/file_system/programs/restock_tracker.dm @@ -0,0 +1,31 @@ +/datum/computer_file/program/restock_tracker + filename = "restockapp" + filedesc = "NT Restock Tracker" + downloader_category = PROGRAM_CATEGORY_SUPPLY + program_open_overlay = "restock" + extended_desc = "Nanotrasen IoT network listing all the vending machines found on station, and how well stocked they are each. Profitable!" + program_flags = PROGRAM_ON_NTNET_STORE | PROGRAM_REQUIRES_NTNET + can_run_on_flags = PROGRAM_LAPTOP | PROGRAM_PDA + size = 4 + program_icon = "cash-register" + tgui_id = "NtosRestock" + +/datum/computer_file/program/restock_tracker/ui_data() + var/list/data = list() + var/list/vending_list = list() + var/id_increment = 1 + for(var/obj/machinery/vending/vendor as anything in GLOB.vending_machines_to_restock) + var/stock = vendor.total_loaded_stock() + var/max_stock = vendor.total_max_stock() + if((max_stock == 0 || (stock >= max_stock)) && vendor.credits_contained == 0) + continue + vending_list += list(list( + "name" = vendor.name, + "location" = get_area_name(vendor), + "credits" = vendor.credits_contained, + "percentage" = (stock / max_stock) * 100, + "id" = id_increment, + )) + id_increment++ + data["vending_list"] = vending_list + return data diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm index a344140d181..4ad46bb3b1a 100644 --- a/code/modules/vending/_vending.dm +++ b/code/modules/vending/_vending.dm @@ -14,8 +14,12 @@ premium = list() */ +/// List of vending machines that players can restock, so only vending machines that are on station or don't have a unique condition. +GLOBAL_LIST_EMPTY(vending_machines_to_restock) + /// Maximum amount of items in a storage bag that we're transferring items to the vendor from. #define MAX_VENDING_INPUT_AMOUNT 30 +#define CREDITS_DUMP_THRESHOLD 50 /** * # vending record datum * @@ -178,6 +182,8 @@ var/displayed_currency_name = " cr" ///Whether our age check is currently functional var/age_restrictions = TRUE + /// How many credits does this vending machine have? 20% of all sales go to this pool, and are given freely when the machine is restocked, or successfully tilted. Lost on deconstruction. + var/credits_contained = 0 /** * Is this item on station or not * @@ -256,6 +262,7 @@ onstation = FALSE if(circuit) circuit.onstation = onstation //sync up the circuit so the pricing schema is carried over if it's reconstructed. + else if(HAS_TRAIT(SSstation, STATION_TRAIT_VENDING_SHORTAGE)) for (var/datum/data/vending_product/product_record as anything in product_records + coin_records + hidden_records) /** @@ -264,16 +271,22 @@ */ var/max_amount = rand(CEILING(product_record.amount * 0.5, 1), product_record.amount) product_record.amount = rand(0, max_amount) + credits_contained += rand(0, 1) //randomly add a few credits to the machine to make it look like it's been used, proportional to the amount missing. if(tiltable && prob(6)) // 1 in 17 chance to start tilted (as an additional hint to the station trait behind it) INVOKE_ASYNC(src, PROC_REF(tilt), loc) + credits_contained = 0 // If it's tilted, it's been looted, so no credits for you. else if(circuit && (circuit.onstation != onstation)) //check if they're not the same to minimize the amount of edited values. onstation = circuit.onstation //if it was constructed outside mapload, sync the vendor up with the circuit's var so you can't bypass price requirements by moving / reconstructing it off station. + if(onstation && !onstation_override) + AddComponent(/datum/component/payment, 0, SSeconomy.get_dep_account(payment_department), PAYMENT_VENDING) + GLOB.vending_machines_to_restock += src //We need to keep track of the final onstation vending machines so we can keep them restocked. /obj/machinery/vending/Destroy() QDEL_NULL(wires) QDEL_NULL(coin) QDEL_NULL(bill) QDEL_NULL(sec_radio) + GLOB.vending_machines_to_restock -= src return ..() /obj/machinery/vending/can_speak() @@ -611,6 +624,24 @@ else //no category found - dump it into standard stock products[record.product_path] = record.amount +/** + * Returns the total amount of items in the vending machine based on the product records and premium records, but not contraband + */ +/obj/machinery/vending/proc/total_loaded_stock() + var/total = 0 + for(var/datum/data/vending_product/record as anything in product_records + coin_records) + total += record.amount + return total + +/** + * Returns the total amount of items in the vending machine based on the product records and premium records, but not contraband + */ +/obj/machinery/vending/proc/total_max_stock() + var/total_max = 0 + for(var/datum/data/vending_product/record as anything in product_records + coin_records) + total_max += record.max_amount + return total_max + /obj/machinery/vending/crowbar_act(mob/living/user, obj/item/attack_item) if(!component_parts) return FALSE @@ -655,7 +686,11 @@ // instantiate canister if needed var/transferred = restock(canister) if(transferred) - to_chat(user, span_notice("You loaded [transferred] items in [src].")) + to_chat(user, span_notice("You loaded [transferred] items in [src][credits_contained > 0 ? ", and are rewarded [credits_contained] credits." : "."]")) + var/datum/bank_account/cargo_account = SSeconomy.get_dep_account(ACCOUNT_CAR) + cargo_account.adjust_money(round(credits_contained * 0.5), "Vending: Restock") + var/obj/item/holochip/payday = new(src, credits_contained) + try_put_in_hand(payday, user) else to_chat(user, span_warning("There's nothing to restock!")) return @@ -707,7 +742,7 @@ * freebies - number of free items to vend */ /obj/machinery/vending/proc/freebie(freebies) - visible_message(span_notice("[src] yields [freebies > 1 ? "several free goodies" : "a free goody"]!")) + visible_message(span_notice("[src] yields [freebies > 1 ? "several free goodies" : "a free goody"][credits_contained > 0 ? " and some credits" : ""]!")) for(var/i in 1 to freebies) playsound(src, 'sound/machines/machine_vend.ogg', 50, TRUE, extrarange = -3) @@ -726,6 +761,7 @@ returned_obj_to_dump.forceMove(get_turf(src)) record.amount-- break + deploy_credits() /** * Tilts ontop of the atom supplied, if crit is true some extra shit can happen. See [fall_and_crush] for return values. @@ -1206,13 +1242,15 @@ /obj/machinery/vending/ui_data(mob/user) . = list() var/obj/item/card/id/card_used + var/held_cash = 0 if(isliving(user)) var/mob/living/living_user = user card_used = living_user.get_idcard(TRUE) + held_cash = living_user.tally_physical_credits() if(card_used?.registered_account) .["user"] = list() .["user"]["name"] = card_used.registered_account.account_holder - .["user"]["cash"] = fetch_balance_to_use(card_used) + .["user"]["cash"] = fetch_balance_to_use(card_used) + held_cash if(card_used.registered_account.account_job) .["user"]["job"] = card_used.registered_account.account_job.title .["user"]["department"] = card_used.registered_account.account_job.paycheck_department @@ -1333,25 +1371,12 @@ vend_ready = TRUE return if(onstation) + // Here we do additional handing ahead of the payment component's logic, such as age restrictions and additional logging var/obj/item/card/id/card_used + var/mob/living/living_user if(isliving(usr)) - var/mob/living/living_user = usr + living_user = usr card_used = living_user.get_idcard(TRUE) - if(!card_used) - speak("No card found.") - flick(icon_deny,src) - vend_ready = TRUE - return - else if (!card_used.registered_account) - speak("No account found.") - flick(icon_deny,src) - vend_ready = TRUE - return - else if(!card_used.registered_account.account_job) - speak("Departmental accounts have been blacklisted from personal expenses due to embezzlement.") - flick(icon_deny, src) - vend_ready = TRUE - return else if(age_restrictions && item_record.age_restricted && (!card_used.registered_age || card_used.registered_age < AGE_MINOR)) speak("You are not of legal age to purchase [item_record.name].") if(!(usr in GLOB.narcd_underages)) @@ -1365,7 +1390,7 @@ vend_ready = TRUE return - if(!proceed_payment(card_used, item_record, price_to_use)) + if(!proceed_payment(card_used, living_user, item_record, price_to_use)) return if(last_shopper != REF(usr) || purchase_message_cooldown < world.time) @@ -1407,11 +1432,12 @@ /** * Handles payment processing: discounts, logging, balance change etc. * arguments: - * paying_id_card - the id card that will be billed for the product - * product_to_vend - the product record of the item we're trying to vend - * price_to_use - price of the item we're trying to vend + * paying_id_card - the id card that will be billed for the product. + * mob_paying - the mob that is trying to purchase the item. + * product_to_vend - the product record of the item we're trying to vend. + * price_to_use - price of the item we're trying to vend. */ -/obj/machinery/vending/proc/proceed_payment(obj/item/card/id/paying_id_card, datum/data/vending_product/product_to_vend, price_to_use) +/obj/machinery/vending/proc/proceed_payment(obj/item/card/id/paying_id_card, mob/living/mob_paying, datum/data/vending_product/product_to_vend, price_to_use) var/datum/bank_account/account = paying_id_card.registered_account if(account.account_job && account.account_job.paycheck_department == payment_department) price_to_use = max(round(price_to_use * DEPARTMENT_DISCOUNT), 1) //No longer free, but signifigantly cheaper. @@ -1419,7 +1445,7 @@ price_to_use = product_to_vend.custom_premium_price ? product_to_vend.custom_premium_price : extra_price if(LAZYLEN(product_to_vend.returned_products)) price_to_use = 0 //returned items are free - if(price_to_use && !account.adjust_money(-price_to_use, "Vending: [product_to_vend.name]")) + if(price_to_use && (attempt_charge(src, mob_paying, price_to_use) & COMPONENT_OBJ_CANCEL_CHARGE)) speak("You do not possess the funds to purchase [product_to_vend.name].") flick(icon_deny,src) vend_ready = TRUE @@ -1427,10 +1453,10 @@ //actual payment here var/datum/bank_account/paying_id_account = SSeconomy.get_dep_account(payment_department) if(paying_id_account) - paying_id_account.adjust_money(price_to_use) SSblackbox.record_feedback("amount", "vending_spent", price_to_use) SSeconomy.track_purchase(account, price_to_use, name) log_econ("[price_to_use] credits were inserted into [src] by [account.account_holder] to buy [product_to_vend].") + credits_contained += round(price_to_use * 0.2) return TRUE /obj/machinery/vending/process(seconds_per_tick) @@ -1569,6 +1595,15 @@ tilt(fatty=hit_atom) return ..() +/** Drop credits when the vendor is attacked.*/ +/obj/machinery/vending/proc/deploy_credits() + if(credits_contained <= 0) + return + var/credits_to_remove = min(CREDITS_DUMP_THRESHOLD, round(credits_contained)) + var/obj/item/holochip/holochip = new(loc, credits_to_remove) + credits_contained = max(0, credits_contained - credits_to_remove) + SSblackbox.record_feedback("amount", "vending machine looted", holochip.credits) + /obj/machinery/vending/custom name = "Custom Vendor" icon_state = "custom" diff --git a/code/modules/vending/assist.dm b/code/modules/vending/assist.dm index 229b19aeadb..a043a365046 100644 --- a/code/modules/vending/assist.dm +++ b/code/modules/vending/assist.dm @@ -21,6 +21,7 @@ /obj/item/assembly/timer = 2, /obj/item/assembly/voice = 2, /obj/item/stock_parts/cell/high = 1, + /obj/item/market_uplink/blackmarket = 1, ) premium = list( /obj/item/assembly/igniter/condenser = 2, diff --git a/code/modules/vending/sustenance.dm b/code/modules/vending/sustenance.dm index d8229121490..a1d11c30727 100644 --- a/code/modules/vending/sustenance.dm +++ b/code/modules/vending/sustenance.dm @@ -48,7 +48,7 @@ return return ..() -/obj/machinery/vending/sustenance/labor_camp/proceed_payment(obj/item/card/id/paying_id_card, datum/data/vending_product/product_to_vend, price_to_use) +/obj/machinery/vending/sustenance/labor_camp/proceed_payment(obj/item/card/id/paying_id_card, mob/living/mob_paying, datum/data/vending_product/product_to_vend, price_to_use) if(!istype(paying_id_card, /obj/item/card/id/advanced/prisoner)) speak("I don't take bribes! Pay with labor points!") return FALSE diff --git a/icons/obj/machines/modular_console.dmi b/icons/obj/machines/modular_console.dmi index 2677dbb7122..7b370a76785 100644 Binary files a/icons/obj/machines/modular_console.dmi and b/icons/obj/machines/modular_console.dmi differ diff --git a/icons/obj/modular_laptop.dmi b/icons/obj/modular_laptop.dmi index c8ad438d1a3..1accc56f4c1 100644 Binary files a/icons/obj/modular_laptop.dmi and b/icons/obj/modular_laptop.dmi differ diff --git a/icons/obj/modular_pda.dmi b/icons/obj/modular_pda.dmi index 5a39c6cd726..afd75b78d4b 100644 Binary files a/icons/obj/modular_pda.dmi and b/icons/obj/modular_pda.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 5563d87506a..f9fdfc3f1b3 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -5187,6 +5187,7 @@ #include "code\modules\modular_computers\file_system\programs\powermonitor.dm" #include "code\modules\modular_computers\file_system\programs\radar.dm" #include "code\modules\modular_computers\file_system\programs\records.dm" +#include "code\modules\modular_computers\file_system\programs\restock_tracker.dm" #include "code\modules\modular_computers\file_system\programs\robocontrol.dm" #include "code\modules\modular_computers\file_system\programs\robotact.dm" #include "code\modules\modular_computers\file_system\programs\secureye.dm" diff --git a/tgui/packages/tgui/interfaces/NtosRestock.tsx b/tgui/packages/tgui/interfaces/NtosRestock.tsx new file mode 100644 index 00000000000..055dfda6e4e --- /dev/null +++ b/tgui/packages/tgui/interfaces/NtosRestock.tsx @@ -0,0 +1,12 @@ +import { NtosWindow } from '../layouts'; +import { RestockTracker } from './RestockTracker'; + +export const NtosRestock = (props) => { + return ( + + + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/RestockTracker.jsx b/tgui/packages/tgui/interfaces/RestockTracker.jsx new file mode 100644 index 00000000000..236f486069c --- /dev/null +++ b/tgui/packages/tgui/interfaces/RestockTracker.jsx @@ -0,0 +1,86 @@ +import { sortBy } from 'common/collections'; +import { round } from 'common/math'; + +import { useBackend } from '../backend'; +import { ColorBox, ProgressBar, Section, Stack } from '../components'; +import { Window } from '../layouts'; + +export const Restock = (props) => { + return ( + + + + + + ); +}; + +export const RestockTracker = (props) => { + const { data } = useBackend(); + const vending_list = sortBy((vend) => vend.percentage)( + data.vending_list ?? [], + ); + return ( +
+ + + + Vending Name + + + Location + + + Stock % + + + Credits stored + + +
+ {vending_list?.map((vend) => ( + + + {vend.name} + + + {vend.location} + + 75 + ? 'left' + : vend.percentage > 45 + ? 'right' + : 'center' + } + > + + {round(vend.percentage, 0.01)} + + + 50 ? 'good' : 'bad'} + > + 50 ? 'good' : 'bad'} mr={'5%'} /> + {vend.credits} + + + ))} +
+
+ ); +};