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