diff --git a/code/game/objects/structures/crates_lockers/crates/secure.dm b/code/game/objects/structures/crates_lockers/crates/secure.dm index 2c923c1905..eb652c5180 100644 --- a/code/game/objects/structures/crates_lockers/crates/secure.dm +++ b/code/game/objects/structures/crates_lockers/crates/secure.dm @@ -80,16 +80,25 @@ name = "private crate" desc = "A crate cover designed to only open for who purchased its contents." icon_state = "privatecrate" + ///Account of the person buying the crate if private purchasing. var/datum/bank_account/buyer_account + ///Department of the person buying the crate if buying via the NIRN app. + var/datum/bank_account/department/department_account + ///Is the secure crate opened or closed? var/privacy_lock = TRUE + ///Is the crate being bought by a person, or a budget card? + var/department_purchase = FALSE /obj/structure/closet/crate/secure/owned/examine(mob/user) . = ..() - to_chat(user, "It's locked with a privacy lock, and can only be unlocked by the buyer's ID.") + . += "It's locked with a privacy lock, and can only be unlocked by the buyer's ID." /obj/structure/closet/crate/secure/owned/Initialize(mapload, datum/bank_account/_buyer_account) . = ..() buyer_account = _buyer_account + if(istype(buyer_account, /datum/bank_account/department)) + department_purchase = TRUE + department_account = buyer_account /obj/structure/closet/crate/secure/owned/togglelock(mob/living/user, silent) if(privacy_lock) @@ -97,7 +106,7 @@ var/obj/item/card/id/id_card = user.get_idcard(TRUE) if(id_card) if(id_card.registered_account) - if(id_card.registered_account == buyer_account) + if(id_card.registered_account == buyer_account || (department_purchase && (id_card.registered_account?.account_job?.paycheck_department) == (department_account.department_id))) if(iscarbon(user)) add_fingerprint(user) locked = !locked diff --git a/code/modules/modular_computers/file_system/programs/budgetordering.dm b/code/modules/modular_computers/file_system/programs/budgetordering.dm index e55257dfbd..162f480c02 100644 --- a/code/modules/modular_computers/file_system/programs/budgetordering.dm +++ b/code/modules/modular_computers/file_system/programs/budgetordering.dm @@ -1,7 +1,7 @@ /datum/computer_file/program/budgetorders filename = "orderapp" filedesc = "NT IRN" - category = PROGRAM_CATEGORY_SUPL + // category = PROGRAM_CATEGORY_SUPL program_icon_state = "request" extended_desc = "Nanotrasen Internal Requisition Network interface for supply purchasing using a department budget account." requires_ntnet = TRUE @@ -36,7 +36,7 @@ return FALSE if(!paccess_to_check) // No required_access, allow it. return TRUE - if(isAdminGhostAI(user)) + if(IsAdminGhost(user)) return TRUE //Aquire access from the inserted ID card. diff --git a/code/modules/shuttle/supply.dm b/code/modules/shuttle/supply.dm index 7af0315934..899e2b2f6f 100644 --- a/code/modules/shuttle/supply.dm +++ b/code/modules/shuttle/supply.dm @@ -25,7 +25,14 @@ GLOBAL_LIST_INIT(blacklisted_cargo_types, typecacheof(list( /obj/item/shared_storage, /obj/structure/extraction_point, /obj/machinery/syndicatebomb, - /obj/item/hilbertshotel + /obj/item/hilbertshotel, + /obj/machinery/launchpad, + /obj/machinery/disposal, + /obj/structure/disposalpipe, + /obj/item/hilbertshotel, + /obj/machinery/camera, + /obj/item/gps, + /obj/structure/checkoutmachine ))) GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list( @@ -33,6 +40,11 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list( /mob/living/simple_animal/slaughter ))) +/// How many goody orders we can fit in a lockbox before we upgrade to a crate +#define GOODY_FREE_SHIPPING_MAX 5 +/// How much to charge oversized goody orders +#define CRATE_TAX 700 + /obj/docking_port/mobile/supply name = "supply shuttle" id = "supply" @@ -58,6 +70,7 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list( return check_blacklist(shuttle_areas, GLOB.blacklisted_cargo_types - GLOB.cargo_shuttle_leave_behind_typecache) return ..() +// fuc off /obj/docking_port/mobile/supply/enterTransit() var/list/leave_behind = list() for(var/i in check_blacklist(shuttle_areas, GLOB.cargo_shuttle_leave_behind_typecache)) @@ -98,12 +111,11 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list( sell() /obj/docking_port/mobile/supply/proc/buy() - if(!SSshuttle.shoppinglist.len) - return - var/list/obj/miscboxes = list() //miscboxes are combo boxes that contain all goody orders grouped var/list/misc_order_num = list() //list of strings of order numbers, so that the manifest can show all orders in a box var/list/misc_contents = list() //list of lists of items that each box will contain + if(!SSshuttle.shoppinglist.len) + return var/list/empty_turfs = list() for(var/place in shuttle_areas) @@ -113,30 +125,39 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list( continue empty_turfs += T - var/datum/bank_account/cargo_budget = SSeconomy.get_dep_account(ACCOUNT_CAR) var/value = 0 var/purchases = 0 + var/list/goodies_by_buyer = list() // if someone orders more than GOODY_FREE_SHIPPING_MAX goodies, we upcharge to a normal crate so they can't carry around 20 combat shotties + for(var/datum/supply_order/SO in SSshuttle.shoppinglist) if(!empty_turfs.len) break - var/price = SO.pack.cost if(SO.applied_coupon) price *= (1 - SO.applied_coupon.discount_pct_off) + var/datum/bank_account/D if(SO.paying_account) //Someone paid out of pocket D = SO.paying_account + var/list/current_buyer_orders = goodies_by_buyer[SO.paying_account] // so we can access the length a few lines down if(!SO.pack.goody) price *= 1.1 //TODO make this customizable by the quartermaster + + // note this is before we increment, so this is the GOODY_FREE_SHIPPING_MAX + 1th goody to ship. also note we only increment off this step if they successfully pay the fee, so there's no way around it + else if(LAZYLEN(current_buyer_orders) == GOODY_FREE_SHIPPING_MAX) + price += CRATE_TAX + D.bank_card_talk("Goody order size exceeds free shipping limit: Assessing [CRATE_TAX] credit S&H fee.") else - D = cargo_budget + D = SSeconomy.get_dep_account(ACCOUNT_CAR) if(D) - if(!D.adjust_money(-SO.pack.cost)) + if(!D.adjust_money(-price)) if(SO.paying_account) D.bank_card_talk("Cargo order #[SO.id] rejected due to lack of funds. Credits required: [price]") continue if(SO.paying_account) + if(SO.pack.goody) + LAZYADD(goodies_by_buyer[SO.paying_account], SO) D.bank_card_talk("Cargo order #[SO.id] has shipped. [price] credits have been charged to your bank account.") var/datum/bank_account/department/cargo = SSeconomy.get_dep_account(ACCOUNT_CAR) cargo.adjust_money(price - SO.pack.cost) //Cargo gets the handling fee @@ -145,30 +166,7 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list( SSshuttle.orderhistory += SO QDEL_NULL(SO.applied_coupon) - if(SO.pack.goody) //goody means it gets piled in the miscbox - if(SO.paying_account) - if(!miscboxes.len || !miscboxes[D.account_holder]) //if there's no miscbox for this person - miscboxes[D.account_holder] = new /obj/item/storage/lockbox/order(pick_n_take(empty_turfs)) - var/obj/item/storage/lockbox/order/our_box = miscboxes[D.account_holder] - our_box.buyer_account = SO.paying_account - miscboxes[D.account_holder].name = "small items case - purchased by [D.account_holder]" - misc_contents[D.account_holder] = list() - for (var/item in SO.pack.contains) - misc_contents[D.account_holder] += item - misc_order_num[D.account_holder] = "[misc_order_num[D.account_holder]]#[SO.id] " - else //No private payment, so we just stuff it all into a generic crate - if(!miscboxes.len || !miscboxes["Cargo"]) - miscboxes["Cargo"] = new /obj/structure/closet/secure_closet/goodies(pick_n_take(empty_turfs)) - miscboxes["Cargo"].name = "small items closet" - misc_contents["Cargo"] = list() - miscboxes["Cargo"].req_access = list() - for (var/item in SO.pack.contains) - misc_contents["Cargo"] += item - //new item(miscboxes["Cargo"]) - if(SO.pack.access) - miscboxes["Cargo"].req_access += SO.pack.access - misc_order_num["Cargo"] = "[misc_order_num["Cargo"]]#[SO.id] " - else + if(!SO.pack.goody) //we handle goody crates below SO.generate(pick_n_take(empty_turfs)) SSblackbox.record_feedback("nested tally", "cargo_imports", 1, list("[SO.pack.cost]", "[SO.pack.name]")) @@ -177,16 +175,43 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list( message_admins("\A [SO.pack.name] ordered by [ADMIN_LOOKUPFLW(SO.orderer_ckey)], paid by [D.account_holder] has shipped.") purchases++ + // we handle packing all the goodies last, since the type of crate we use depends on how many goodies they ordered. If it's more than GOODY_FREE_SHIPPING_MAX + // then we send it in a crate (including the CRATE_TAX cost), otherwise send it in a free shipping case + for(var/D in goodies_by_buyer) + var/list/buying_account_orders = goodies_by_buyer[D] + var/datum/bank_account/buying_account = D + var/buyer = buying_account.account_holder + + if(buying_account_orders.len > GOODY_FREE_SHIPPING_MAX) // no free shipping, send a crate + var/obj/structure/closet/crate/secure/owned/our_crate = new /obj/structure/closet/crate/secure/owned(pick_n_take(empty_turfs)) + our_crate.buyer_account = buying_account + our_crate.name = "goody crate - purchased by [buyer]" + miscboxes[buyer] = our_crate + else //free shipping in a case + miscboxes[buyer] = new /obj/item/storage/lockbox/order(pick_n_take(empty_turfs)) + var/obj/item/storage/lockbox/order/our_case = miscboxes[buyer] + our_case.buyer_account = buying_account + miscboxes[buyer].name = "goody case - purchased by [buyer]" + misc_contents[buyer] = list() + + for(var/O in buying_account_orders) + var/datum/supply_order/our_order = O + for (var/item in our_order.pack.contains) + misc_contents[buyer] += item + misc_order_num[buyer] = "[misc_order_num[buyer]]#[our_order.id] " + for(var/I in miscboxes) var/datum/supply_order/SO = new/datum/supply_order() SO.id = misc_order_num[I] SO.generateCombo(miscboxes[I], I, misc_contents[I]) qdel(SO) + var/datum/bank_account/cargo_budget = SSeconomy.get_dep_account(ACCOUNT_CAR) investigate_log("[purchases] orders in this shipment, worth [value] credits. [cargo_budget.account_balance] credits left.", INVESTIGATE_CARGO) /obj/docking_port/mobile/supply/proc/sell() var/datum/bank_account/D = SSeconomy.get_dep_account(ACCOUNT_CAR) + var/presale_points = D.account_balance var/gain = 0 if(!GLOB.exports_list.len) // No exports list? Generate it! @@ -204,6 +229,8 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list( continue if(bounty_ship_item_and_contents(AM, dry_run = FALSE)) matched_bounty = TRUE + // ignore mech checks because the mech is ONLY for bounty + continue if(!AM.anchored || istype(AM, /obj/mecha)) export_item_and_contents(AM, export_categories , dry_run = FALSE, external_report = ex) @@ -230,4 +257,7 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list( msg = copytext_char(msg, 1, MAX_MESSAGE_LEN) SSshuttle.centcom_message = msg - investigate_log("Shuttle contents sold for [gain] credits. Contents: [ex.exported_atoms || "none."] Message: [SSshuttle.centcom_message || "none."]", INVESTIGATE_CARGO) + investigate_log("Shuttle contents sold for [D.account_balance - presale_points] credits. Contents: [ex.exported_atoms ? ex.exported_atoms.Join(",") + "." : "none."] Message: [SSshuttle.centcom_message || "none."]", INVESTIGATE_CARGO) + +#undef GOODY_FREE_SHIPPING_MAX +#undef CRATE_TAX