From 495ccc99c5604ad356823d2f5f0675ae81a45acd Mon Sep 17 00:00:00 2001
From: Ghommie <42542238+Ghommie@users.noreply.github.com>
Date: Mon, 8 Jun 2020 06:12:51 +0200
Subject: [PATCH 1/7] Porting some cargo/vending updates.
---
code/__DEFINES/cargo.dm | 6 +-
code/datums/components/omen.dm | 74 +++++++++
code/game/machinery/doors/airlock.dm | 4 +-
.../items/stacks/sheets/sheet_types.dm | 3 +
.../objects/items/stacks/tiles/tile_types.dm | 30 ++++
code/game/objects/items/storage/fancy.dm | 19 +++
code/game/objects/items/storage/lockbox.dm | 53 +++++--
.../closets/secure/secure_closets.dm | 12 +-
code/modules/cargo/console.dm | 22 ++-
code/modules/cargo/coupon.dm | 50 ++++++
code/modules/cargo/order.dm | 75 +++++----
code/modules/cargo/packs.dm | 1 +
code/modules/cargo/packs/armory.dm | 9 --
code/modules/cargo/packs/engineering.dm | 11 +-
code/modules/cargo/packs/goodies.dm | 77 +++++++++
code/modules/cargo/packs/materials.dm | 76 ++++-----
code/modules/cargo/packs/medical.dm | 57 -------
code/modules/cargo/packs/misc.dm | 89 ++++++-----
code/modules/power/power.dm | 4 +-
code/modules/shuttle/supply.dm | 43 ++++-
code/modules/vending/_vending.dm | 149 +++++++++++++++++-
code/modules/vending/medical_wall.dm | 1 +
icons/obj/closet.dmi | Bin 38279 -> 39711 bytes
tgstation.dme | 3 +
tgui-next/packages/tgui/interfaces/Cargo.js | 21 ++-
tgui-next/packages/tgui/public/tgui.bundle.js | 2 +-
26 files changed, 666 insertions(+), 225 deletions(-)
create mode 100644 code/datums/components/omen.dm
create mode 100644 code/modules/cargo/coupon.dm
create mode 100644 code/modules/cargo/packs/goodies.dm
diff --git a/code/__DEFINES/cargo.dm b/code/__DEFINES/cargo.dm
index 52a2d56697..bba5b5c5ed 100644
--- a/code/__DEFINES/cargo.dm
+++ b/code/__DEFINES/cargo.dm
@@ -32,4 +32,8 @@
list("", "\improper S.T.E.A.L.T.H. pod MKVII", "A supply pod that, under normal circumstances, is completely invisible to conventional methods of detection. How are you even seeing this?"),\
list("gondolapod", "gondola", "The silent walker. This one seems to be part of a delivery agency."),\
list("", "", "")\
-)
\ No newline at end of file
+)
+
+#define PACK_GOODY_NONE 0
+#define PACK_GOODY_PUBLIC 1 //can be bought by both privates and cargo
+#define PACK_GOODY_PRIVATE 2 //can be bought only by privates
\ No newline at end of file
diff --git a/code/datums/components/omen.dm b/code/datums/components/omen.dm
new file mode 100644
index 0000000000..3ea7677710
--- /dev/null
+++ b/code/datums/components/omen.dm
@@ -0,0 +1,74 @@
+/**
+ * omen.dm: For when you want someone to have a really bad day
+ *
+ * When you attach an omen component to someone, they start running the risk of all sorts of bad environmental injuries, like nearby vending machines randomly falling on you,
+ * or hitting your head really hard when you slip and fall, or... well, for now those two are all I have. More will come.
+ *
+ * Omens are removed once the victim is either maimed by one of the possible injuries, or if they receive a blessing (read: bashing with a bible) from the chaplain.
+ */
+/datum/component/omen
+ dupe_mode = COMPONENT_DUPE_UNIQUE
+
+ /// Whatever's causing the omen, if there is one. Destroying the vessel won't stop the omen, but we destroy the vessel (if one exists) upon the omen ending
+ var/obj/vessel
+
+/datum/component/omen/Initialize(silent=FALSE, vessel)
+ if(!isliving(parent))
+ return COMPONENT_INCOMPATIBLE
+ var/mob/person = parent
+ if(!silent)
+ to_chat(person, "You get a bad feeling...")
+ src.vessel = vessel
+
+/datum/component/omen/Destroy(force, silent)
+ if(vessel)
+ vessel.visible_message("[vessel] burns up in a sinister flash, taking an evil energy with it...")
+ vessel = null
+ return ..()
+
+/datum/component/omen/RegisterWithParent()
+ RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/check_accident)
+ RegisterSignal(parent, COMSIG_LIVING_STATUS_KNOCKDOWN, .proc/check_slip)
+ RegisterSignal(parent, COMSIG_ADD_MOOD_EVENT, .proc/check_bless)
+
+/datum/component/omen/UnregisterFromParent()
+ UnregisterSignal(parent, list(COMSIG_LIVING_STATUS_KNOCKDOWN, COMSIG_MOVABLE_MOVED, COMSIG_ADD_MOOD_EVENT))
+
+/**
+ * check_accident() is called each step we take
+ *
+ * While we're walking around, roll to see if there's any environmental hazards (currently only vending machines) on one of the adjacent tiles we can trigger.
+ * We do the prob() at the beginning to A. add some tension for /when/ it will strike, and B. (more importantly) ameliorate the fact that we're checking up to 5 turfs's contents each time
+ */
+/datum/component/omen/proc/check_accident(atom/movable/our_guy)
+ if(!prob(15))
+ return
+ for(var/t in get_adjacent_open_turfs(our_guy))
+ var/turf/the_turf = t
+ for(var/obj/machinery/vending/darth_vendor in the_turf)
+ if(darth_vendor.tiltable)
+ darth_vendor.tilt(our_guy)
+ qdel(src)
+ return
+
+/// If we get knocked down, see if we have a really bad slip and bash our head hard
+/datum/component/omen/proc/check_slip(mob/living/our_guy, amount)
+ if(amount <= 0 || prob(50)) // 50% chance to bonk our head
+ return
+
+ var/obj/item/bodypart/the_head = our_guy.get_bodypart(BODY_ZONE_HEAD)
+ if(!the_head)
+ return
+
+ playsound(get_turf(our_guy), "sound/effects/tableheadsmash.ogg", 90, TRUE)
+ our_guy.visible_message("[our_guy] hits [our_guy.p_their()] head really badly falling down!", "You hit your head really badly falling down!")
+ the_head.receive_damage(75)
+ our_guy.adjustOrganLoss(ORGAN_SLOT_BRAIN, 100)
+ qdel(src)
+
+/// Hijack the mood system to see if we get the blessing mood event to cancel the omen
+/datum/component/omen/proc/check_bless(mob/living/our_guy, category)
+ if(category != "blessing")
+ return
+ to_chat(our_guy, "You feel a horrible omen lifted off your shoulders!")
+ qdel(src)
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index 2a45267c65..635522fa41 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -413,8 +413,8 @@
// shock user with probability prb (if all connections & power are working)
// returns TRUE if shocked, FALSE otherwise
// The preceding comment was borrowed from the grille's shock script
-/obj/machinery/door/airlock/proc/shock(mob/user, prb)
- if(!hasPower()) // unpowered, no shock
+/obj/machinery/door/airlock/proc/shock(mob/living/user, prb)
+ if(!istype(user) || !hasPower()) // unpowered, no shock
return FALSE
if(shockCooldown > world.time)
return FALSE //Already shocked someone recently?
diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index 6553cd2f7c..35fb374e7f 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -778,6 +778,9 @@ GLOBAL_LIST_INIT(plastic_recipes, list(
/obj/item/stack/sheet/plastic/fifty
amount = 50
+/obj/item/stack/sheet/plastic/twenty
+ amount = 20
+
/obj/item/stack/sheet/plastic/five
amount = 5
diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm
index ff81b4340a..0635c55ca3 100644
--- a/code/game/objects/items/stacks/tiles/tile_types.dm
+++ b/code/game/objects/items/stacks/tiles/tile_types.dm
@@ -266,6 +266,9 @@
/obj/item/stack/tile/carpet/blackred/twenty
amount = 20
+/obj/item/stack/tile/carpet/blackred/thirty
+ amount = 30
+
/obj/item/stack/tile/carpet/blackred/fifty
amount = 50
@@ -275,6 +278,9 @@
/obj/item/stack/tile/carpet/monochrome/twenty
amount = 20
+/obj/item/stack/tile/carpet/monochrome/thirty
+ amount = 30
+
/obj/item/stack/tile/carpet/monochrome/fifty
amount = 50
@@ -284,6 +290,9 @@
/obj/item/stack/tile/carpet/blue/twenty
amount = 20
+/obj/item/stack/tile/carpet/blue/thirty
+ amount = 30
+
/obj/item/stack/tile/carpet/blue/fifty
amount = 50
@@ -293,6 +302,9 @@
/obj/item/stack/tile/carpet/cyan/twenty
amount = 20
+/obj/item/stack/tile/carpet/cyan/thirty
+ amount = 30
+
/obj/item/stack/tile/carpet/cyan/fifty
amount = 50
@@ -302,6 +314,9 @@
/obj/item/stack/tile/carpet/green/twenty
amount = 20
+/obj/item/stack/tile/carpet/green/thirty
+ amount = 30
+
/obj/item/stack/tile/carpet/green/fifty
amount = 50
@@ -311,6 +326,9 @@
/obj/item/stack/tile/carpet/orange/twenty
amount = 20
+/obj/item/stack/tile/carpet/orange/thirty
+ amount = 30
+
/obj/item/stack/tile/carpet/orange/fifty
amount = 50
@@ -320,6 +338,9 @@
/obj/item/stack/tile/carpet/purple/twenty
amount = 20
+/obj/item/stack/tile/carpet/purple/thirty
+ amount = 30
+
/obj/item/stack/tile/carpet/purple/fifty
amount = 50
@@ -329,6 +350,9 @@
/obj/item/stack/tile/carpet/red/twenty
amount = 20
+/obj/item/stack/tile/carpet/red/thirty
+ amount = 30
+
/obj/item/stack/tile/carpet/red/fifty
amount = 50
@@ -338,6 +362,9 @@
/obj/item/stack/tile/carpet/royalblack/twenty
amount = 20
+/obj/item/stack/tile/carpet/royalblack/thirty
+ amount = 30
+
/obj/item/stack/tile/carpet/royalblack/fifty
amount = 50
@@ -347,6 +374,9 @@
/obj/item/stack/tile/carpet/royalblue/twenty
amount = 20
+/obj/item/stack/tile/carpet/royalblue/thirty
+ amount = 30
+
/obj/item/stack/tile/carpet/royalblue/fifty
amount = 50
diff --git a/code/game/objects/items/storage/fancy.dm b/code/game/objects/items/storage/fancy.dm
index 685a3b59f6..e263709ad8 100644
--- a/code/game/objects/items/storage/fancy.dm
+++ b/code/game/objects/items/storage/fancy.dm
@@ -137,6 +137,22 @@
icon_type = "cigarette"
spawn_type = /obj/item/clothing/mask/cigarette/space_cigarette
custom_price = 75
+ var/spawn_coupon = TRUE
+
+/obj/item/storage/fancy/cigarettes/attack_self(mob/user)
+ if(contents.len == 0 && spawn_coupon)
+ to_chat(user, "You rip the back off \the [src] and get a coupon!")
+ var/obj/item/coupon/attached_coupon = new
+ user.put_in_hands(attached_coupon)
+ attached_coupon.generate()
+ attached_coupon = null
+ spawn_coupon = FALSE
+ name = "discarded cigarette packet"
+ desc = "An old cigarette packet with the back torn off, worth less than nothing now."
+ var/datum/component/storage/STR = GetComponent(/datum/component/storage)
+ STR.max_items = 0
+ return
+ return ..()
/obj/item/storage/fancy/cigarettes/ComponentInitialize()
. = ..()
@@ -147,6 +163,8 @@
/obj/item/storage/fancy/cigarettes/examine(mob/user)
. = ..()
. += "Alt-click to extract contents."
+ if(spawn_coupon)
+ . += "There's a coupon on the back of the pack! You can tear it off once it's empty."
/obj/item/storage/fancy/cigarettes/AltClick(mob/living/carbon/user)
if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
@@ -307,6 +325,7 @@
w_class = WEIGHT_CLASS_NORMAL
icon_type = "premium cigar"
spawn_type = /obj/item/clothing/mask/cigarette/cigar
+ spawn_coupon = FALSE
/obj/item/storage/fancy/cigarettes/cigars/ComponentInitialize()
. = ..()
diff --git a/code/game/objects/items/storage/lockbox.dm b/code/game/objects/items/storage/lockbox.dm
index 5b6089d430..ce4e8b9df1 100644
--- a/code/game/objects/items/storage/lockbox.dm
+++ b/code/game/objects/items/storage/lockbox.dm
@@ -188,19 +188,52 @@
new /obj/item/clothing/accessory/medal/plasma/nobel_science(src)
/obj/item/storage/lockbox/medal/engineering
- name = "engineering medal box"
- desc = "A locked box used to store medals to be given to the members of the engineering department."
- req_access = list(ACCESS_CE)
+ name = "engineering medal box"
+ desc = "A locked box used to store medals to be given to the members of the engineering department."
+ req_access = list(ACCESS_CE)
/obj/item/storage/lockbox/medal/engineering/PopulateContents()
- for(var/i in 1 to 3)
- new /obj/item/clothing/accessory/medal/engineer(src)
+ for(var/i in 1 to 3)
+ new /obj/item/clothing/accessory/medal/engineer(src)
/obj/item/storage/lockbox/medal/medical
- name = "medical medal box"
- desc = "A locked box used to store medals to be given to the members of the medical department."
- req_access = list(ACCESS_CMO)
+ name = "medical medal box"
+ desc = "A locked box used to store medals to be given to the members of the medical department."
+ req_access = list(ACCESS_CMO)
/obj/item/storage/lockbox/medal/medical/PopulateContents()
- for(var/i in 1 to 3)
- new /obj/item/clothing/accessory/medal/ribbon/medical_doctor(src)
\ No newline at end of file
+ for(var/i in 1 to 3)
+ new /obj/item/clothing/accessory/medal/ribbon/medical_doctor(src)
+
+/obj/item/storage/lockbox/order
+ name = "order lockbox"
+ desc = "A box used to secure small cargo orders from being looted by those who didn't order it. Yeah, cargo tech, that means you."
+ icon = 'icons/obj/storage.dmi'
+ icon_state = "secure"
+ item_state = "sec-case"
+ lefthand_file = 'icons/mob/inhands/equipment/briefcase_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/briefcase_righthand.dmi'
+ w_class = WEIGHT_CLASS_HUGE
+ var/datum/bank_account/buyer_account
+ var/privacy_lock = TRUE
+
+/obj/item/storage/lockbox/order/Initialize(datum/bank_account/_buyer_account)
+ . = ..()
+ buyer_account = _buyer_account
+
+/obj/item/storage/lockbox/order/attackby(obj/item/W, mob/user, params)
+ if(!istype(W, /obj/item/card/id))
+ return ..()
+
+ var/obj/item/card/id/id_card = W
+ if(iscarbon(user))
+ add_fingerprint(user)
+
+ if(id_card.registered_account != buyer_account)
+ to_chat(user, "Bank account does not match with buyer![user] [privacy_lock ? "" : "un"]locks [src]'s privacy lock.",
+ "You [privacy_lock ? "" : "un"]lock [src]'s privacy lock.")
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm b/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm
index 57520f6f40..0c314d988c 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm
@@ -6,8 +6,16 @@
max_integrity = 250
armor = list("melee" = 30, "bullet" = 50, "laser" = 50, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 80)
secure = TRUE
+ var/melee_min_damage = 20
/obj/structure/closet/secure_closet/run_obj_armor(damage_amount, damage_type, damage_flag = 0, attack_dir)
- if(damage_flag == "melee" && damage_amount < 20)
+ if(damage_flag == "melee" && damage_amount < melee_min_damage)
return 0
- . = ..()
\ No newline at end of file
+ . = ..()
+
+// Exists to work around the minimum 700 cr price for goodies / small items
+/obj/structure/closet/secure_closet/goodies
+ icon_state = "goodies"
+ desc = "A sturdier card-locked storage unit used for bulky shipments."
+ max_integrity = 500 // Same as crates.
+ melee_min_damage = 25 // Idem.
diff --git a/code/modules/cargo/console.dm b/code/modules/cargo/console.dm
index 6968a5ccd8..d010cee761 100644
--- a/code/modules/cargo/console.dm
+++ b/code/modules/cargo/console.dm
@@ -18,6 +18,7 @@
var/obj/item/radio/headset/radio
/// var that tracks message cooldown
var/message_cooldown
+ var/list/loaded_coupons
light_color = "#E2853D"//orange
@@ -134,6 +135,8 @@
"cost" = P.cost,
"id" = pack,
"desc" = P.desc || P.name, // If there is a description, use it. Otherwise use the pack's name.
+ "private_goody" = P.goody == PACK_GOODY_PRIVATE,
+ "goody" = P.goody == PACK_GOODY_PUBLIC,
"access" = P.access,
"can_private_buy" = P.can_private_buy
))
@@ -215,8 +218,22 @@
if(isnull(reason) || ..())
return
+ if(pack.goody == PACK_GOODY_PRIVATE && !self_paid)
+ playsound(src, 'sound/machines/buzz-sigh.ogg', 50, FALSE)
+ say("ERROR: Private small crates may only be purchased by private accounts.")
+ return
+
+ var/obj/item/coupon/applied_coupon
+ for(var/i in loaded_coupons)
+ var/obj/item/coupon/coupon_check = i
+ if(pack.type == coupon_check.discounted_pack)
+ say("Coupon found! [round(coupon_check.discount_pct_off * 100)]% off applied!")
+ coupon_check.moveToNullspace()
+ applied_coupon = coupon_check
+ break
+
var/turf/T = get_turf(src)
- var/datum/supply_order/SO = new(pack, name, rank, ckey, reason, account)
+ var/datum/supply_order/SO = new(pack, name, rank, ckey, reason, account, applied_coupon)
SO.generateRequisition(T)
if(requestonly && !self_paid)
SSshuttle.requestlist += SO
@@ -229,6 +246,9 @@
var/id = text2num(params["id"])
for(var/datum/supply_order/SO in SSshuttle.shoppinglist)
if(SO.id == id)
+ if(SO.applied_coupon)
+ say("Coupon refunded.")
+ SO.applied_coupon.forceMove(get_turf(src))
SSshuttle.shoppinglist -= SO
. = TRUE
break
diff --git a/code/modules/cargo/coupon.dm b/code/modules/cargo/coupon.dm
new file mode 100644
index 0000000000..6feeb28646
--- /dev/null
+++ b/code/modules/cargo/coupon.dm
@@ -0,0 +1,50 @@
+
+#define COUPON_OMEN "omen"
+
+obj/item/coupon
+ name = "coupon"
+ desc = "It doesn't matter if you didn't want it before, what matters now is that you've got a coupon for it!"
+ icon_state = "data_1"
+ icon = 'icons/obj/card.dmi'
+ item_flags = NOBLUDGEON
+ w_class = WEIGHT_CLASS_TINY
+ var/datum/supply_pack/discounted_pack
+ var/discount_pct_off = 0.05
+ var/obj/machinery/computer/cargo/inserted_console
+
+/// Choose what our prize is :D
+/obj/item/coupon/proc/generate()
+ discounted_pack = pick(subtypesof(/datum/supply_pack/goody))
+ var/list/chances = list("0.10" = 4, "0.15" = 8, "0.20" = 10, "0.25" = 8, "0.50" = 4, COUPON_OMEN = 1)
+ discount_pct_off = pickweight(chances)
+ if(discount_pct_off == COUPON_OMEN)
+ name = "coupon - fuck you"
+ desc = "The small text reads, 'You will be slaughtered'... That doesn't sound right, does it?"
+ if(ismob(loc))
+ var/mob/M = loc
+ to_chat(M, "The coupon reads 'fuck you' in large, bold text... is- is that a prize, or?")
+ M.AddComponent(/datum/component/omen, TRUE, src)
+ else
+ discount_pct_off = text2num(discount_pct_off)
+ name = "coupon - [round(discount_pct_off * 100)]% off [initial(discounted_pack.name)]"
+
+/obj/item/coupon/attack_obj(obj/O, mob/living/user)
+ if(!istype(O, /obj/machinery/computer/cargo))
+ return ..()
+ if(discount_pct_off == COUPON_OMEN)
+ to_chat(user, "\The [O] validates the coupon as authentic, but refuses to accept it...")
+ O.say("Coupon fulfillment already in progress...")
+ return
+
+ inserted_console = O
+ LAZYADD(inserted_console.loaded_coupons, src)
+ inserted_console.say("Coupon for [initial(discounted_pack.name)] applied!")
+ forceMove(inserted_console)
+
+/obj/item/coupon/Destroy()
+ if(inserted_console)
+ LAZYREMOVE(inserted_console.loaded_coupons, src)
+ inserted_console = null
+ . = ..()
+
+#undef COUPON_OMEN
diff --git a/code/modules/cargo/order.dm b/code/modules/cargo/order.dm
index 3d1caf6ba6..34986b1f05 100644
--- a/code/modules/cargo/order.dm
+++ b/code/modules/cargo/order.dm
@@ -27,10 +27,12 @@
var/orderer_rank
var/orderer_ckey
var/reason
+ var/discounted_pct
var/datum/supply_pack/pack
var/datum/bank_account/paying_account
+ var/obj/item/coupon/applied_coupon
-/datum/supply_order/New(datum/supply_pack/pack, orderer, orderer_rank, orderer_ckey, reason, paying_account)
+/datum/supply_order/New(datum/supply_pack/pack, orderer, orderer_rank, orderer_ckey, reason, paying_account, coupon)
id = SSshuttle.ordernum++
src.pack = pack
src.orderer = orderer
@@ -38,6 +40,7 @@
src.orderer_ckey = orderer_ckey
src.reason = reason
src.paying_account = paying_account
+ src.applied_coupon = coupon
/datum/supply_order/proc/generateRequisition(turf/T)
var/obj/item/paper/P = new(T)
@@ -57,58 +60,64 @@
P.update_icon()
return P
-/datum/supply_order/proc/generateManifest(obj/structure/closet/crate/C)
- var/obj/item/paper/fluff/jobs/cargo/manifest/P = new(C, id, pack.cost)
+/datum/supply_order/proc/generateManifest(obj/container, owner, packname) //generates-the-manifests.
+ var/obj/item/paper/fluff/jobs/cargo/manifest/P = new(container, id, 0)
var/station_name = (P.errors & MANIFEST_ERROR_NAME) ? new_station_name() : station_name()
- P.name = "shipping manifest - #[id] ([pack.name])"
+ P.name = "shipping manifest - [packname?"#[id] ([pack.name])":"(Grouped Item Crate)"]"
P.info += "
[command_name()] Shipping Manifest
"
P.info += "
"
- if(paying_account)
- P.info += "Direct purchase from [paying_account.account_holder]
"
- P.name += " - Purchased by [paying_account.account_holder]"
+ if(id && !(id == "Cargo"))
+ P.info += "Direct purchase from [owner]
"
+ P.name += " - Purchased by [owner]"
P.info += "Order #[id]
"
P.info += "Destination: [station_name]
"
- P.info += "Item: [pack.name]
"
+ if(packname)
+ P.info += "Item: [packname]
"
P.info += "Contents:
"
P.info += ""
- for(var/atom/movable/AM in C.contents - P - C.lockerelectronics)
+ var/list/ignore_this = list(P)
+ if(istype(container, /obj/structure/closet))
+ var/obj/structure/closet/C = container
+ ignore_this += C.lockerelectronics
+ for(var/atom/movable/AM in container.contents - ignore_this)
if((P.errors & MANIFEST_ERROR_CONTENTS) && prob(50))
continue
P.info += "- [AM.name]
"
P.info += "
"
P.info += "Stamp below to confirm receipt of goods:
"
+ if(P.errors & MANIFEST_ERROR_ITEM)
+ var/static/list/blacklisted_error = typecacheof(list(
+ /obj/structure/closet/crate/secure,
+ /obj/structure/closet/crate/large,
+ /obj/structure/closet/secure_closet/goodies
+ ))
+ if(blacklisted_error[container.type])
+ P.errors &= ~MANIFEST_ERROR_ITEM
+ else
+ var/lost = max(round(container.contents.len / 10), 1)
+ while(--lost >= 0)
+ qdel(pick(container.contents))
+
P.update_icon()
- P.forceMove(C)
- C.manifest = P
- C.update_icon()
+ P.forceMove(container)
+
+ if(istype(container, /obj/structure/closet/crate))
+ var/obj/structure/closet/crate/C = container
+ C.manifest = P
+ C.update_icon()
return P
/datum/supply_order/proc/generate(atom/A)
var/obj/structure/closet/crate/C = pack.generate(A, paying_account)
- var/obj/item/paper/fluff/jobs/cargo/manifest/M = generateManifest(C)
-
- if(M.errors & MANIFEST_ERROR_ITEM)
- if(istype(C, /obj/structure/closet/crate/secure) || istype(C, /obj/structure/closet/crate/large))
- M.errors &= ~MANIFEST_ERROR_ITEM
- else
- var/lost = max(round(C.contents.len / 10), 1)
- while(--lost >= 0)
- qdel(pick(C.contents))
+ generateManifest(C, paying_account, pack)
return C
-//Paperwork for NT
-/obj/item/folder/paperwork
- name = "Incomplete Paperwork"
- desc = "These should've been filled out four months ago! Unfinished grant papers issued by Nanotrasen's finance department. Complete this page for additional funding."
- icon = 'icons/obj/bureaucracy.dmi'
- icon_state = "docs_generic"
-
-/obj/item/folder/paperwork_correct
- name = "Finished Paperwork"
- desc = "A neat stack of filled-out forms, in triplicate and signed. Is there anything more satisfying? Make sure they get stamped."
- icon = 'icons/obj/bureaucracy.dmi'
- icon_state = "docs_verified"
+/datum/supply_order/proc/generateCombo(var/miscbox, var/misc_own, var/misc_contents)
+ for (var/I in misc_contents)
+ new I(miscbox)
+ generateManifest(miscbox, misc_own, "")
+ return
diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm
index f82e16ad5c..7ec3a775a5 100644
--- a/code/modules/cargo/packs.dm
+++ b/code/modules/cargo/packs.dm
@@ -15,6 +15,7 @@
var/special_enabled = FALSE
var/DropPodOnly = FALSE //only usable by the Bluespace Drop Pod via the express cargo console
var/admin_spawned = FALSE //Can only an admin spawn this crate?
+ var/goody = PACK_GOODY_NONE //Small items can be grouped into a single crate.They also come in a closet/lockbox instead of a full crate, so the 700 min doesn't apply
var/can_private_buy = TRUE //Can it be purchased privately by each crewmember?
/datum/supply_pack/proc/generate(atom/A, datum/bank_account/paying_account)
diff --git a/code/modules/cargo/packs/armory.dm b/code/modules/cargo/packs/armory.dm
index 3a3357cc42..835457536f 100644
--- a/code/modules/cargo/packs/armory.dm
+++ b/code/modules/cargo/packs/armory.dm
@@ -37,15 +37,6 @@
contains = list(/obj/item/storage/box/chemimp)
crate_name = "chemical implant crate"
-/datum/supply_pack/security/armory/combatknives
- name = "Combat Knives Crate"
- desc = "Contains three sharpened combat knives. Each knife guaranteed to fit snugly inside any Nanotrasen-standard boot. Requires Armory access to open."
- cost = 3200
- contains = list(/obj/item/kitchen/knife/combat,
- /obj/item/kitchen/knife/combat,
- /obj/item/kitchen/knife/combat)
- crate_name = "combat knife crate"
-
/datum/supply_pack/security/armory/ballistic
name = "Combat Shotguns Crate"
desc = "For when the enemy absolutely needs to be replaced with lead. Contains three Aussec-designed Combat Shotguns, with three Shotgun Bandoliers, as well as seven buchshot and 12g shotgun slugs. Requires Armory access to open."
diff --git a/code/modules/cargo/packs/engineering.dm b/code/modules/cargo/packs/engineering.dm
index 22258d19a7..9af18e13f6 100644
--- a/code/modules/cargo/packs/engineering.dm
+++ b/code/modules/cargo/packs/engineering.dm
@@ -90,16 +90,6 @@
crate_name = "industrial rcd"
crate_type = /obj/structure/closet/crate/secure/engineering
-/datum/supply_pack/engineering/powergamermitts
- name = "Insulated Gloves Crate"
- desc = "The backbone of modern society. Barely ever ordered for actual engineering. Contains three insulated gloves."
- cost = 2300 //Made of pure-grade bullshittinium
- contains = list(/obj/item/clothing/gloves/color/yellow,
- /obj/item/clothing/gloves/color/yellow,
- /obj/item/clothing/gloves/color/yellow)
- crate_name = "insulated gloves crate"
- crate_type = /obj/structure/closet/crate/engineering/electrical
-
/datum/supply_pack/engineering/inducers
name = "NT-75 Electromagnetic Power Inducers Crate"
desc = "No rechargers? No problem, with the NT-75 EPI, you can recharge any standard cell-based equipment anytime, anywhere. Contains two Inducers."
@@ -162,6 +152,7 @@
/obj/item/storage/toolbox/mechanical)
cost = 1200
crate_name = "toolbox crate"
+ special = TRUE //Department resupply shuttle loan event.
/datum/supply_pack/engineering/bsa
name = "Bluespace Artillery Parts"
diff --git a/code/modules/cargo/packs/goodies.dm b/code/modules/cargo/packs/goodies.dm
new file mode 100644
index 0000000000..ac8b1e9032
--- /dev/null
+++ b/code/modules/cargo/packs/goodies.dm
@@ -0,0 +1,77 @@
+
+/datum/supply_pack/goody
+ access = NONE
+ group = "Goodies"
+ goody = PACK_GOODY_PRIVATE
+
+/datum/supply_pack/goody/combatknives_single
+ name = "Combat Knife Single-Pack"
+ desc = "Contains one sharpened combat knive. Guaranteed to fit snugly inside any Nanotrasen-standard boot."
+ cost = 800
+ contains = list(/obj/item/kitchen/knife/combat)
+
+/datum/supply_pack/goody/sologamermitts
+ name = "Insulated Gloves Single-Pack"
+ desc = "The backbone of modern society. Barely ever ordered for actual engineering."
+ cost = 800
+ contains = list(/obj/item/clothing/gloves/color/yellow)
+
+/datum/supply_pack/goody/firstaidbruises_single
+ name = "Bruise Treatment Kit Single-Pack"
+ desc = "A single brute first-aid kit, perfect for recovering from being crushed in an airlock. Did you know people get crushed in airlocks all the time? Interesting..."
+ cost = 330
+ contains = list(/obj/item/storage/firstaid/brute)
+
+/datum/supply_pack/goody/firstaidburns_single
+ name = "Burn Treatment Kit Single-Pack"
+ desc = "A single burn first-aid kit. The advertisement displays a winking atmospheric technician giving a thumbs up, saying \"Mistakes happen!\""
+ cost = 330
+ contains = list(/obj/item/storage/firstaid/fire)
+
+/datum/supply_pack/goody/firstaid_single
+ name = "First Aid Kit Single-Pack"
+ desc = "A single first-aid kit, fit for healing most types of bodily harm."
+ cost = 250
+ contains = list(/obj/item/storage/firstaid/regular)
+
+/datum/supply_pack/goody/firstaidoxygen_single
+ name = "Oxygen Deprivation Kit Single-Pack"
+ desc = "A single oxygen deprivation first-aid kit, marketed heavily to those with crippling fears of asphyxiation."
+ cost = 330
+ contains = list(/obj/item/storage/firstaid/o2)
+
+/datum/supply_pack/goody/firstaidtoxins_single
+ name = "Toxin Treatment Kit Single-Pack"
+ desc = "A single first aid kit focused on healing damage dealt by heavy toxins."
+ cost = 330
+ contains = list(/obj/item/storage/firstaid/toxin)
+
+/datum/supply_pack/goody/toolbox // mostly just to water down coupon probability
+ name = "Mechanical Toolbox"
+ desc = "A fully stocked mechanical toolbox, for when you're too lazy to just print them out."
+ cost = 300
+ contains = list(/obj/item/storage/toolbox/mechanical)
+
+/datum/supply_pack/goody/electrical_toolbox // mostly just to water down coupon probability
+ name = "Mechanical Toolbox"
+ desc = "A fully stocked electrical toolbox, for when you're too lazy to just print them out."
+ cost = 300
+ contains = list(/obj/item/storage/toolbox/electrical)
+
+/datum/supply_pack/goody/valentine
+ name = "Valentine Card"
+ desc = "Make an impression on that special someone! Comes with one valentine card and a free candy heart!"
+ cost = 150
+ contains = list(/obj/item/valentine, /obj/item/reagent_containers/food/snacks/candyheart)
+
+/datum/supply_pack/goody/beeplush
+ name = "Bee Plushie"
+ desc = "The most important thing you could possibly spend your hard-earned money on."
+ cost = 1500
+ contains = list(/obj/item/toy/plush/beeplushie)
+
+/datum/supply_pack/goody/beach_ball
+ name = "Beach Ball"
+ desc = "The simple beach ball is one of Nanotrasen's most popular products. 'Why do we make beach balls? Because we can! (TM)' - Nanotrasen"
+ cost = 200
+ contains = list(/obj/item/toy/beach_ball)
diff --git a/code/modules/cargo/packs/materials.dm b/code/modules/cargo/packs/materials.dm
index 771f7ce222..0cf12fbc5d 100644
--- a/code/modules/cargo/packs/materials.dm
+++ b/code/modules/cargo/packs/materials.dm
@@ -14,53 +14,60 @@
//////////////////////////////////////////////////////////////////////////////
/datum/supply_pack/materials/cardboard50
+ goody = PACK_GOODY_PUBLIC
name = "50 Cardboard Sheets"
desc = "Create a bunch of boxes."
- cost = 1000
+ cost = 300 //thrice their export value
contains = list(/obj/item/stack/sheet/cardboard/fifty)
- crate_name = "cardboard sheets crate"
/datum/supply_pack/materials/glass50
+ goody = PACK_GOODY_PUBLIC
name = "50 Glass Sheets"
desc = "Let some nice light in with fifty glass sheets!"
- cost = 850
+ cost = 300 //double their export value
contains = list(/obj/item/stack/sheet/glass/fifty)
- crate_name = "glass sheets crate"
/datum/supply_pack/materials/metal50
+ goody = PACK_GOODY_PUBLIC
name = "50 Metal Sheets"
desc = "Any construction project begins with a good stack of fifty metal sheets!"
- cost = 850
+ cost = 300 //double their export value
contains = list(/obj/item/stack/sheet/metal/fifty)
- crate_name = "metal sheets crate"
/datum/supply_pack/materials/plasteel20
+ goody = PACK_GOODY_PUBLIC
name = "20 Plasteel Sheets"
desc = "Reinforce the station's integrity with twenty plasteel sheets!"
- cost = 4700
+ cost = 4000
contains = list(/obj/item/stack/sheet/plasteel/twenty)
- crate_name = "plasteel sheets crate"
-
-/datum/supply_pack/materials/plasteel50
- name = "50 Plasteel Sheets"
- desc = "For when you REALLY have to reinforce something."
- cost = 9050
- contains = list(/obj/item/stack/sheet/plasteel/fifty)
- crate_name = "plasteel sheets crate"
/datum/supply_pack/materials/plastic50
+ goody = PACK_GOODY_PUBLIC
name = "50 Plastic Sheets"
desc = "Build a limitless amount of toys with fifty plastic sheets!"
- cost = 950
- contains = list(/obj/item/stack/sheet/plastic/fifty)
- crate_name = "plastic sheets crate"
+ cost = 200 // double their export
+ contains = list(/obj/item/stack/sheet/plastic/twenty)
/datum/supply_pack/materials/sandstone30
+ goody = PACK_GOODY_PUBLIC
name = "30 Sandstone Blocks"
desc = "Neither sandy nor stoney, these thirty blocks will still get the job done."
- cost = 800
+ cost = 150 // five times their export
contains = list(/obj/item/stack/sheet/mineral/sandstone/thirty)
- crate_name = "sandstone blocks crate"
+
+/datum/supply_pack/materials/wood50
+ goody = PACK_GOODY_PUBLIC
+ name = "50 Wood Planks"
+ desc = "Turn cargo's boring metal groundwork into beautiful panelled flooring and much more with fifty wooden planks!"
+ cost = 400 // 6-7 planks shy from having equal import/export prices
+ contains = list(/obj/item/stack/sheet/mineral/wood/twenty)
+
+/datum/supply_pack/materials/rcdammo
+ goody = PACK_GOODY_PUBLIC
+ name = "Large RCD ammo Single-Pack"
+ desc = "A single large compressed RCD matter pack, to help with any holes or projects people might be working on."
+ cost = 600
+ contains = list(/obj/item/rcd_ammo/large)
/datum/supply_pack/materials/rawlumber
name = "50 Towercap Logs"
@@ -74,35 +81,6 @@
for(var/i in 1 to 49)
new /obj/item/grown/log(.)
-/datum/supply_pack/materials/wood50
- name = "50 Wood Planks"
- desc = "Turn cargo's boring metal groundwork into beautiful panelled flooring and much more with fifty wooden planks!"
- cost = 1450
- contains = list(/obj/item/stack/sheet/mineral/wood/fifty)
- crate_name = "wood planks crate"
-
-/datum/supply_pack/materials/rcdammo
- name = "Spare RCD ammo"
- desc = "This crate contains sixteen RCD compressed matter packs, to help with any holes or projects people might be working on."
- cost = 3750
- contains = list(/obj/item/rcd_ammo,
- /obj/item/rcd_ammo,
- /obj/item/rcd_ammo,
- /obj/item/rcd_ammo,
- /obj/item/rcd_ammo,
- /obj/item/rcd_ammo,
- /obj/item/rcd_ammo,
- /obj/item/rcd_ammo,
- /obj/item/rcd_ammo,
- /obj/item/rcd_ammo,
- /obj/item/rcd_ammo,
- /obj/item/rcd_ammo,
- /obj/item/rcd_ammo,
- /obj/item/rcd_ammo,
- /obj/item/rcd_ammo,
- /obj/item/rcd_ammo)
- crate_name = "rcd ammo"
-
//////////////////////////////////////////////////////////////////////////////
///////////////////////////// Canisters //////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
diff --git a/code/modules/cargo/packs/medical.dm b/code/modules/cargo/packs/medical.dm
index ab188f235b..2bb629308c 100644
--- a/code/modules/cargo/packs/medical.dm
+++ b/code/modules/cargo/packs/medical.dm
@@ -141,34 +141,6 @@
///////////////////////////// Medical Kits ///////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
-/datum/supply_pack/medical/firstaidbruises
- name = "Bruise Treatment Kit Crate"
- desc = "Contains three first aid kits focused on healing bruises and broken bones."
- cost = 1000
- contains = list(/obj/item/storage/firstaid/brute,
- /obj/item/storage/firstaid/brute,
- /obj/item/storage/firstaid/brute)
- crate_name = "brute treatment kit crate"
-
-/datum/supply_pack/medical/firstaidburns
- name = "Burn Treatment Kit Crate"
- desc = "Contains three first aid kits focused on healing severe burns."
- cost = 1000
- contains = list(/obj/item/storage/firstaid/fire,
- /obj/item/storage/firstaid/fire,
- /obj/item/storage/firstaid/fire)
- crate_name = "burn treatment kit crate"
-
-/datum/supply_pack/medical/firstaid
- name = "First Aid Kit Crate"
- desc = "Contains four first aid kits for healing most types of wounds."
- cost = 1000
- contains = list(/obj/item/storage/firstaid/regular,
- /obj/item/storage/firstaid/regular,
- /obj/item/storage/firstaid/regular,
- /obj/item/storage/firstaid/regular)
- crate_name = "first aid kit crate"
-
/datum/supply_pack/medical/sprays
name = "Medical Sprays"
desc = "Contains two cans of Styptic Spray, Silver Sulfadiazine Spray, Synthflesh Spray and Sterilizer Compound Spray."
@@ -183,35 +155,6 @@
/obj/item/reagent_containers/medspray/sterilizine)
crate_name = "medical supplies crate"
-/datum/supply_pack/medical/firstaidmixed
- name = "Mixed Medical Kits"
- desc = "Contains one of each medical kits for dealing with a variety of injured crewmembers."
- cost = 1250
- contains = list(/obj/item/storage/firstaid/toxin,
- /obj/item/storage/firstaid/o2,
- /obj/item/storage/firstaid/brute,
- /obj/item/storage/firstaid/fire,
- /obj/item/storage/firstaid/regular)
- crate_name = "medical supplies crate"
-
-/datum/supply_pack/medical/firstaidoxygen
- name = "Oxygen Deprivation Kit Crate"
- desc = "Contains three first aid kits focused on helping oxygen deprivation victims."
- cost = 1000
- contains = list(/obj/item/storage/firstaid/o2,
- /obj/item/storage/firstaid/o2,
- /obj/item/storage/firstaid/o2)
- crate_name = "oxygen deprivation kit crate"
-
-/datum/supply_pack/medical/firstaidtoxins
- name = "Toxin Treatment Kit Crate"
- desc = "Contains three first aid kits focused on healing damage dealt by heavy toxins."
- cost = 1000
- contains = list(/obj/item/storage/firstaid/toxin,
- /obj/item/storage/firstaid/toxin,
- /obj/item/storage/firstaid/toxin)
- crate_name = "toxin treatment kit crate"
-
/datum/supply_pack/medical/advrad
name = "Radiation Treatment Crate Deluxe"
desc = "A crate for when radiation is out of hand... Contains two rad-b-gone kits, one bottle of anti radiation deluxe pills, as well as a radiation treatment deluxe pill bottle!"
diff --git a/code/modules/cargo/packs/misc.dm b/code/modules/cargo/packs/misc.dm
index 5265b2c2f6..414595e206 100644
--- a/code/modules/cargo/packs/misc.dm
+++ b/code/modules/cargo/packs/misc.dm
@@ -333,45 +333,58 @@
//////////////////////////// Misc + Decor ////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
-/datum/supply_pack/misc/carpet_exotic
- name = "Exotic Carpet Crate"
- desc = "Exotic carpets straight from Space Russia, for all your decorating needs. Contains 100 tiles each of 10 different flooring patterns."
- cost = 7000
- contains = list(/obj/item/stack/tile/carpet/blue/fifty,
- /obj/item/stack/tile/carpet/blue/fifty,
- /obj/item/stack/tile/carpet/cyan/fifty,
- /obj/item/stack/tile/carpet/cyan/fifty,
- /obj/item/stack/tile/carpet/green/fifty,
- /obj/item/stack/tile/carpet/green/fifty,
- /obj/item/stack/tile/carpet/orange/fifty,
- /obj/item/stack/tile/carpet/orange/fifty,
- /obj/item/stack/tile/carpet/purple/fifty,
- /obj/item/stack/tile/carpet/purple/fifty,
- /obj/item/stack/tile/carpet/red/fifty,
- /obj/item/stack/tile/carpet/red/fifty,
- /obj/item/stack/tile/carpet/royalblue/fifty,
- /obj/item/stack/tile/carpet/royalblue/fifty,
- /obj/item/stack/tile/carpet/royalblack/fifty,
- /obj/item/stack/tile/carpet/royalblack/fifty,
- /obj/item/stack/tile/carpet/blackred/fifty,
- /obj/item/stack/tile/carpet/blackred/fifty,
- /obj/item/stack/tile/carpet/monochrome/fifty,
- /obj/item/stack/tile/carpet/monochrome/fifty)
- crate_name = "exotic carpet crate"
-
/datum/supply_pack/misc/carpet
- name = "Premium Carpet Crate"
- desc = "Plasteel floor tiles getting on your nerves? These stacks of extra soft carpet will tie any room together. Contains some classic carpet, along with black, red, and monochrome varients."
- cost = 1350
- contains = list(/obj/item/stack/tile/carpet/fifty,
- /obj/item/stack/tile/carpet/fifty,
- /obj/item/stack/tile/carpet/black/fifty,
- /obj/item/stack/tile/carpet/black/fifty,
- /obj/item/stack/tile/carpet/blackred/fifty,
- /obj/item/stack/tile/carpet/blackred/fifty,
- /obj/item/stack/tile/carpet/monochrome/fifty,
- /obj/item/stack/tile/carpet/monochrome/fifty)
- crate_name = "premium carpet crate"
+ goody = PACK_GOODY_PUBLIC
+ name = "Classic Carpet Single-Pack"
+ desc = "Plasteel floor tiles getting on your nerves? This 50 units stack of extra soft carpet will tie any room together."
+ cost = 200
+ contains = list(/obj/item/stack/tile/carpet/fifty)
+
+/datum/supply_pack/misc/carpet/black
+ name = "Black Carpet Single-Pack"
+ contains = list(/obj/item/stack/tile/carpet/black/fifty)
+
+/datum/supply_pack/misc/carpet/premium
+ name = "Monochrome Carpet Single-Pack"
+ desc = "Exotic carpets for all your decorating needs. This 30 units stack of extra soft carpet will tie any room together."
+ cost = 250
+ contains = list(/obj/item/stack/tile/carpet/monochrome/thirty)
+
+/datum/supply_pack/misc/carpet/premium/blackred
+ name = "Black-Red Carpet Single-Pack"
+ contains = list(/obj/item/stack/tile/carpet/blackred/thirty)
+
+/datum/supply_pack/misc/carpet/premium/royalblack
+ name = "Royal Black Carpet Single-Pack"
+ contains = list(/obj/item/stack/tile/carpet/royalblack/thirty)
+
+/datum/supply_pack/misc/carpet/premium/royalblue
+ name = "Royal Blue Carpet Single-Pack"
+ contains = list(/obj/item/stack/tile/carpet/royalblue/thirty)
+
+/datum/supply_pack/misc/carpet/premium/red
+ name = "Red Carpet Single-Pack"
+ contains = list(/obj/item/stack/tile/carpet/red/thirty)
+
+/datum/supply_pack/misc/carpet/premium/purple
+ name = "Purple Carpet Single-Pack"
+ contains = list(/obj/item/stack/tile/carpet/purple/thirty)
+
+/datum/supply_pack/misc/carpet/premium/orange
+ name = "Orange Carpet Single-Pack"
+ contains = list(/obj/item/stack/tile/carpet/orange/thirty)
+
+/datum/supply_pack/misc/carpet/premium/green
+ name = "Green Carpet Single-Pack"
+ contains = list(/obj/item/stack/tile/carpet/green/thirty)
+
+/datum/supply_pack/misc/carpet/premium/cyan
+ name = "Cyan Carpet Single-Pack"
+ contains = list(/obj/item/stack/tile/carpet/cyan/thirty)
+
+/datum/supply_pack/misc/carpet/premium/blue
+ name = "Blue Carpet Single-Pack"
+ contains = list(/obj/item/stack/tile/carpet/blue/thirty)
/datum/supply_pack/misc/noslipfloor
name = "High-traction Floor Tiles"
diff --git a/code/modules/power/power.dm b/code/modules/power/power.dm
index f84b639d68..d5b19b495c 100644
--- a/code/modules/power/power.dm
+++ b/code/modules/power/power.dm
@@ -299,8 +299,8 @@
//siemens_coeff - layman's terms, conductivity
//dist_check - set to only shock mobs within 1 of source (vendors, airlocks, etc.)
//No animations will be performed by this proc.
-/proc/electrocute_mob(mob/living/carbon/M, power_source, obj/source, siemens_coeff = 1, dist_check = FALSE)
- if(!M || ismecha(M.loc))
+/proc/electrocute_mob(mob/living/M, power_source, obj/source, siemens_coeff = 1, dist_check = FALSE)
+ if(!istype(M) || ismecha(M.loc))
return 0 //feckin mechs are dumb
if(dist_check)
if(!in_range(source,M))
diff --git a/code/modules/shuttle/supply.dm b/code/modules/shuttle/supply.dm
index a4ef2dfde9..36ba19d2a2 100644
--- a/code/modules/shuttle/supply.dm
+++ b/code/modules/shuttle/supply.dm
@@ -101,6 +101,10 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list(
if(!SSshuttle.shoppinglist.len)
return
+ var/list/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
+
var/list/empty_turfs = list()
for(var/place in shuttle_areas)
var/area/shuttle/shuttle_area = place
@@ -117,10 +121,13 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list(
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
- price *= 1.1 //TODO make this customizable by the quartermaster
+ if(!SO.pack.goody)
+ price *= 1.1 //TODO make this customizable by the quartermaster
else
D = cargo_budget
if(D)
@@ -136,14 +143,46 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list(
value += SO.pack.cost
SSshuttle.shoppinglist -= SO
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
+ SO.generate(pick_n_take(empty_turfs))
- SO.generate(pick_n_take(empty_turfs))
SSblackbox.record_feedback("nested tally", "cargo_imports", 1, list("[SO.pack.cost]", "[SO.pack.name]"))
investigate_log("Order #[SO.id] ([SO.pack.name], placed by [key_name(SO.orderer_ckey)]), paid by [D.account_holder] has shipped.", INVESTIGATE_CARGO)
if(SO.pack.dangerous)
message_admins("\A [SO.pack.name] ordered by [ADMIN_LOOKUPFLW(SO.orderer_ckey)], paid by [D.account_holder] has shipped.")
purchases++
+ 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)
+
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()
diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm
index 6e6636cd62..62bdf347da 100644
--- a/code/modules/vending/_vending.dm
+++ b/code/modules/vending/_vending.dm
@@ -105,6 +105,12 @@ IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY C
///Last world tick we sent a slogan message out
var/last_slogan
var/last_shopper
+ var/tilted = FALSE
+ var/tiltable = TRUE
+ var/squish_damage = 75
+ var/forcecrit = 0
+ var/num_shards = 7
+ var/list/pinned_mobs = list()
///How many ticks until we can send another
var/slogan_delay = 6000
///Icon when vending an item to the user
@@ -372,6 +378,7 @@ GLOBAL_LIST_EMPTY(vending_products)
..()
if(panel_open)
default_unfasten_wrench(user, I, time = 60)
+ unbuckle_all_mobs(TRUE)
return TRUE
/obj/machinery/vending/screwdriver_act(mob/living/user, obj/item/I)
@@ -435,6 +442,131 @@ GLOBAL_LIST_EMPTY(vending_products)
updateUsrDialog()
else
. = ..()
+ if(tiltable && !tilted && I.force)
+ switch(rand(1, 100))
+ if(1 to 5)
+ freebie(user, 3)
+ if(6 to 15)
+ freebie(user, 2)
+ if(16 to 25)
+ freebie(user, 1)
+ if(76 to 90)
+ tilt(user)
+ if(91 to 100)
+ tilt(user, crit=TRUE)
+
+/obj/machinery/vending/proc/freebie(mob/fatty, freebies)
+ visible_message("[src] yields [freebies > 1 ? "several free goodies" : "a free goody"]!")
+
+ for(var/i in 1 to freebies)
+ playsound(src, 'sound/machines/machine_vend.ogg', 50, TRUE, extrarange = -3)
+ for(var/datum/data/vending_product/R in shuffle(product_records))
+
+ if(R.amount <= 0) //Try to use a record that actually has something to dump.
+ continue
+ var/dump_path = R.product_path
+ if(!dump_path)
+ continue
+
+ R.amount--
+ new dump_path(get_turf(src))
+ break
+
+/obj/machinery/vending/proc/tilt(mob/fatty, crit=FALSE)
+ visible_message("[src] tips over!")
+ tilted = TRUE
+ layer = ABOVE_MOB_LAYER
+
+ var/crit_case
+ if(crit)
+ crit_case = rand(1,5)
+
+ if(forcecrit)
+ crit_case = forcecrit
+
+ if(in_range(fatty, src))
+ for(var/mob/living/L in get_turf(fatty))
+ var/mob/living/carbon/C = L
+
+ if(istype(C))
+ var/crit_rebate = 0 // lessen the normal damage we deal for some of the crits
+
+ if(crit_case != 5) // the head asplode case has its own description
+ C.visible_message("[C] is crushed by [src]!", \
+ "You are crushed by [src]!")
+
+ switch(crit_case) // only carbons can have the fun crits
+ if(1) // shatter their legs and bleed 'em
+ crit_rebate = 60
+ C.bleed(150)
+ var/obj/item/bodypart/l_leg/l = C.get_bodypart(BODY_ZONE_L_LEG)
+ if(l)
+ l.receive_damage(brute=200, updating_health=TRUE)
+ var/obj/item/bodypart/r_leg/r = C.get_bodypart(BODY_ZONE_R_LEG)
+ if(r)
+ r.receive_damage(brute=200, updating_health=TRUE)
+ if(l || r)
+ C.visible_message("[C]'s legs shatter with a sickening crunch!", \
+ "Your legs shatter with a sickening crunch!")
+ if(2) // pin them beneath the machine until someone untilts it
+ forceMove(get_turf(C))
+ buckle_mob(C, force=TRUE)
+ C.visible_message("[C] is pinned underneath [src]!", \
+ "You are pinned down by [src]!")
+ if(3) // glass candy
+ crit_rebate = 50
+ for(var/i = 0, i < num_shards, i++)
+ var/obj/item/shard/shard = new /obj/item/shard(get_turf(C))
+ shard.embedding = shard.embedding.setRating(embed_chance = 100, embedded_ignore_throwspeed_threshold = TRUE, embedded_impact_pain_multiplier=1,embedded_pain_chance=5)
+ C.hitby(shard, skipcatch = TRUE, hitpush = FALSE)
+ shard.embedding = shard.embedding.setRating(embed_chance = EMBED_CHANCE, embedded_ignore_throwspeed_threshold = FALSE)
+ if(4) // paralyze this binch
+ // the new paraplegic gets like 4 lines of losing their legs so skip them
+ visible_message("[C]'s spinal cord is obliterated with a sickening crunch!", ignored_mobs = list(C))
+ C.gain_trauma(/datum/brain_trauma/severe/paralysis/paraplegic)
+ if(5) // skull squish!
+ var/obj/item/bodypart/head/O = C.get_bodypart(BODY_ZONE_HEAD)
+ if(O)
+ C.visible_message("[O] explodes in a shower of gore beneath [src]!", \
+ "Oh f-")
+ O.dismember()
+ O.drop_organs()
+ qdel(O)
+ new /obj/effect/gibspawner/human/bodypartless(get_turf(C))
+
+ C.apply_damage(max(0, squish_damage - crit_rebate), forced=TRUE, spread_damage=TRUE)
+ C.AddElement(/datum/element/squish, 18 SECONDS)
+ else
+ L.visible_message("[L] is crushed by [src]!", \
+ "You are crushed by [src]!")
+ L.apply_damage(squish_damage, forced=TRUE)
+ if(crit_case)
+ L.apply_damage(squish_damage, forced=TRUE)
+
+ L.Paralyze(60)
+ L.emote("scream")
+ playsound(L, 'sound/effects/blobattack.ogg', 40, TRUE)
+ playsound(L, 'sound/effects/splat.ogg', 50, TRUE)
+
+ var/matrix/M = matrix()
+ M.Turn(pick(90, 270))
+ transform = M
+
+ if(get_turf(fatty) != get_turf(src))
+ throw_at(get_turf(fatty), 1, 1, spin=FALSE)
+
+/obj/machinery/vending/proc/untilt(mob/user)
+ user.visible_message("[user] rights [src].", \
+ "You right [src].")
+
+ unbuckle_all_mobs(TRUE)
+
+ tilted = FALSE
+ layer = initial(layer)
+
+ var/matrix/M = matrix()
+ M.Turn(0)
+ transform = M
/obj/machinery/vending/proc/loadingAttempt(obj/item/I, mob/user)
. = TRUE
@@ -447,6 +579,12 @@ GLOBAL_LIST_EMPTY(vending_products)
to_chat(user, "You insert [I] into [src]'s input compartment.")
loaded_items++
+
+/obj/machinery/vending/unbuckle_mob(mob/living/buckled_mob, force=FALSE)
+ if(!force)
+ return
+ . = ..()
+
/**
* Is the passed in user allowed to load this vending machines compartments
*
@@ -511,12 +649,13 @@ GLOBAL_LIST_EMPTY(vending_products)
if(seconds_electrified && !(stat & NOPOWER))
if(shock(user, 100))
return
+ if(tilted && !user.buckled && !isAI(user))
+ to_chat(user, "You begin righting [src].")
+ if(do_after(user, 50, target=src))
+ untilt(user)
+ return
return ..()
-/obj/machinery/vending/ui_base_html(html)
- var/datum/asset/spritesheet/assets = get_asset_datum(/datum/asset/spritesheet/vending)
- . = replacetext(html, "", assets.css_tag())
-
/obj/machinery/vending/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
@@ -922,7 +1061,7 @@ GLOBAL_LIST_EMPTY(vending_products)
C = H.get_idcard(TRUE)
if(C?.registered_account)
private_a = C.registered_account
- say("\The [src] has been linked to [C].")
+ say("[src] has been linked to [C].")
if(compartmentLoadAccessCheck(user))
if(istype(I, /obj/item/pen))
diff --git a/code/modules/vending/medical_wall.dm b/code/modules/vending/medical_wall.dm
index b51705c7e1..d952139407 100644
--- a/code/modules/vending/medical_wall.dm
+++ b/code/modules/vending/medical_wall.dm
@@ -22,6 +22,7 @@
extra_price = 100
payment_department = ACCOUNT_MED
cost_multiplier_per_dept = list(ACCOUNT_MED = 0)
+ tiltable = FALSE
/obj/item/vending_refill/wallmed
machine_name = "NanoMed"
diff --git a/icons/obj/closet.dmi b/icons/obj/closet.dmi
index d3f055d1f2e8148a08c9921c39623da9d7d28290..b71b021d80a50ab52c5be891fa2ac5022d2bf58b 100644
GIT binary patch
literal 39711
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