diff --git a/code/datums/uplink_items/uplink_general.dm b/code/datums/uplink_items/uplink_general.dm
index 2a15591d7c8..16f098df0a5 100644
--- a/code/datums/uplink_items/uplink_general.dm
+++ b/code/datums/uplink_items/uplink_general.dm
@@ -1,4 +1,7 @@
GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
+// This define is used when we have to spawn in an uplink item in a weird way, like a Surplus crate spawning an actual crate.
+// Use this define by setting `uses_special_spawn` to TRUE on the item, and then checking if the parent proc of `spawn_item` returns this define. If it does, implement your special spawn after that.
+#define UPLINK_SPECIAL_SPAWNING "ONE PINK CHAINSAW PLEASE"
/proc/get_uplink_items(obj/item/uplink/U)
var/list/uplink_items = list()
@@ -83,6 +86,8 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
var/refundable = FALSE
var/refund_path = null // Alternative path for refunds, in case the item purchased isn't what is actually refunded (ie: holoparasites).
var/refund_amount // specified refund amount in case there needs to be a TC penalty for refunds.
+ /// Our special little snowflakes that have to be spawned in a different way than normal, like a surplus crate spawning a crate or contractor kits
+ var/uses_special_spawn = FALSE
/datum/uplink_item/proc/spawn_item(turf/loc, obj/item/uplink/U)
@@ -91,12 +96,13 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
to_chat(usr, "The Syndicate will only issue this extremely dangerous item to agents assigned the Hijack objective.")
return
- if(item)
- U.uses -= max(cost, 0)
- U.used_TC += cost
- SSblackbox.record_feedback("nested tally", "traitor_uplink_items_bought", 1, list("[initial(name)]", "[cost]"))
+ U.uses -= max(cost, 0)
+ U.used_TC += cost
+ SSblackbox.record_feedback("nested tally", "traitor_uplink_items_bought", 1, list("[initial(name)]", "[cost]"))
+ if(item && !uses_special_spawn)
return new item(loc)
+ return UPLINK_SPECIAL_SPAWNING
/datum/uplink_item/proc/description()
if(!desc)
diff --git a/code/datums/uplink_items/uplink_traitor.dm b/code/datums/uplink_items/uplink_traitor.dm
index c8db7820e1d..9f5e90ba7eb 100644
--- a/code/datums/uplink_items/uplink_traitor.dm
+++ b/code/datums/uplink_items/uplink_traitor.dm
@@ -575,6 +575,7 @@
item = /obj/item/storage/box/syndie_kit/bundle
excludefrom = list(UPLINK_TYPE_NUCLEAR, UPLINK_TYPE_SST)
var/crate_value = 250
+ uses_special_spawn = TRUE
/datum/uplink_item/bundles_TC/surplus_crate/super
name = "Syndicate Super Surplus Crate"
@@ -583,84 +584,11 @@
cost = 200
crate_value = 625
-#define RECURSION_PANIC_AMOUNT 10
-
/datum/uplink_item/bundles_TC/surplus_crate/spawn_item(turf/loc, obj/item/uplink/U)
- var/obj/structure/closet/crate/C = new(loc)
- var/list/temp_uplink_list = get_uplink_items(U)
- var/list/buyable_items = list()
- for(var/category in temp_uplink_list)
- buyable_items += temp_uplink_list[category]
-
- if(!length(buyable_items)) // UH OH.
- fucked_shit_up_alert(loc, "[src] spawning failed: had no buyable items on purchase which would have caused an infinite loop, refunding [cost] telecrystals instead. (Original cost of the crate). Report this to coders please.")
- generate_refund(cost, C)
- return
-
- var/remaining_TC = crate_value
- var/list/bought_items = list()
- var/list/itemlog = list()
- U.uses -= cost
- U.used_TC = cost
-
- var/datum/uplink_item/I
- var/danger_counter = 0 // lets make sure we dont get into an infinite loop...
- while(remaining_TC)
- if(danger_counter > RECURSION_PANIC_AMOUNT)
- fucked_shit_up_alert(loc, "[src] spawning failed: approached an infinite loop by cost checking, giving the remaining [remaining_TC] telecrystals instead.")
- generate_refund(remaining_TC, C)
- break
- if(!length(buyable_items))
- fucked_shit_up_alert(loc, "[src] spawning failed: ran out of buyable items while looping, refunding [cost] telecrystals and cancelling crate. (Original cost of the crate). Report this to coders please.")
- generate_refund(cost, C)
- bought_items.Cut()
- break
- I = pick(buyable_items)
- if(!I.surplus)
- buyable_items -= I
- continue
- if(I.cost > remaining_TC)
- danger_counter++
- buyable_items -= I
- continue
- if(prob(100 - I.surplus))
- continue
- if((I.item in bought_items) && prob(33)) //To prevent people from being flooded with the same thing over and over again.
- continue
- bought_items += I.item
- remaining_TC -= I.cost
- itemlog += I.name // To make the name more readable for the log compared to just i.item
- danger_counter = 0
-
- U.purchase_log += "[bicon(C)]"
- for(var/item in bought_items)
- var/obj/purchased = new item(C)
- U.purchase_log += "[bicon(purchased)]"
- log_game("[key_name(usr)] purchased a surplus crate with [jointext(itemlog, ", ")]")
-
-/datum/uplink_item/bundles_TC/surplus_crate/proc/generate_refund(amount, crate)
- var/changing_amount = amount
- var/obj/item/stack/telecrystal/TC
- var/prohibitor = 0
- while(changing_amount >= 1)
- var/give_amount = min(changing_amount, initial(TC.max_amount))
- changing_amount -= give_amount
- new /obj/item/stack/telecrystal(crate, give_amount)
- if(prohibitor > RECURSION_PANIC_AMOUNT) // idk how they got 1000+ tc, dont ask me
- new /obj/item/stack/telecrystal(crate, changing_amount)
- // Return of Bogdanoff: doomp it
- var/turf/T = get_turf(crate)
- message_admins("While refunding telecrystals, [src] went over the expected limit, for a total of [amount] TC. Expected refund is likely [cost]. [ADMIN_COORDJMP(T)]")
- break
- prohibitor++
-
-/datum/uplink_item/bundles_TC/surplus_crate/proc/fucked_shit_up_alert(turf/loc, msg) // yeah just fuckin tell everyone, this shit is bad
- stack_trace(msg)
- message_admins("[msg] [ADMIN_COORDJMP(loc)]")
- log_admin(msg)
-
-#undef RECURSION_PANIC_AMOUNT
+ if(..() != UPLINK_SPECIAL_SPAWNING)
+ return FALSE
+ new /obj/structure/closet/crate/surplus(loc, U, crate_value, cost)
// -----------------------------------
// PRICES OVERRIDEN FOR NUCLEAR AGENTS
diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm
index 6b6f51f1e17..b6d9fd0399f 100644
--- a/code/game/objects/structures/crates_lockers/crates.dm
+++ b/code/game/objects/structures/crates_lockers/crates.dm
@@ -543,3 +543,89 @@
new /obj/item/clothing/glasses/meson(src)
new /obj/item/card/id/golem(src)
new /obj/item/flashlight/lantern(src)
+
+#define RECURSION_PANIC_AMOUNT 10
+
+/obj/structure/closet/crate/surplus
+
+/obj/structure/closet/crate/surplus/Initialize(mapload, obj/item/uplink/U, crate_value, cost)
+ . = ..()
+ var/list/temp_uplink_list = get_uplink_items(U)
+ var/list/buyable_items = list()
+ for(var/category in temp_uplink_list)
+ buyable_items += temp_uplink_list[category]
+
+ for(var/datum/uplink_item/uplink_item in buyable_items)
+ if(!uplink_item.surplus) // Otherwise we'll just have an element with a weight of 0 in our weighted list
+ continue
+ buyable_items[uplink_item] = uplink_item.surplus
+
+ if(!length(buyable_items)) // UH OH - Will almost always happen when an admin will try to spawn a crate
+ fucked_shit_up_alert(loc, "[src] spawning failed: had no buyable items on purchase which would have caused an infinite loop, refunding [cost] telecrystals instead. (Original cost of the crate). Report this to coders please.")
+ generate_refund(cost, loc)
+ return
+
+ var/remaining_TC = crate_value
+ var/list/bought_items = list()
+ var/list/itemlog = list()
+
+ var/datum/uplink_item/uplink_item
+ var/danger_counter = 0 // lets make sure we dont get into an infinite loop...
+ while(remaining_TC)
+ if(danger_counter > RECURSION_PANIC_AMOUNT)
+ fucked_shit_up_alert(loc, "[src] spawning failed: approached an infinite loop by cost checking, giving the remaining [remaining_TC] telecrystals instead.")
+ generate_refund(remaining_TC, loc)
+ break
+
+ if(!length(buyable_items)) // UH OH V.2
+ fucked_shit_up_alert(loc, "[src] spawning failed: ran out of buyable items while looping, refunding [remaining_TC] telecrystals and cancelling crate. (Original cost of the crate). Report this to coders please.")
+ generate_refund(remaining_TC, loc)
+ bought_items.Cut()
+ break
+
+ uplink_item = pickweight(buyable_items)
+
+ if(uplink_item.cost > remaining_TC)
+ danger_counter++
+ buyable_items -= uplink_item
+ continue
+
+ bought_items += uplink_item.item
+ remaining_TC -= uplink_item.cost
+
+ buyable_items[uplink_item] *= 0.66 // To prevent people from getting the same thing over and over again
+
+ itemlog += uplink_item.name // To make the name more readable for the log compared to just uplink_item.item
+ danger_counter = 0
+
+ U.purchase_log += "[bicon(src)]"
+ for(var/item in bought_items)
+ var/obj/purchased = new item(src)
+ U.purchase_log += "[bicon(purchased)]"
+ log_game("[key_name(usr)] purchased a surplus crate with [jointext(itemlog, ", ")]")
+
+/obj/structure/closet/crate/surplus/proc/generate_refund(amount)
+ var/changing_amount = amount
+ var/prohibitor = 0
+ var/given_out_TC = 0
+ while(changing_amount >= 1)
+ var/obj/item/stack/telecrystal/TC = new /obj/item/stack/telecrystal(src)
+ var/give_amount = min(changing_amount, TC.max_amount)
+ TC.amount = give_amount
+ changing_amount -= give_amount
+ given_out_TC += give_amount
+ if(prohibitor > RECURSION_PANIC_AMOUNT) // idk how they got 1000+ tc, dont ask me
+ new /obj/item/stack/telecrystal(src, changing_amount)
+ // Return of Bogdanoff: doomp it
+ var/turf/T = get_turf(loc)
+ given_out_TC += changing_amount
+ message_admins("While refunding telecrystals, [src] went over the expected limit, for a total of [amount] TC. Expected refund is likely [given_out_TC]. [ADMIN_COORDJMP(T)]")
+ break
+ prohibitor++
+
+/obj/structure/closet/crate/surplus/proc/fucked_shit_up_alert(turf/loc, msg) // yeah just fuckin tell everyone, this shit is bad
+ stack_trace(msg)
+ message_admins("[msg] [ADMIN_COORDJMP(loc)]")
+ log_admin(msg)
+
+#undef RECURSION_PANIC_AMOUNT