From 61aef2bd6f26e7f4b5f5012f8d5ef8853bdd3a85 Mon Sep 17 00:00:00 2001
From: Contrabang <91113370+Contrabang@users.noreply.github.com>
Date: Tue, 5 Sep 2023 18:36:47 -0400
Subject: [PATCH] [s] Fixes a exploit (#22255)
* god, what the fuck
* fuck
* just set it to 0 guck it
* fix
---
code/datums/uplink_items/uplink_traitor.dm | 49 +++++++++++++++++++++-
1 file changed, 48 insertions(+), 1 deletion(-)
diff --git a/code/datums/uplink_items/uplink_traitor.dm b/code/datums/uplink_items/uplink_traitor.dm
index 3c6a02fc79c..9ee2462721c 100644
--- a/code/datums/uplink_items/uplink_traitor.dm
+++ b/code/datums/uplink_items/uplink_traitor.dm
@@ -557,12 +557,20 @@
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()
@@ -570,17 +578,33 @@
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 || prob(100 - I.surplus))
+ 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)
@@ -588,6 +612,29 @@
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
+
// -----------------------------------
// PRICES OVERRIDEN FOR NUCLEAR AGENTS