diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm index 8c66bbe50ef..b24fdc145d2 100644 --- a/code/__DEFINES/antagonists.dm +++ b/code/__DEFINES/antagonists.dm @@ -249,6 +249,12 @@ GLOBAL_LIST_INIT(ai_employers, list( /// because they have nothing else that supports an implant. #define UPLINK_IMPLANT_TELECRYSTAL_COST 4 +/// Items with this stock key do not share stock with other items +#define UPLINK_SHARED_STOCK_UNIQUE "uplink_shared_stock_unique" +/// Stock keys for items that share inventory stock +#define UPLINK_SHARED_STOCK_KITS "uplink_shared_stock_kits" +#define UPLINK_SHARED_STOCK_SURPLUS "uplink_shared_stock_surplus" + // Used for traitor objectives /// If the objective hasn't been taken yet #define OBJECTIVE_STATE_INACTIVE 1 diff --git a/code/datums/components/uplink.dm b/code/datums/components/uplink.dm index 4fb916a497d..a2e6f17f81c 100644 --- a/code/datums/components/uplink.dm +++ b/code/datums/components/uplink.dm @@ -230,8 +230,8 @@ )) var/list/remaining_stock = list() - for(var/datum/uplink_item/item as anything in stock_list) - remaining_stock[item.type] = stock_list[item] + for(var/item as anything in stock_list) + remaining_stock[item] = stock_list[item] data["extra_purchasable"] = extra_purchasable data["extra_purchasable_stock"] = extra_purchasable_stock data["current_stock"] = remaining_stock diff --git a/code/game/objects/items/granters/magic/lightning_bolt.dm b/code/game/objects/items/granters/magic/lightning_bolt.dm new file mode 100644 index 00000000000..3e3cbade46f --- /dev/null +++ b/code/game/objects/items/granters/magic/lightning_bolt.dm @@ -0,0 +1,16 @@ +/obj/item/book/granter/action/spell/lightningbolt + granted_action = /datum/action/cooldown/spell/pointed/projectile/lightningbolt + action_name = "lightning bolt" + icon_state ="booklightning" + desc = "Become like lightning, the rain transformed." + remarks = list( + "I never quite liked insulated gloves...", + "Will this effect my haircut?", + "I wonder if I can use this to charge a MODsuit?", + "Ouch! That page had static...", + "Is cackling optional?", + "Just think like a tesla ball...", + "UNLIMITED power? Well... maybe if I practice...", + "Wait until they're grouped up...", + ) + diff --git a/code/game/objects/items/storage/uplink_kits.dm b/code/game/objects/items/storage/uplink_kits.dm index d95207b5795..7b13ad501c4 100644 --- a/code/game/objects/items/storage/uplink_kits.dm +++ b/code/game/objects/items/storage/uplink_kits.dm @@ -20,6 +20,7 @@ #define KIT_MR_FREEZE "mr_freeze" #define KIT_TRAITOR_2006 "ancient" +/// last audited december 2022 /obj/item/storage/box/syndicate /obj/item/storage/box/syndicate/bundle_a/PopulateContents() @@ -44,7 +45,7 @@ new /obj/item/storage/box/syndie_kit/space(src) //4 tc new /obj/item/grenade/frag(src) // ~2 tc each? new /obj/item/grenade/frag(src) - new /obj/item/flashlight/emp(src) + new /obj/item/flashlight/emp(src) // 4 tc if(KIT_BLOODY_SPAI) new /obj/item/card/id/advanced/chameleon(src) // 2 tc @@ -61,84 +62,86 @@ new /obj/item/chameleon(src) // 7 tc if(KIT_STEALTHY) - new /obj/item/gun/energy/recharge/ebow(src) - new /obj/item/pen/sleepy(src) - new /obj/item/healthanalyzer/rad_laser(src) - new /obj/item/chameleon(src) - new /obj/item/soap/syndie(src) - new /obj/item/clothing/glasses/thermal/syndi(src) - new /obj/item/flashlight/emp(src) - new /obj/item/jammer(src) + new /obj/item/gun/energy/recharge/ebow(src) // 10 tc + new /obj/item/pen/sleepy(src) // 4 tc + new /obj/item/healthanalyzer/rad_laser(src) // 3 tc + new /obj/item/chameleon(src) // 7 tc + new /obj/item/soap/syndie(src) // 1 tc + new /obj/item/clothing/glasses/thermal/syndi(src) // 4 tc + new /obj/item/flashlight/emp(src) // 2 tc + new /obj/item/jammer(src) // 5 tc if(KIT_GUN) - new /obj/item/gun/ballistic/revolver/syndicate(src) + new /obj/item/gun/ballistic/revolver/syndicate(src) // 13 tc + new /obj/item/ammo_box/a357(src) // 4tc new /obj/item/ammo_box/a357(src) - new /obj/item/ammo_box/a357(src) - new /obj/item/card/emag(src) - new /obj/item/grenade/c4(src) - new /obj/item/clothing/gloves/color/latex/nitrile(src) + new /obj/item/storage/belt/holster/chameleon(src) // 1 tc + new /obj/item/card/emag/doorjack(src) // 3 tc replaced the emag with the doorjack + new /obj/item/grenade/c4(src) // 1 tc + new /obj/item/clothing/gloves/color/latex/nitrile(src) // ~1 tc for whole outfit new /obj/item/clothing/mask/gas/clown_hat(src) new /obj/item/clothing/under/suit/black_really(src) new /obj/item/clothing/neck/tie/red/hitman(src) if(KIT_SCREWED) - new /obj/item/sbeacondrop/bomb(src) - new /obj/item/grenade/syndieminibomb(src) - new /obj/item/sbeacondrop/powersink(src) - new /obj/item/clothing/suit/space/syndicate/black/red(src) + new /obj/item/sbeacondrop/bomb(src) // 11 tc + new /obj/item/grenade/syndieminibomb(src) // 6 tc + new /obj/item/sbeacondrop/powersink(src) // 11 tc + new /obj/item/clothing/suit/space/syndicate/black/red(src) // outfit 1 tc new /obj/item/clothing/head/helmet/space/syndicate/black/red(src) - new /obj/item/encryptionkey/syndicate(src) + new /obj/item/encryptionkey/syndicate(src) // 2 tc if(KIT_MURDER) - new /obj/item/melee/energy/sword/saber(src) - new /obj/item/clothing/glasses/thermal/syndi(src) - new /obj/item/card/emag(src) - new /obj/item/clothing/shoes/chameleon/noslip(src) - new /obj/item/encryptionkey/syndicate(src) - new /obj/item/grenade/syndieminibomb(src) + new /obj/item/melee/energy/sword/saber(src) // 8 tc + new /obj/item/clothing/glasses/thermal/syndi(src) // 4 tc + new /obj/item/card/emag/doorjack(src) // 3 tc + new /obj/item/clothing/shoes/chameleon/noslip(src) // 2 tc + new /obj/item/encryptionkey/syndicate(src) // 2 tc + new /obj/item/grenade/syndieminibomb(src) // 6 tc if(KIT_IMPLANTS) - new /obj/item/implanter/freedom(src) - new /obj/item/implanter/uplink/precharged(src) - new /obj/item/implanter/emp(src) - new /obj/item/implanter/explosive(src) - new /obj/item/implanter/storage(src) + new /obj/item/implanter/freedom(src) // 5 tc + new /obj/item/implanter/uplink/precharged(src) // 10 tc is inside this thing + new /obj/item/implanter/emp(src) // 1 tc + new /obj/item/implanter/explosive(src) // 2 tc + new /obj/item/implanter/storage(src) // 8 tc if(KIT_HACKER) //L-L--LOOK AT YOU, HACKER - new /obj/item/ai_module/syndicate(src) - new /obj/item/card/emag(src) - new /obj/item/encryptionkey/binary(src) - new /obj/item/ai_module/toy_ai(src) - new /obj/item/multitool/ai_detect(src) - new /obj/item/storage/toolbox/syndicate(src) - new /obj/item/camera_bug(src) - new /obj/item/clothing/glasses/thermal/syndi(src) - new /obj/item/card/id/advanced/chameleon(src) + new /obj/item/ai_module/syndicate(src) // 4 tc + new /obj/item/card/emag(src) // 4 tc + new /obj/item/card/emag/doorjack(src) // 3 tc + new /obj/item/encryptionkey/binary(src) // 5 tc + new /obj/item/ai_module/toy_ai(src) // ~6 tc + new /obj/item/multitool/ai_detect(src) // 1 tc + new /obj/item/storage/toolbox/syndicate(src) // 1 tc + new /obj/item/camera_bug(src) // 1 tc + new /obj/item/clothing/glasses/thermal/syndi(src) // 4 tc + new /obj/item/card/id/advanced/chameleon(src) // 2 tc - if(KIT_LORD_SINGULOTH) //can't loose the goose anymore without SM :( - new /obj/item/sbeacondrop(src) + if(KIT_LORD_SINGULOTH) //currently disabled, i might return with another anti-engine kit + new /obj/item/sbeacondrop(src) // 10 tc new /obj/item/clothing/suit/space/syndicate/black/red(src) new /obj/item/clothing/head/helmet/space/syndicate/black/red(src) - new /obj/item/card/emag(src) - new /obj/item/storage/toolbox/syndicate(src) + new /obj/item/card/emag(src) // 4 tc + new /obj/item/storage/toolbox/syndicate(src) // 1 tc new /obj/item/card/id/advanced/mining(src) - new /obj/item/stack/spacecash/c10000(src) + new /obj/item/stack/spacecash/c10000(src) // this is technically 10 tc but not really new /obj/item/toy/spinningtoy(src) //lol if(KIT_SABOTAGE) - /obj/item/storage/backpack/duffelbag/syndie/sabotage - new /obj/item/camera_bug(src) - new /obj/item/sbeacondrop/powersink(src) - new /obj/item/computer_disk/virus/detomatix(src) - new /obj/item/storage/toolbox/syndicate(src) - new /obj/item/pizzabox/bomb(src) - new /obj/item/storage/box/syndie_kit/emp(src) + new /obj/item/storage/backpack/duffelbag/syndie/sabotage(src) // 5 tc for 3 c4 and 2 x4 + new /obj/item/camera_bug(src) // 1 tc + new /obj/item/sbeacondrop/powersink(src) // 11 tc + new /obj/item/computer_disk/virus/detomatix(src) // 6 tc + new /obj/item/storage/toolbox/syndicate(src) // 1 tc + new /obj/item/pizzabox/bomb(src) // 6 tc + new /obj/item/storage/box/syndie_kit/emp(src) // 2 tc if(KIT_SNIPER) //This shit is unique so can't really balance it around tc, also no silencer because getting killed without ANY indicator on what killed you sucks new /obj/item/gun/ballistic/automatic/sniper_rifle(src) // 12 tc - new /obj/item/ammo_box/magazine/sniper_rounds/penetrator(src) - new /obj/item/clothing/glasses/thermal/syndi(src) - new /obj/item/clothing/gloves/color/latex/nitrile(src) + new /obj/item/ammo_box/magazine/sniper_rounds/penetrator(src) // 5 tc + new /obj/item/clothing/glasses/thermal/syndi(src) // 4 tc + new /obj/item/clothing/gloves/color/latex/nitrile(src) // ~ 1 tc for outfit new /obj/item/clothing/mask/gas/clown_hat(src) new /obj/item/clothing/under/suit/black_really(src) new /obj/item/clothing/neck/tie/red/hitman(src) @@ -166,31 +169,40 @@ KIT_TRAITOR_2006 = 1 ))) if(KIT_JAMES_BOND) - new /obj/item/gun/ballistic/automatic/pistol(src) - new /obj/item/suppressor(src) + new /obj/item/gun/ballistic/automatic/pistol(src) // 7 tc + new /obj/item/suppressor(src) // 3 tc + new /obj/item/ammo_box/magazine/m9mm(src) // 1 tc new /obj/item/ammo_box/magazine/m9mm(src) - new /obj/item/ammo_box/magazine/m9mm(src) - new /obj/item/card/id/advanced/chameleon(src) - new /obj/item/clothing/under/chameleon(src) - new /obj/item/reagent_containers/hypospray/medipen/stimulants(src) + new /obj/item/card/id/advanced/chameleon(src) // 2 tc + new /obj/item/clothing/under/chameleon(src) // 1 tc + new /obj/item/reagent_containers/hypospray/medipen/stimulants(src) // 5 tc new /obj/item/reagent_containers/cup/rag(src) + new /obj/item/implanter/freedom(src) // 5 tc + new /obj/item/flashlight/emp(src) // 2 tc + new /obj/item/grenade/c4/x4(src) // 1ish tc + new /obj/item/reagent_containers/pill/cyanide(src) + new /obj/item/toy/cards/deck/syndicate(src) // 1 tc, for poker if(KIT_NINJA) new /obj/item/katana(src) // Unique , hard to tell how much tc this is worth. 8 tc? new /obj/item/reagent_containers/hypospray/medipen/stimulants(src) // 5 tc for(var/i in 1 to 6) - new /obj/item/throwing_star(src) // ~5 tc for all 6 - new /obj/item/storage/belt/chameleon(src) // Unique but worth at least 2 tc + new /obj/item/throwing_star(src) // 1 tc + new /obj/item/storage/belt/chameleon(src) // worth some fraction of a tc new /obj/item/chameleon(src) // 7 tc new /obj/item/card/id/advanced/chameleon(src) // 2 tc + new /obj/item/card/emag/doorjack(src) // 3 tc + new /obj/item/book/granter/action/spell/smoke(src) // ninja smoke bomb. 1 tc + new /obj/item/clothing/shoes/bhop(src) // mining item, lets you jump at people, at least 2 tc if(KIT_DARK_LORD) - new /obj/item/dualsaber(src) - new /obj/item/dnainjector/telemut/darkbundle(src) + new /obj/item/dualsaber/red(src) // 16 tc + new /obj/item/dnainjector/telemut/darkbundle(src) // ~ 4 tc for tk new /obj/item/clothing/suit/hooded/chaplain_hoodie(src) - new /obj/item/card/id/advanced/chameleon(src) - new /obj/item/clothing/shoes/chameleon/noslip(src) //because slipping while being a dark lord sucks - new /obj/item/book/granter/action/spell/summonitem(src) + new /obj/item/card/id/advanced/chameleon(src) // 2 tc + new /obj/item/clothing/shoes/chameleon/noslip(src) //2 tc ,because slipping while being a dark lord sucks + new /obj/item/book/granter/action/spell/summonitem(src) // ~2 tc + new /obj/item/book/granter/action/spell/lightningbolt(src) // 4 tc if(KIT_WHITE_WHALE_HOLY_GRAIL) //Unique items that don't appear anywhere else new /obj/item/gun/ballistic/rifle/boltaction/harpoon(src) @@ -198,6 +210,7 @@ new /obj/item/clothing/suit/hooded/carp_costume/spaceproof(src) new /obj/item/clothing/mask/gas/carp(src) new /obj/item/grenade/spawnergrenade/spesscarp(src) + new /obj/item/toy/plush/carpplushie/dehy_carp(src) // 1 tc, for use as a personal mount if(KIT_MAD_SCIENTIST) new /obj/item/clothing/suit/toggle/labcoat/mad(src) // 0 tc @@ -211,17 +224,17 @@ new /obj/item/assembly/signaler(src) // 0 tc new /obj/item/assembly/signaler(src) // 0 tc new /obj/item/storage/toolbox/syndicate(src) // 1 tc - new /obj/item/pen/edagger(src) - new /obj/item/gun/energy/wormhole_projector/core_inserted(src) - new /obj/item/gun/energy/decloner/unrestricted(src) + new /obj/item/pen/edagger(src) // 2 tc + new /obj/item/gun/energy/wormhole_projector/core_inserted(src) // 5 tc easily + new /obj/item/gun/energy/decloner/unrestricted(src) // 5 tc at least also if(KIT_BEES) new /obj/item/paper/fluff/bee_objectives(src) // 0 tc (motivation) new /obj/item/clothing/suit/hooded/bee_costume(src) // 0 tc new /obj/item/clothing/mask/animal/small/bee(src) // 0 tc new /obj/item/storage/belt/fannypack/yellow(src) // 0 tc - new /obj/item/grenade/spawnergrenade/buzzkill(src) - new /obj/item/grenade/spawnergrenade/buzzkill(src) + new /obj/item/grenade/spawnergrenade/buzzkill(src) // these are the random super bees this is definitely all of the tc budget for this one + new /obj/item/grenade/spawnergrenade/buzzkill(src) // 10 tc per grenade new /obj/item/reagent_containers/cup/bottle/beesease(src) // 10 tc? new /obj/item/melee/beesword(src) //priceless @@ -231,14 +244,15 @@ new /obj/item/clothing/mask/chameleon(src) new /obj/item/clothing/suit/hooded/wintercoat(src) new /obj/item/clothing/shoes/winterboots(src) + new /obj/item/grenade/gluon(src) // whole belt is 22 and gluon is weight 4 so lets just go with like 7 total new /obj/item/grenade/gluon(src) new /obj/item/grenade/gluon(src) new /obj/item/grenade/gluon(src) - new /obj/item/grenade/gluon(src) - new /obj/item/dnainjector/geladikinesis(src) + new /obj/item/dnainjector/geladikinesis(src) // both abilities are probably 3 tc total new /obj/item/dnainjector/cryokinesis(src) - new /obj/item/gun/energy/temperature/security(src) - new /obj/item/melee/energy/sword/saber/blue(src) //see see it fits the theme bc its blue and ice is blue + new /obj/item/gun/energy/temperature/freeze(src) // ~6 tc + new /obj/item/gun/energy/laser/thermal/cryo(src) // ~6 tc + new /obj/item/melee/energy/sword/saber/blue(src) //see see it fits the theme bc its blue and ice is blue, 8 tc if(KIT_TRAITOR_2006) //A kit so old, it's probably older than you. //This bundle is filled with the entire unlink contents traitors had access to in 2006, from OpenSS13. Notably the esword was not a choice but existed in code. new /obj/item/storage/toolbox/emergency/old/ancientbundle(src) //Items fit neatly into a classic toolbox just to remind you what the theme is. @@ -246,12 +260,13 @@ /obj/item/storage/toolbox/emergency/old/ancientbundle/ //So the subtype works /obj/item/storage/toolbox/emergency/old/ancientbundle/PopulateContents() - new /obj/item/card/emag(src) - new /obj/item/pen/sleepy(src) + new /obj/item/card/emag(src) // 4 tc + new /obj/item/card/emag/doorjack(src) //emag used to do both. 3 tc + new /obj/item/pen/sleepy(src) // 4 tc new /obj/item/reagent_containers/pill/cyanide(src) - new /obj/item/chameleon(src) //its not the original cloaking device, but it will do. - new /obj/item/gun/ballistic/revolver/syndicate(src) - new /obj/item/implanter/freedom(src) + new /obj/item/chameleon(src) //its not the original cloaking device, but it will do. 8 tc + new /obj/item/gun/ballistic/revolver(src) // 13 tc old one stays in the old box + new /obj/item/implanter/freedom(src) // 5 tc new /obj/item/stack/telecrystal(src) //The failsafe/self destruct isn't an item we can physically include in the kit, but 1 TC is technically enough to buy the equivalent. /obj/item/storage/box/syndicate/contract_kit //SKYRAT EDIT - CHANGED IN MODULAR FOLDER diff --git a/code/game/objects/structures/crates_lockers/crates/syndicrate.dm b/code/game/objects/structures/crates_lockers/crates/syndicrate.dm new file mode 100644 index 00000000000..c5106354ae5 --- /dev/null +++ b/code/game/objects/structures/crates_lockers/crates/syndicrate.dm @@ -0,0 +1,76 @@ +/obj/structure/closet/crate/syndicrate + name = "surplus syndicrate" + desc = "A conspicuous crate with the Syndicate logo on it. You don't know how to open it." + icon_state = "syndicrate" + max_integrity = 500 + armor = list(MELEE = 30, BULLET = 50, LASER = 50, ENERGY = 100, BOMB = 0, BIO = 0) + resistance_flags = FIRE_PROOF | ACID_PROOF + integrity_failure = 0 //prevents bust_open from activating + /// variable that only lets the crate open if opened by a key from the uplink + var/created_items = FALSE + /// this is what will spawn when it is opened with a syndicrate key + var/list/unlock_contents = list() + +/// if the crate takes damage it will explode 25% of the time +/obj/structure/closet/crate/syndicrate/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1) + if(created_items) + return ..() + if(damage_amount < DAMAGE_PRECISION) + return ..() + if(prob(75)) + return ..() + visible_message(span_danger("The syndicrate's anti-tamper system activates!")) + explosion(src, heavy_impact_range = 1, light_impact_range = 2, flash_range = 2) + qdel(src) + +///ensures that the syndicrate can only be unlocked by opening it with a syndicrate_key +/obj/structure/closet/crate/syndicrate/attackby(obj/item/item, mob/user, params) + if(!istype(item, /obj/item/syndicrate_key) || created_items) + return ..() + created_items = TRUE + for(var/item_path as anything in unlock_contents) + new item_path(src) + unlock_contents = list() + qdel(item) + to_chat(user, span_notice("You twist the key into both locks at once, opening the crate.")) + playsound(src, 'sound/machines/boltsup.ogg', 50, vary = FALSE) + update_appearance(updates = UPDATE_OVERLAYS) + togglelock(user) + +/obj/structure/closet/crate/syndicrate/attackby_secondary(obj/item/weapon, mob/user, params) + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + +///overwrites default opening behavior until it is unlocked via the syndicrate key +/obj/structure/closet/crate/syndicrate/can_open(mob/living/user, force = FALSE) + if(!created_items) + balloon_alert(user, "Locked!") + return FALSE + return ..() + +///syndicrate has a unique overlay for being unlocked +/obj/structure/closet/crate/syndicrate/closet_update_overlays(list/new_overlays) + . = new_overlays + if(created_items) + . += "syndicrate_unlocked" + +/obj/item/syndicrate_key + name = "syndicrate key" + desc = "A device bearing a serpentine emblem, capable of splitting itself into two keys. Can be used to open one syndicrate." + icon = 'icons/obj/storage/crates.dmi' + icon_state = "syndicrate_key" + w_class = WEIGHT_CLASS_TINY + +/obj/item/syndicrate_key/Initialize(mapload) + . = ..() + register_item_context() + +/obj/item/add_item_context(obj/item/source, list/context, atom/target, mob/living/user,) + . = ..() + + var/obj/structure/closet/crate/syndicrate/target_structure = target + if(!istype(target_structure)) + return NONE + if(target_structure.created_items) + return NONE + context[SCREENTIP_CONTEXT_LMB] = "Unlock Syndicrate" + return CONTEXTUAL_SCREENTIP_SET diff --git a/code/modules/antagonists/traitor/uplink_handler.dm b/code/modules/antagonists/traitor/uplink_handler.dm index 8b65312fc6c..800844a70dc 100644 --- a/code/modules/antagonists/traitor/uplink_handler.dm +++ b/code/modules/antagonists/traitor/uplink_handler.dm @@ -16,8 +16,8 @@ var/progression_points = 0 /// The purchase log of this uplink handler var/datum/uplink_purchase_log/purchase_log - /// Associative array of uplink item = stock left - var/list/item_stock = list() + /// Associative array of stock keys = stock left. For items that don't share stock, the key is their typepath + var/list/item_stock = list(UPLINK_SHARED_STOCK_KITS = 1 , UPLINK_SHARED_STOCK_SURPLUS = 1) /// Extra stuff that can be purchased by an uplink, regardless of flag. var/list/extra_purchasable = list() /// Whether this uplink handler has objectives. @@ -56,22 +56,32 @@ SEND_SIGNAL(src, COMSIG_UPLINK_HANDLER_ON_UPDATE) return +/// Checks if traitor has enough reputation to purchase an item +/datum/uplink_handler/proc/not_enough_reputation(datum/uplink_item/to_purchase) + return has_progression && progression_points < to_purchase.progression_minimum + +/// Checks for uplink flags as well as items restricted to roles and species +/datum/uplink_handler/proc/check_if_restricted(datum/uplink_item/to_purchase) + if((to_purchase in extra_purchasable)) + return TRUE + if(!(to_purchase.purchasable_from & uplink_flag)) + return FALSE + if(length(to_purchase.restricted_roles) && !(assigned_role in to_purchase.restricted_roles)) + return FALSE + if(length(to_purchase.restricted_species) && !(assigned_species in to_purchase.restricted_species)) + return FALSE + return TRUE + /datum/uplink_handler/proc/can_purchase_item(mob/user, datum/uplink_item/to_purchase) if(debug_mode) return TRUE - if(!(to_purchase in extra_purchasable)) - if(!(to_purchase.purchasable_from & uplink_flag)) - return FALSE + if(!check_if_restricted(to_purchase)) + return FALSE - if(length(to_purchase.restricted_roles) && !(assigned_role in to_purchase.restricted_roles)) - return FALSE - if(length(to_purchase.restricted_species) && !(assigned_species in to_purchase.restricted_species)) - return FALSE - - var/current_stock = item_stock[to_purchase] + var/current_stock = item_stock[to_purchase.stock_key] var/stock = current_stock != null? current_stock : INFINITY - if(telecrystals < to_purchase.cost || stock <= 0 || (has_progression && progression_points < to_purchase.progression_minimum)) + if(telecrystals < to_purchase.cost || stock <= 0 || not_enough_reputation(to_purchase)) return FALSE return TRUE @@ -80,14 +90,14 @@ if(!can_purchase_item(user, to_purchase)) return - if(to_purchase.limited_stock != -1 && !(to_purchase in item_stock)) - item_stock[to_purchase] = to_purchase.limited_stock + if(to_purchase.limited_stock != -1 && !(to_purchase.stock_key in item_stock)) + item_stock[to_purchase.stock_key] = to_purchase.limited_stock telecrystals -= to_purchase.cost to_purchase.purchase(user, src, source) - if(to_purchase in item_stock) - item_stock[to_purchase] -= 1 + if(to_purchase.stock_key in item_stock) + item_stock[to_purchase.stock_key] -= 1 SSblackbox.record_feedback("nested tally", "traitor_uplink_items_bought", 1, list("[initial(to_purchase.name)]", "[to_purchase.cost]")) on_update() diff --git a/code/modules/asset_cache/assets/uplink.dm b/code/modules/asset_cache/assets/uplink.dm index 6af6e1ff93e..7d1b6d950b9 100644 --- a/code/modules/asset_cache/assets/uplink.dm +++ b/code/modules/asset_cache/assets/uplink.dm @@ -28,6 +28,7 @@ "purchasable_from" = item.purchasable_from, "restricted" = item.restricted, "limited_stock" = item.limited_stock, + "stock_key" = item.stock_key, "restricted_roles" = item.restricted_roles, "restricted_species" = item.restricted_species, "progression_minimum" = item.progression_minimum, diff --git a/code/modules/cargo/packs/general.dm b/code/modules/cargo/packs/general.dm index d7819b8a60e..b1ff57bccf9 100644 --- a/code/modules/cargo/packs/general.dm +++ b/code/modules/cargo/packs/general.dm @@ -256,11 +256,12 @@ /datum/supply_pack/misc/syndicate name = "Assorted Syndicate Gear" desc = "Contains a random assortment of syndicate gear." - special = TRUE ///Cannot be ordered via cargo + special = TRUE //Cannot be ordered via cargo contains = list() crate_name = "syndicate gear crate" crate_type = /obj/structure/closet/crate - var/crate_value = 30 ///Total TC worth of contained uplink items + ///Total TC worth of contained uplink items + var/crate_value = 30 var/uplink_flag = UPLINK_TRAITORS ///Generate assorted uplink items, taking into account the same surplus modifiers used for surplus crates @@ -275,6 +276,8 @@ var/datum/uplink_item/uplink_item = pick(uplink_items) if(!uplink_item.surplus || prob(100 - uplink_item.surplus)) continue + if(length(uplink_item.restricted_roles) || length(uplink_item.restricted_species)) + continue if(crate_value < uplink_item.cost) continue crate_value -= uplink_item.cost diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index 78be2aef3f7..12212dd9b9b 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -338,6 +338,12 @@ desc = "A weapon that can only be used to its full potential by the truly robust." pin = /obj/item/firing_pin +/obj/item/gun/energy/temperature/freeze + name = "cryogenic temperature gun" + desc = "A gun that reduces temperatures. Only for those with ice in their veins." + pin = /obj/item/firing_pin + ammo_type = list(/obj/item/ammo_casing/energy/temp) + /obj/item/gun/energy/gravity_gun name = "one-point gravitational manipulator" desc = "An experimental, multi-mode device that fires bolts of Zero-Point Energy, causing local distortions in gravity. Requires a gravitational anomaly core to function." diff --git a/code/modules/spells/spell_types/right_and_wrong.dm b/code/modules/spells/spell_types/right_and_wrong.dm index 9b973b90f48..2758cea178c 100644 --- a/code/modules/spells/spell_types/right_and_wrong.dm +++ b/code/modules/spells/spell_types/right_and_wrong.dm @@ -67,6 +67,7 @@ GLOBAL_LIST_INIT(summoned_magic, list( /obj/item/book/granter/action/spell/barnyard, /obj/item/book/granter/action/spell/charge, /obj/item/book/granter/action/spell/summonitem, + /obj/item/book/granter/action/spell/lightningbolt, /obj/item/gun/magic/wand/nothing, /obj/item/gun/magic/wand/death, /obj/item/gun/magic/wand/resurrection, diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm index 12c0134e37a..cf9f7315eb9 100644 --- a/code/modules/uplink/uplink_items.dm +++ b/code/modules/uplink/uplink_items.dm @@ -46,6 +46,8 @@ var/surplus = 100 /// Whether this can be discounted or not var/cant_discount = FALSE + /// If this value is changed on two items they will share stock, defaults to not sharing stock with any other item + var/stock_key = UPLINK_SHARED_STOCK_UNIQUE /// How many items of this stock can be purchased. var/limited_stock = -1 //Setting this above zero limits how many times this item can be bought by the same traitor in a round, -1 is unlimited /// A bitfield to represent what uplinks can purchase this item. @@ -66,6 +68,12 @@ // String to be shown instead of the price, e.g for the Random item. var/cost_override_string = "" +/datum/uplink_item/New() + . = ..() + if(stock_key != UPLINK_SHARED_STOCK_UNIQUE) + return + stock_key = type + /datum/uplink_category /// Name of the category var/name @@ -125,3 +133,6 @@ ..() if(user?.mind?.failed_special_equipment) user.mind.failed_special_equipment -= item + +/// Code that enables the ability to have limited stock that is shared by different items +/datum/shared_uplink_stock diff --git a/code/modules/uplink/uplink_items/bundle.dm b/code/modules/uplink/uplink_items/bundle.dm index 103125633d4..cabfd2ed249 100644 --- a/code/modules/uplink/uplink_items/bundle.dm +++ b/code/modules/uplink/uplink_items/bundle.dm @@ -51,3 +51,126 @@ desc = "Twenty telecrystals in their rawest and purest form; can be utilized on active uplinks to increase their telecrystal count." item = /obj/item/stack/telecrystal/twenty cost = 20 + +/datum/uplink_item/bundles_tc/bundle_a + name = "Syndi-kit Tactical" + desc = "Syndicate Bundles, also known as Syndi-Kits, are specialized groups of items that arrive in a plain box. \ + These items are collectively worth more than 25 telecrystals, but you do not know which specialization \ + you will receive. May contain discontinued and/or exotic items. \ + The Syndicate will only provide one Syndi-Kit per agent." + progression_minimum = 30 MINUTES + item = /obj/item/storage/box/syndicate/bundle_a + cost = 25 + stock_key = UPLINK_SHARED_STOCK_KITS + purchasable_from = ~(UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS) + +/datum/uplink_item/bundles_tc/bundle_b + name = "Syndi-kit Special" + desc = "Syndicate Bundles, also known as Syndi-Kits, are specialized groups of items that arrive in a plain box. \ + In Syndi-kit Special, you will receive items used by famous syndicate agents of the past. \ + Collectively worth more than 25 telecrystals, the syndicate loves a good throwback. \ + The Syndicate will only provide one Syndi-Kit per agent." + progression_minimum = 30 MINUTES + item = /obj/item/storage/box/syndicate/bundle_b + cost = 25 + stock_key = UPLINK_SHARED_STOCK_KITS + purchasable_from = ~(UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS) + +/datum/uplink_item/bundles_tc/surplus + name = "Syndicate Surplus Crate" + desc = "A dusty crate from the back of the Syndicate warehouse delivered directly to you via Supply Pod. \ + If the rumors are true, it will fill it's contents based on your current reputation. Get on that grind. \ + Contents are sorted to always be worth 30 TC. The Syndicate will only provide one surplus item per agent." + item = /obj/structure/closet/crate // will be replaced in purchase() + cost = 20 + purchasable_from = ~(UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS) + stock_key = UPLINK_SHARED_STOCK_SURPLUS + /// Value of items inside the crate in TC + var/crate_tc_value = 30 + /// crate that will be used for the surplus crate + var/crate_type = /obj/structure/closet/crate + +/// generates items that can go inside crates, edit this proc to change what items could go inside your specialized crate +/datum/uplink_item/bundles_tc/surplus/proc/generate_possible_items(mob/user, datum/uplink_handler/handler) + var/list/possible_items = list() + for(var/datum/uplink_item/item_path as anything in SStraitor.uplink_items_by_type) + var/datum/uplink_item/uplink_item = SStraitor.uplink_items_by_type[item_path] + if(src == uplink_item || !uplink_item.item) + continue + if(!handler.check_if_restricted(uplink_item)) + continue + if(!uplink_item.surplus) + continue + if(handler.not_enough_reputation(uplink_item)) + continue + possible_items += uplink_item + return possible_items + +/// picks items from the list given to proc and generates a valid uplink item that is less or equal to the amount of TC it can spend +/datum/uplink_item/bundles_tc/surplus/proc/pick_possible_item(list/possible_items, tc_budget) + var/datum/uplink_item/uplink_item = pick(possible_items) + if(prob(100 - uplink_item.surplus)) + return null + if(tc_budget < uplink_item.cost) + return null + return uplink_item + +/// fills the crate that will be given to the traitor, edit this to change the crate and how the item is filled +/datum/uplink_item/bundles_tc/surplus/proc/fill_crate(obj/structure/closet/crate/surplus_crate, list/possible_items) + var/tc_budget = crate_tc_value + while(tc_budget) + var/datum/uplink_item/uplink_item = pick_possible_item(possible_items, tc_budget) + if(!uplink_item) + continue + tc_budget -= uplink_item.cost + new uplink_item.item(surplus_crate) + +/// overwrites purchase for surplus items to instead spawn this crate and run the previous procs +/datum/uplink_item/bundles_tc/surplus/purchase(mob/user, datum/uplink_handler/handler, atom/movable/source) + var/obj/structure/closet/crate/surplus_crate = new crate_type() + if(!istype(surplus_crate)) + CRASH("crate_type is not a crate") + var/list/possible_items = generate_possible_items(user, handler) + + fill_crate(surplus_crate, possible_items) + + podspawn(list( + "target" = get_turf(user), + "style" = STYLE_SYNDICATE, + "spawn" = surplus_crate, + )) + +/datum/uplink_item/bundles_tc/surplus/united + name = "United Surplus Crate" + desc = "A shiny and large crate to be delivered directly to you via Supply Pod. It has an advanced locking mechanism with an anti-tampering protocol. \ + It is recommended that you only attempt to open it by having another agent purchase a Surplus Crate Key. Unite and fight. \ + Rumored to contain a valuable assortment of items based on your current reputation, but you never know. Contents are sorted to always be worth 80 TC. \ + The Syndicate will only provide one surplus item per agent." + cost = 20 + item = /obj/structure/closet/crate/syndicrate + progression_minimum = 30 MINUTES + stock_key = UPLINK_SHARED_STOCK_SURPLUS + crate_tc_value = 80 + crate_type = /obj/structure/closet/crate/syndicrate + +/// edited version of fill crate for super surplus to ensure it can only be unlocked with the syndicrate key +/datum/uplink_item/bundles_tc/surplus/united/fill_crate(obj/structure/closet/crate/syndicrate/surplus_crate, list/possible_items) + if(!istype(surplus_crate)) + return + var/tc_budget = crate_tc_value + while(tc_budget) + var/datum/uplink_item/uplink_item = pick_possible_item(possible_items, tc_budget) + if(!uplink_item) + continue + tc_budget -= uplink_item.cost + surplus_crate.unlock_contents += uplink_item.item + +/datum/uplink_item/bundles_tc/surplus_key + name = "United Surplus Crate Key" + desc = "This inconscpicous device is actually a key that can open any United Surplus Crate. It can only be used once. \ + Though initially designed to encourage cooperation, agents quickly discovered that you can turn the key to the crate by yourself. \ + The Syndicate will only provide one surplus item per agent." + cost = 20 + item = /obj/item/syndicrate_key + progression_minimum = 30 MINUTES + stock_key = UPLINK_SHARED_STOCK_SURPLUS diff --git a/code/modules/uplink/uplink_items/device_tools.dm b/code/modules/uplink/uplink_items/device_tools.dm index d6cea88e96e..5e8e22427d1 100644 --- a/code/modules/uplink/uplink_items/device_tools.dm +++ b/code/modules/uplink/uplink_items/device_tools.dm @@ -252,6 +252,7 @@ progression_minimum = 30 MINUTES item = /obj/item/sbeacondrop cost = 10 + surplus = 0 // not while there isnt one on any station purchasable_from = ~(UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS) /datum/uplink_item/device_tools/powersink diff --git a/code/modules/uplink/uplink_items/job.dm b/code/modules/uplink/uplink_items/job.dm index 97c8878a8fc..b5088f9c9db 100644 --- a/code/modules/uplink/uplink_items/job.dm +++ b/code/modules/uplink/uplink_items/job.dm @@ -7,7 +7,6 @@ /datum/uplink_item/role_restricted category = /datum/uplink_category/role_restricted purchasable_from = ~(UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS) - surplus = 0 // No progression cost /datum/uplink_item/role_restricted/haunted_magic_eightball @@ -18,6 +17,7 @@ cost = 2 restricted_roles = list(JOB_CURATOR) limited_stock = 1 //please don't spam deadchat + surplus = 5 /datum/uplink_item/role_restricted/bureaucratic_error_remote name = "Organic Resources Disturbance Inducer" @@ -26,6 +26,7 @@ limited_stock = 1 item = /obj/item/devices/bureaucratic_error_remote restricted_roles = list(JOB_HEAD_OF_PERSONNEL, JOB_QUARTERMASTER) + surplus = 5 /datum/uplink_item/role_restricted/clumsinessinjector //clown ops can buy this too, but it's in the pointless badassery section for them name = "Clumsiness Injector" @@ -34,6 +35,7 @@ cost = 1 restricted_roles = list(JOB_CLOWN) illegal_tech = FALSE + surplus = 25 /datum/uplink_item/role_restricted/ancient_jumpsuit name = "Ancient Jumpsuit" @@ -61,6 +63,7 @@ item = /obj/item/firing_pin/clown/ultra restricted_roles = list(JOB_CLOWN) illegal_tech = FALSE + surplus = 25 /datum/uplink_item/role_restricted/clownsuperpin name = "Super Ultra Hilarious Firing Pin" @@ -70,6 +73,7 @@ item = /obj/item/firing_pin/clown/ultra/selfdestruct restricted_roles = list(JOB_CLOWN) illegal_tech = FALSE + surplus = 25 /datum/uplink_item/role_restricted/syndimmi name = "Syndicate Brand MMI" @@ -87,7 +91,6 @@ progression_minimum = 10 MINUTES item = /obj/item/hot_potato/syndicate cost = 4 - surplus = 0 restricted_roles = list(JOB_COOK, JOB_BOTANIST, JOB_CLOWN, JOB_MIME) /datum/uplink_item/role_restricted/combat_baking @@ -171,6 +174,7 @@ item = /obj/item/disk/surgery/brainwashing restricted_roles = list(JOB_MEDICAL_DOCTOR, JOB_CHIEF_MEDICAL_OFFICER, JOB_ROBOTICIST) cost = 5 + surplus = 50 /datum/uplink_item/role_restricted/springlock_module name = "Heavily Modified Springlock MODsuit Module" @@ -183,6 +187,7 @@ item = /obj/item/mod/module/springlock/bite_of_87 restricted_roles = list(JOB_ROBOTICIST, JOB_RESEARCH_DIRECTOR) cost = 2 + surplus = 15 /datum/uplink_item/role_restricted/reverse_revolver name = "Reverse Revolver" @@ -202,6 +207,7 @@ cost = 5 //you need two for full damage, so total of 10 for maximum damage limited_stock = 2 //you can't use more than two! restricted_roles = list("Shaft Miner") + surplus = 20 /datum/uplink_item/role_restricted/mimery name = "Guide to Advanced Mimery Series" @@ -220,6 +226,7 @@ cost = 10 item = /obj/item/autosurgeon/syndicate/laser_arm restricted_roles = list(JOB_ROBOTICIST, JOB_RESEARCH_DIRECTOR) + surplus = 20 /datum/uplink_item/role_restricted/chemical_gun name = "Reagent Dartgun" @@ -236,7 +243,6 @@ cost = 10 item = /obj/item/pneumatic_cannon/pie/selfcharge restricted_roles = list(JOB_CLOWN) - surplus = 0 //No fun unless you're the clown! /datum/uplink_item/role_restricted/clown_bomb name = "Clown Bomb" @@ -249,6 +255,7 @@ item = /obj/item/sbeacondrop/clownbomb cost = 15 restricted_roles = list(JOB_CLOWN) + surplus = 10 /datum/uplink_item/role_restricted/clown_bomb/New() . = ..() @@ -266,6 +273,7 @@ item = /obj/vehicle/sealed/car/clowncar cost = 20 restricted_roles = list(JOB_CLOWN) + surplus = 10 /datum/uplink_item/role_restricted/concealed_weapon_bay name = "Concealed Weapon Bay" @@ -277,6 +285,7 @@ item = /obj/item/mecha_parts/mecha_equipment/concealed_weapon_bay cost = 3 restricted_roles = list(JOB_ROBOTICIST, JOB_RESEARCH_DIRECTOR) + surplus = 15 /* //SKYRAT REMOVAL START /datum/uplink_item/role_restricted/his_grace @@ -289,7 +298,7 @@ item = /obj/item/his_grace cost = 20 restricted_roles = list(JOB_CHAPLAIN) - surplus = 5 //Very low chance to get it in a surplus crate even without being the chaplain + surplus = 5 */ //SKYRAT REMOVAL END // High progression cost @@ -306,6 +315,7 @@ item = /obj/item/reagent_containers/syringe/spider_extract cost = 10 restricted_roles = list(JOB_RESEARCH_DIRECTOR, JOB_SCIENTIST, JOB_ROBOTICIST) + surplus = 10 */ // SKYRAT EDIT END @@ -319,3 +329,4 @@ item = /obj/item/gun/blastcannon cost = 14 //High cost because of the potential for extreme damage in the hands of a skilled scientist. restricted_roles = list(JOB_RESEARCH_DIRECTOR, JOB_SCIENTIST) + surplus = 5 diff --git a/code/modules/uplink/uplink_items/species.dm b/code/modules/uplink/uplink_items/species.dm index 85f0ee9e050..54ba353c00a 100644 --- a/code/modules/uplink/uplink_items/species.dm +++ b/code/modules/uplink/uplink_items/species.dm @@ -5,7 +5,6 @@ /datum/uplink_item/species_restricted category = /datum/uplink_category/species purchasable_from = ~(UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS) - surplus = 0 /datum/uplink_item/species_restricted/moth_lantern name = "Extra-Bright Lantern" @@ -14,3 +13,4 @@ cost = 2 item = /obj/item/flashlight/lantern/syndicate restricted_species = list(SPECIES_MOTH) + surplus = 0 diff --git a/icons/obj/library.dmi b/icons/obj/library.dmi index 322bad96e1e..b002d8c7261 100644 Binary files a/icons/obj/library.dmi and b/icons/obj/library.dmi differ diff --git a/icons/obj/storage/crates.dmi b/icons/obj/storage/crates.dmi index 208af28f97c..1ce37de5c5d 100644 Binary files a/icons/obj/storage/crates.dmi and b/icons/obj/storage/crates.dmi differ diff --git a/modular_skyrat/modules/aesthetics/crates/code/crates.dm b/modular_skyrat/modules/aesthetics/crates/code/crates.dm index a09c9b63178..d7a7201a563 100644 --- a/modular_skyrat/modules/aesthetics/crates/code/crates.dm +++ b/modular_skyrat/modules/aesthetics/crates/code/crates.dm @@ -1,6 +1,9 @@ /obj/structure/closet/crate icon = 'modular_skyrat/modules/aesthetics/crates/icons/crates.dmi' +/obj/structure/closet/crate/syndicrate + icon = 'icons/obj/storage/crates.dmi' + /obj/item/delivery icon = 'modular_skyrat/modules/aesthetics/crates/icons/crates.dmi' diff --git a/modular_skyrat/modules/skyrat-uplinks/code/categories/bundles.dm b/modular_skyrat/modules/skyrat-uplinks/code/categories/bundles.dm index 5e83e8119b1..f93e915b8c1 100644 --- a/modular_skyrat/modules/skyrat-uplinks/code/categories/bundles.dm +++ b/modular_skyrat/modules/skyrat-uplinks/code/categories/bundles.dm @@ -15,38 +15,8 @@ cost = 20 purchasable_from = ~(UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS) -/datum/uplink_item/bundles_tc/surplus_crate - name = "Surplus Crate" - desc = "A dusty crate from the back of the Syndicate warehouse. Rumored to contain a valuable assortment of items, \ - but you never know. Contents are sorted to always be worth 50 TC." - item = /obj/effect/gibspawner/generic - cost = 20 - /// The contents of the surplus crate will be equal to this var in TC - var/telecrystal_count = 50 +/datum/uplink_item/bundles_tc/surplus + crate_tc_value = 50 -/datum/uplink_item/bundles_tc/surplus_crate/spawn_item(spawn_path, mob/user, datum/uplink_handler/uplink_handler, atom/movable/source) - telecrystal_count = initial(telecrystal_count) - var/list/uplink_items = list() - var/obj/structure/closet/crate/holder_crate = new(get_turf(user)) - for(var/datum/uplink_item/item_path as anything in SStraitor.uplink_items_by_type) - var/datum/uplink_item/item = SStraitor.uplink_items_by_type[item_path] - if(item.purchasable_from & UPLINK_TRAITORS) - uplink_items += item - - while(telecrystal_count) - var/datum/uplink_item/uplink_item = pick(uplink_items) - if(!uplink_item.surplus || prob(100 - uplink_item.surplus)) - continue - if(telecrystal_count < uplink_item.cost) - continue - if(!uplink_item.item) - continue - telecrystal_count -= uplink_item.cost - new uplink_item.item(holder_crate) - -/datum/uplink_item/bundles_tc/surplus_crate/super - name = "Super Surplus Crate" - desc = "A dusty SUPER-SIZED crate from the back of the Syndicate warehouse. Rumored to contain a valuable assortment of items, \ - but you never know. Contents are sorted to always be worth 125 TC." - telecrystal_count = 125 - cost = 40 +/datum/uplink_item/bundles_tc/surplus/united + crate_tc_value = 125 diff --git a/tgstation.dme b/tgstation.dme index b22551d853d..3c54a24472e 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1901,6 +1901,7 @@ #include "code\game\objects\items\granters\magic\fireball.dm" #include "code\game\objects\items\granters\magic\forcewall.dm" #include "code\game\objects\items\granters\magic\knock.dm" +#include "code\game\objects\items\granters\magic\lightning_bolt.dm" #include "code\game\objects\items\granters\magic\mime.dm" #include "code\game\objects\items\granters\magic\mindswap.dm" #include "code\game\objects\items\granters\magic\sacred_flame.dm" @@ -2125,6 +2126,7 @@ #include "code\game\objects\structures\crates_lockers\crates\critter.dm" #include "code\game\objects\structures\crates_lockers\crates\large.dm" #include "code\game\objects\structures\crates_lockers\crates\secure.dm" +#include "code\game\objects\structures\crates_lockers\crates\syndicrate.dm" #include "code\game\objects\structures\crates_lockers\crates\wooden.dm" #include "code\game\objects\structures\icemoon\cave_entrance.dm" #include "code\game\objects\structures\lavaland\geyser.dm" diff --git a/tgui/packages/tgui/interfaces/Uplink/index.tsx b/tgui/packages/tgui/interfaces/Uplink/index.tsx index f432d422e39..2ae997f15eb 100644 --- a/tgui/packages/tgui/interfaces/Uplink/index.tsx +++ b/tgui/packages/tgui/interfaces/Uplink/index.tsx @@ -19,6 +19,7 @@ type UplinkItem = { purchasable_from: number; restricted: BooleanLike; limited_stock: number; + stock_key: string; restricted_roles: string; restricted_species: string; progression_minimum: number; @@ -187,7 +188,7 @@ export class Uplink extends Component<{}, UplinkState> { const hasEnoughProgression = progression_points >= item.progression_minimum; - let stock: number | null = current_stock[item.id]; + let stock: number | null = current_stock[item.stock_key]; if (item.ref) { stock = extra_purchasable_stock[item.ref]; }