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