diff --git a/code/__DEFINES/components.dm b/code/__DEFINES/components.dm
index f1a4e014a176..6bd346821ef9 100644
--- a/code/__DEFINES/components.dm
+++ b/code/__DEFINES/components.dm
@@ -63,4 +63,4 @@
// /obj/machinery signals
#define COMSIG_MACHINE_PROCESS "machine_process" //from machinery subsystem fire(): ()
-#define COMSIG_MACHINE_PROCESS_ATMOS "machine_process_atmos" //from air subsystem process_atmos_machinery(): ()
+#define COMSIG_MACHINE_PROCESS_ATMOS "machine_process_atmos" //from air subsystem process_atmos_machinery(): ()
diff --git a/code/datums/components/_component.dm b/code/datums/components/_component.dm
index 0c85ddd871af..48e1b98fd194 100644
--- a/code/datums/components/_component.dm
+++ b/code/datums/components/_component.dm
@@ -16,7 +16,7 @@
if(Initialize(arglist(arguments)) == COMPONENT_INCOMPATIBLE)
qdel(src, TRUE, TRUE)
return
-
+
_CheckDupesAndJoinParent(P)
/datum/component/proc/_CheckDupesAndJoinParent()
@@ -45,12 +45,12 @@
if(!old)
//let the others know
P.SendSignal(COMSIG_COMPONENT_ADDED, src)
-
+
//lazy init the parent's dc list
var/list/dc = P.datum_components
if(!dc)
P.datum_components = dc = list()
-
+
//set up the typecache
var/our_type = type
for(var/I in _GetInverseTypeList(our_type))
@@ -114,7 +114,7 @@
if(!procs)
procs = list()
signal_procs = procs
-
+
var/list/sig_types = islist(sig_type_or_types) ? sig_type_or_types : list(sig_type_or_types)
for(var/sig_type in sig_types)
if(!override)
@@ -177,7 +177,7 @@
for(var/I in target)
var/datum/component/C = I
if(!C.enabled)
- continue
+ continue
var/list/sps = C.signal_procs
var/datum/callback/CB = LAZYACCESS(sps, sigtype)
if(!CB)
@@ -255,3 +255,6 @@
target.TakeComponent(I)
else
target.TakeComponent(comps)
+
+/datum/component/ui_host()
+ return parent
diff --git a/code/datums/components/uplink.dm b/code/datums/components/uplink.dm
new file mode 100644
index 000000000000..407965aeb98f
--- /dev/null
+++ b/code/datums/components/uplink.dm
@@ -0,0 +1,204 @@
+GLOBAL_LIST_EMPTY(uplinks)
+
+/**
+ * Uplinks
+ *
+ * All /obj/item(s) have a hidden_uplink var. By default it's null. Give the item one with 'new(src') (it must be in it's contents). Then add 'uses.'
+ * Use whatever conditionals you want to check that the user has an uplink, and then call interact() on their uplink.
+ * You might also want the uplink menu to open if active. Check if the uplink is 'active' and then interact() with it.
+**/
+/datum/component/uplink
+ dupe_mode = COMPONENT_DUPE_UNIQUE
+ var/name = "syndicate uplink"
+ var/active = FALSE
+ var/lockable = TRUE
+ var/locked = TRUE
+ var/telecrystals
+ var/selected_cat
+ var/owner = null
+ var/datum/game_mode/gamemode
+ var/spent_telecrystals = 0
+ var/datum/uplink_purchase_log/purchase_log
+ var/list/uplink_items
+ var/hidden_crystals = 0
+
+/datum/component/uplink/Initialize(_owner, _lockable = TRUE, _enabled = FALSE, datum/game_mode/_gamemode, starting_tc = 20)
+ if(!isitem(parent))
+ return COMPONENT_INCOMPATIBLE
+ GLOB.uplinks += src
+ uplink_items = get_uplink_items(gamemode)
+ RegisterSignal(COMSIG_PARENT_ATTACKBY, .proc/OnAttackBy)
+ RegisterSignal(COMSIG_ITEM_ATTACK_SELF, .proc/interact)
+ owner = _owner
+ if(owner)
+ LAZYINITLIST(GLOB.uplink_purchase_logs_by_key)
+ if(GLOB.uplink_purchase_logs_by_key[owner])
+ purchase_log = GLOB.uplink_purchase_logs_by_key[owner]
+ else
+ purchase_log = new(owner, src)
+ lockable = _lockable
+ active = _enabled
+ gamemode = _gamemode
+ telecrystals = starting_tc
+ if(!lockable)
+ active = TRUE
+ locked = FALSE
+
+/datum/component/uplink/InheritComponent(datum/component/uplink/U)
+ lockable |= U.lockable
+ active |= U.active
+ if(!gamemode)
+ gamemode = U.gamemode
+ telecrystals += U.telecrystals
+ if(purchase_log && U.purchase_log)
+ purchase_log.MergeWithAndDel(U.purchase_log)
+
+/datum/component/uplink/Destroy()
+ GLOB.uplinks -= src
+ gamemode = null
+ return ..()
+
+/datum/component/uplink/proc/LoadTC(mob/user, obj/item/stack/telecrystal/TC, silent = FALSE)
+ if(!silent)
+ to_chat(user, "You slot [TC] into [parent] and charge its internal uplink.")
+ var/amt = TC.amount
+ telecrystals += amt
+ TC.use(amt)
+
+/datum/component/uplink/proc/set_gamemode(_gamemode)
+ gamemode = _gamemode
+ uplink_items = get_uplink_items(gamemode)
+
+/datum/component/uplink/proc/OnAttackBy(obj/item/I, mob/user)
+ if(!active)
+ return //no hitting everyone/everything just to try to slot tcs in!
+ if(istype(I, /obj/item/stack/telecrystal))
+ LoadTC(user, I)
+ for(var/item in subtypesof(/datum/uplink_item))
+ var/datum/uplink_item/UI = item
+ var/path = null
+ if(initial(UI.refund_path))
+ path = initial(UI.refund_path)
+ else
+ path = initial(UI.item)
+ var/cost = 0
+ if(initial(UI.refund_amount))
+ cost = initial(UI.refund_amount)
+ else
+ cost = initial(UI.cost)
+ var/refundable = initial(UI.refundable)
+ if(I.type == path && refundable && I.check_uplink_validity())
+ telecrystals += cost
+ spent_telecrystals -= cost
+ to_chat(user, "[I] refunded.")
+ qdel(I)
+ return
+
+/datum/component/uplink/proc/interact(mob/user)
+ if(locked)
+ return
+ active = TRUE
+ if(user)
+ ui_interact(user)
+
+/datum/component/uplink/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
+ datum/tgui/master_ui = null, datum/ui_state/state = GLOB.inventory_state)
+ active = TRUE
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ if(!ui)
+ ui = new(user, src, ui_key, "uplink", name, 450, 750, master_ui, state)
+ ui.set_autoupdate(FALSE) // This UI is only ever opened by one person, and never is updated outside of user input.
+ ui.set_style("syndicate")
+ ui.open()
+
+/datum/component/uplink/ui_data(mob/user)
+ if(!user.mind)
+ return
+ var/list/data = list()
+ data["telecrystals"] = telecrystals
+ data["lockable"] = lockable
+
+ data["categories"] = list()
+ for(var/category in uplink_items)
+ var/list/cat = list(
+ "name" = category,
+ "items" = (category == selected_cat ? list() : null))
+ if(category == selected_cat)
+ for(var/item in uplink_items[category])
+ var/datum/uplink_item/I = uplink_items[category][item]
+ if(I.limited_stock == 0)
+ continue
+ if(I.restricted_roles.len)
+ var/is_inaccessible = 1
+ for(var/R in I.restricted_roles)
+ if(R == user.mind.assigned_role)
+ is_inaccessible = 0
+ if(is_inaccessible)
+ continue
+ cat["items"] += list(list(
+ "name" = I.name,
+ "cost" = I.cost,
+ "desc" = I.desc,
+ ))
+ data["categories"] += list(cat)
+ return data
+
+/datum/component/uplink/ui_act(action, params)
+ if(!active)
+ return
+
+ switch(action)
+ if("buy")
+ var/item = params["item"]
+
+ var/list/buyable_items = list()
+ for(var/category in uplink_items)
+ buyable_items += uplink_items[category]
+
+ if(item in buyable_items)
+ var/datum/uplink_item/I = buyable_items[item]
+ MakePurchase(usr, I)
+ . = TRUE
+ if("lock")
+ active = FALSE
+ locked = TRUE
+ telecrystals += hidden_crystals
+ hidden_crystals = 0
+ SStgui.close_uis(src)
+ if("select")
+ selected_cat = params["category"]
+ return TRUE
+
+/datum/component/uplink/proc/MakePurchase(mob/user, datum/uplink_item/U)
+ if(!istype(U))
+ return
+ if (!user || user.incapacitated())
+ return
+
+ if(telecrystals < U.cost || U.limited_stock == 0)
+ return
+ telecrystals -= U.cost
+
+ var/atom/A = U.spawn_item(get_turf(user), src, user)
+ if(U.purchase_log_vis && purchase_log)
+ var/obj/item/storage/box/B = A
+ var/list/atom/logging = list()
+ if(istype(B) && B.contents.len > 0)
+ logging |= list(B)
+ else
+ logging |= A
+ for(var/atom/_logging in logging)
+ purchase_log.LogPurchase(_logging, U.cost)
+
+ if(U.limited_stock > 0)
+ U.limited_stock -= 1
+
+ SSblackbox.record_feedback("nested tally", "traitor_uplink_items_bought", 1, list("[initial(U.name)]", "[U.cost]"))
+ if(ishuman(user) && istype(A, /obj/item))
+ var/mob/living/carbon/human/H = user
+ if(H.put_in_hands(A))
+ to_chat(H, "[A] materializes into your hands!")
+ else
+ to_chat(H, "\The [A] materializes onto the floor.")
+ return TRUE
+
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index be4c679d68f6..9ba84074f56c 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -295,9 +295,7 @@
to_chat(traitor_mob, "Unfortunately, [employer] wasn't able to get you an Uplink.")
. = 0
else
- var/obj/item/device/uplink/U = new(uplink_loc)
- U.owner = "[traitor_mob.key]"
- uplink_loc.hidden_uplink = U
+ uplink_loc.LoadComponent(/datum/component/uplink, traitor_mob.key)
if(uplink_loc == R)
R.traitor_frequency = sanitize_frequency(rand(MIN_FREQ, MAX_FREQ))
@@ -713,7 +711,7 @@
if(((src in SSticker.mode.traitors) || (src in SSticker.mode.syndicates)) && ishuman(current))
text = "Uplink: give"
- var/obj/item/device/uplink/U = find_syndicate_uplink()
+ var/datum/component/uplink/U = find_syndicate_uplink()
if(U)
text += " | take"
if (check_rights(R_FUN, 0))
@@ -1296,7 +1294,7 @@
log_admin("[key_name(usr)] removed [current]'s uplink.")
if("crystals")
if(check_rights(R_FUN, 0))
- var/obj/item/device/uplink/U = find_syndicate_uplink()
+ var/datum/component/uplink/U = find_syndicate_uplink()
if(U)
var/crystals = input("Amount of telecrystals for [key]","Syndicate uplink", U.telecrystals) as null | num
if(!isnull(crystals))
@@ -1325,15 +1323,14 @@
/datum/mind/proc/find_syndicate_uplink()
var/list/L = current.GetAllContents()
- for (var/obj/item/I in L)
- if (I.hidden_uplink)
- return I.hidden_uplink
- return null
+ for (var/i in L)
+ var/atom/movable/I = i
+ . = I.GetComponent(/datum/component/uplink)
+ if(.)
+ break
/datum/mind/proc/take_uplink()
- var/obj/item/device/uplink/H = find_syndicate_uplink()
- if(H)
- qdel(H)
+ qdel(find_syndicate_uplink())
/datum/mind/proc/make_Traitor()
if(!(has_antag_datum(ANTAG_DATUM_TRAITOR)))
diff --git a/code/modules/uplink/uplink_item.dm b/code/datums/uplink_items.dm
similarity index 97%
rename from code/modules/uplink/uplink_item.dm
rename to code/datums/uplink_items.dm
index 0c178d91a2f6..22c52bc91a3e 100644
--- a/code/modules/uplink/uplink_item.dm
+++ b/code/datums/uplink_items.dm
@@ -89,43 +89,10 @@ GLOBAL_LIST_EMPTY(uplink_items) // Global list so we only initialize this once.
/datum/uplink_item/proc/get_discount()
return pick(4;0.75,2;0.5,1;0.25)
-/datum/uplink_item/proc/spawn_item(turf/loc, obj/item/device/uplink/U)
+/datum/uplink_item/proc/spawn_item(turf/loc, datum/component/uplink/U, mob/user)
if(item)
- SSblackbox.record_feedback("nested tally", "traitor_uplink_items_bought", 1, list("[initial(name)]", "[cost]"))
return new item(loc)
-/datum/uplink_item/proc/buy(mob/user, obj/item/device/uplink/U)
- if(!istype(U))
- return
- if (!user || user.incapacitated())
- return
-
- if(U.telecrystals < cost || limited_stock == 0)
- return
- else
- U.telecrystals -= cost
- U.spent_telecrystals += cost
-
- var/atom/A = spawn_item(get_turf(user), U)
- var/obj/item/storage/box/B = A
- if(istype(B) && B.contents.len > 0)
- for(var/obj/item/I in B)
- U.purchase_log += "[icon2base64html(I)]"
- else
- if(purchase_log_vis)
- U.purchase_log += "[icon2base64html(A)]"
-
- if(limited_stock > 0)
- limited_stock -= 1
-
- if(ishuman(user) && istype(A, /obj/item))
- var/mob/living/carbon/human/H = user
- if(H.put_in_hands(A))
- to_chat(H, "[A] materializes into your hands!")
- else
- to_chat(H, "\The [A] materializes onto the floor.")
- return 1
-
/datum/uplink_item/Destroy()
if(src in GLOB.uplink_items)
GLOB.uplink_items -= src //Take us out instead of leaving a null!
@@ -368,7 +335,7 @@ GLOBAL_LIST_EMPTY(uplink_items) // Global list so we only initialize this once.
cost = 12
surplus = 35
include_modes = list(/datum/game_mode/nuclear)
-
+
/datum/uplink_item/dangerous/guardian
name = "Holoparasites"
desc = "Though capable of near sorcerous feats via use of hardlight holograms and nanomachines, they require an \
@@ -976,8 +943,8 @@ GLOBAL_LIST_EMPTY(uplink_items) // Global list so we only initialize this once.
item = /obj/item/briefcase_launchpad
cost = 6
-/datum/uplink_item/device_tools/briefcase_launchpad/buy(mob/user, obj/item/device/uplink/U)
- var/obj/item/device/launchpad_remote/L = new(get_turf(user)) //free remote
+/datum/uplink_item/device_tools/briefcase_launchpad/spawn_item(turf/loc, datum/component/uplink/U, mob/user)
+ var/obj/item/device/launchpad_remote/L = new(loc) //free remote
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(H.put_in_hands(L))
@@ -1380,7 +1347,7 @@ GLOBAL_LIST_EMPTY(uplink_items) // Global list so we only initialize this once.
exclude_modes = list(/datum/game_mode/nuclear)
cant_discount = TRUE
-/datum/uplink_item/badass/surplus/spawn_item(turf/loc, obj/item/device/uplink/U)
+/datum/uplink_item/badass/surplus/spawn_item(turf/loc, datum/component/uplink/U)
var/list/uplink_items = get_uplink_items(SSticker.mode)
var/crate_value = 50
@@ -1396,7 +1363,7 @@ GLOBAL_LIST_EMPTY(uplink_items) // Global list so we only initialize this once.
continue
crate_value -= I.cost
var/obj/goods = new I.item(C)
- U.purchase_log += "[icon2base64html(goods)]"
+ U.purchase_log.LogPurchase(goods, I.cost)
SSblackbox.record_feedback("nested tally", "traitor_uplink_items_bought", 1, list("[initial(name)]", "[cost]"))
return C
@@ -1408,7 +1375,7 @@ GLOBAL_LIST_EMPTY(uplink_items) // Global list so we only initialize this once.
cost = 0
cant_discount = TRUE
-/datum/uplink_item/badass/random/spawn_item(turf/loc, obj/item/device/uplink/U)
+/datum/uplink_item/badass/random/spawn_item(turf/loc, datum/component/uplink/U)
var/list/uplink_items = get_uplink_items(SSticker.mode)
var/list/possible_items = list()
for(var/category in uplink_items)
diff --git a/code/datums/uplink_purchase_log.dm b/code/datums/uplink_purchase_log.dm
new file mode 100644
index 000000000000..5ec462d237a1
--- /dev/null
+++ b/code/datums/uplink_purchase_log.dm
@@ -0,0 +1,64 @@
+GLOBAL_LIST(uplink_purchase_logs_by_key) //assoc key = /datum/uplink_purchase_log
+
+/datum/uplink_purchase_log
+ var/owner
+ var/list/purchase_log //assoc path-of-item = /datum/uplink_purchase_entry
+ var/datum/component/uplink/parent
+ var/total_spent = 0
+
+/datum/uplink_purchase_log/New(_owner, datum/component/uplink/_parent)
+ owner = _owner
+ parent = _parent
+ LAZYINITLIST(GLOB.uplink_purchase_logs_by_key)
+ if(owner)
+ if(GLOB.uplink_purchase_logs_by_key[owner])
+ stack_trace("WARNING: DUPLICATE PURCHASE LOGS DETECTED. [_owner] [_parent] [_parent.type]")
+ MergeWithAndDel(GLOB.uplink_purchase_logs_by_key[owner])
+ GLOB.uplink_purchase_logs_by_key[owner] = src
+ purchase_log = list()
+
+/datum/uplink_purchase_log/Destroy()
+ purchase_log = null
+ parent = null
+ return ..()
+
+/datum/uplink_purchase_log/proc/MergeWithAndDel(datum/uplink_purchase_log/other)
+ if(!istype(other))
+ return
+ . = owner == other.owner
+ if(!.)
+ return
+ for(var/path in other.purchase_log)
+ if(!purchase_log[path])
+ purchase_log[path] = other.purchase_log[path]
+ else
+ var/datum/uplink_purchase_entry/UPE = purchase_log[path]
+ var/datum/uplink_purchase_entry/UPE_O = other.purchase_log[path]
+ UPE.amount_purchased += UPE_O.amount_purchased
+ qdel(other)
+
+/datum/uplink_purchase_log/proc/TotalTelecrystalsSpent()
+ . = total_spent
+
+/datum/uplink_purchase_log/proc/generate_render(show_key = TRUE)
+ . = ""
+ for(var/path in purchase_log)
+ var/datum/uplink_purchase_entry/UPE = purchase_log[path]
+ . += "\[[UPE.icon_b64][show_key?"([owner])":""]\]"
+
+/datum/uplink_purchase_log/proc/LogPurchase(atom/A, cost)
+ var/datum/uplink_purchase_entry/UPE
+ if(purchase_log[A.type])
+ UPE = purchase_log[A.type]
+ else
+ UPE = new
+ purchase_log[A.type] = UPE
+ UPE.path = A.type
+ UPE.icon_b64 = "[icon2base64html(A)]"
+ UPE.amount_purchased++
+ total_spent += cost
+
+/datum/uplink_purchase_entry
+ var/amount_purchased = 0
+ var/path
+ var/icon_b64
diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm
index 1e5d899bfae1..94c372ef2305 100644
--- a/code/game/gamemodes/nuclear/nuclear.dm
+++ b/code/game/gamemodes/nuclear/nuclear.dm
@@ -264,10 +264,11 @@
var/TC_uses = 0
for(var/datum/mind/syndicate in syndicates)
text += printplayer(syndicate)
- for(var/obj/item/device/uplink/H in GLOB.uplinks)
- if(H && H.owner && H.owner == syndicate.key)
- TC_uses += H.spent_telecrystals
- purchases += H.purchase_log
+ for(var/datum/component/uplink/H in GLOB.uplinks)
+ if(H.purchase_log)
+ purchases += H.purchase_log.generate_render()
+ else
+ stack_trace("WARNING: Uplink with no purchase_log in nuclear mode! Owner: [H.owner]")
text += "
"
text += "(Syndicates used [TC_uses] TC) [purchases]"
if(TC_uses == 0 && station_was_nuked && !are_operatives_dead())
@@ -325,9 +326,7 @@
R.freqlock = 1
if(tc)
- var/obj/item/device/radio/uplink/nuclear/U = new(H)
- U.hidden_uplink.owner = "[H.key]"
- U.hidden_uplink.telecrystals = tc
+ var/obj/item/device/radio/uplink/nuclear/U = new(H, H.key, tc)
H.equip_to_slot_or_del(U, slot_in_backpack)
var/obj/item/implant/weapons_auth/W = new/obj/item/implant/weapons_auth(H)
diff --git a/code/game/gamemodes/nuclear/nuclear_challenge.dm b/code/game/gamemodes/nuclear/nuclear_challenge.dm
index c9314ece1a0c..58128b89cee5 100644
--- a/code/game/gamemodes/nuclear/nuclear_challenge.dm
+++ b/code/game/gamemodes/nuclear/nuclear_challenge.dm
@@ -54,10 +54,7 @@
var/obj/item/circuitboard/computer/syndicate_shuttle/board = V
board.challenge = TRUE
- var/obj/item/device/radio/uplink/nuclear/U = new(get_turf(user))
- U.hidden_uplink.owner = "[user.key]"
- U.hidden_uplink.telecrystals = CHALLENGE_TELECRYSTALS
- U.hidden_uplink.set_gamemode(/datum/game_mode/nuclear)
+ new /obj/item/device/radio/uplink/nuclear(get_turf(user), user.key, CHALLENGE_TELECRYSTALS)
CONFIG_SET(number/shuttle_refuel_delay, max(CONFIG_GET(number/shuttle_refuel_delay), CHALLENGE_SHUTTLE_DELAY))
SSblackbox.record_feedback("amount", "nuclear_challenge_mode", 1)
@@ -66,22 +63,22 @@
/obj/item/device/nuclear_challenge/proc/check_allowed(mob/living/user)
if(declaring_war)
to_chat(user, "You are already in the process of declaring war! Make your mind up.")
- return 0
+ return FALSE
if(GLOB.player_list.len < CHALLENGE_MIN_PLAYERS)
to_chat(user, "The enemy crew is too small to be worth declaring war on.")
- return 0
+ return FALSE
if(user.z != ZLEVEL_CENTCOM)
to_chat(user, "You have to be at your base to use this.")
- return 0
+ return FALSE
if(world.time-SSticker.round_start_time > CHALLENGE_TIME_LIMIT)
to_chat(user, "It's too late to declare hostilities. Your benefactors are already busy with other schemes. You'll have to make do with what you have on hand.")
- return 0
+ return FALSE
for(var/V in GLOB.syndicate_shuttle_boards)
var/obj/item/circuitboard/computer/syndicate_shuttle/board = V
if(board.moved)
to_chat(user, "The shuttle has already been moved! You have forfeit the right to declare war.")
- return 0
- return 1
+ return FALSE
+ return TRUE
#undef CHALLENGE_TELECRYSTALS
#undef CHALLENGE_MIN_PLAYERS
diff --git a/code/game/gamemodes/sandbox/h_sandbox.dm b/code/game/gamemodes/sandbox/h_sandbox.dm
index cf2b8679419d..101a33e55152 100644
--- a/code/game/gamemodes/sandbox/h_sandbox.dm
+++ b/code/game/gamemodes/sandbox/h_sandbox.dm
@@ -28,7 +28,7 @@ GLOBAL_VAR_INIT(hsboxspawn, TRUE)
var/global/list/spawn_forbidden = list(
/obj/item/tk_grab, /obj/item/implant, // not implanter, the actual thing that is inside you
/obj/item/assembly, /obj/item/device/onetankbomb, /obj/item/radio, /obj/item/device/pda/ai,
- /obj/item/device/uplink, /obj/item/smallDelivery, /obj/item/projectile,
+ /obj/item/smallDelivery, /obj/item/projectile,
/obj/item/borg/sight, /obj/item/borg/stun, /obj/item/robot_module)
/datum/hSB/proc/update()
diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm
index a72facc59ea8..c687c0305383 100644
--- a/code/game/gamemodes/traitor/traitor.dm
+++ b/code/game/gamemodes/traitor/traitor.dm
@@ -103,11 +103,11 @@
var/TC_uses = 0
var/uplink_true = FALSE
var/purchases = ""
- for(var/obj/item/device/uplink/H in GLOB.uplinks)
+ for(var/datum/component/uplink/H in GLOB.uplinks)
if(H && H.owner && H.owner == traitor.key)
TC_uses += H.spent_telecrystals
uplink_true = TRUE
- purchases += H.purchase_log
+ purchases += H.purchase_log.generate_render(FALSE)
var/objectives = ""
if(traitor.objectives.len)//If the traitor had no objectives, don't need to process this.
diff --git a/code/game/machinery/computer/telecrystalconsoles.dm b/code/game/machinery/computer/telecrystalconsoles.dm
index 420dc435278d..b0714217f9ec 100644
--- a/code/game/machinery/computer/telecrystalconsoles.dm
+++ b/code/game/machinery/computer/telecrystalconsoles.dm
@@ -33,7 +33,8 @@ GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","E
if(uplinkholder)
to_chat(user, "[src] already has an uplink in it.")
return
- if(I.hidden_uplink)
+ GET_COMPONENT_FROM(hidden_uplink, /datum/component/uplink, I)
+ if(hidden_uplink)
if(!user.transferItemToLoc(I, src))
return
uplinkholder = I
@@ -56,26 +57,28 @@ GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","E
/obj/machinery/computer/telecrystals/uplinker/proc/donateTC(amt, addLog = 1)
if(uplinkholder && linkedboss)
+ GET_COMPONENT_FROM(hidden_uplink, /datum/component/uplink, uplinkholder)
if(amt < 0)
- linkedboss.storedcrystals += uplinkholder.hidden_uplink.telecrystals
+ linkedboss.storedcrystals += hidden_uplink.telecrystals
if(addLog)
- linkedboss.logTransfer("[src] donated [uplinkholder.hidden_uplink.telecrystals] telecrystals to [linkedboss].")
- uplinkholder.hidden_uplink.telecrystals = 0
- else if(amt <= uplinkholder.hidden_uplink.telecrystals)
- uplinkholder.hidden_uplink.telecrystals -= amt
+ linkedboss.logTransfer("[src] donated [hidden_uplink.telecrystals] telecrystals to [linkedboss].")
+ hidden_uplink.telecrystals = 0
+ else if(amt <= hidden_uplink.telecrystals)
+ hidden_uplink.telecrystals -= amt
linkedboss.storedcrystals += amt
if(addLog)
linkedboss.logTransfer("[src] donated [amt] telecrystals to [linkedboss].")
/obj/machinery/computer/telecrystals/uplinker/proc/giveTC(amt, addLog = 1)
if(uplinkholder && linkedboss)
+ GET_COMPONENT_FROM(hidden_uplink, /datum/component/uplink, uplinkholder)
if(amt < 0)
- uplinkholder.hidden_uplink.telecrystals += linkedboss.storedcrystals
+ hidden_uplink.telecrystals += linkedboss.storedcrystals
if(addLog)
linkedboss.logTransfer("[src] received [linkedboss.storedcrystals] telecrystals from [linkedboss].")
linkedboss.storedcrystals = 0
else if(amt <= linkedboss.storedcrystals)
- uplinkholder.hidden_uplink.telecrystals += amt
+ hidden_uplink.telecrystals += amt
linkedboss.storedcrystals -= amt
if(addLog)
linkedboss.logTransfer("[src] received [amt] telecrystals from [linkedboss].")
@@ -95,7 +98,8 @@ GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","E
dat += "No linked management consoles detected. Scan for uplink stations using the management console.
"
if(uplinkholder)
- dat += "[uplinkholder.hidden_uplink.telecrystals] telecrystals remain in this uplink.
"
+ GET_COMPONENT_FROM(hidden_uplink, /datum/component/uplink, uplinkholder)
+ dat += "[hidden_uplink.telecrystals] telecrystals remain in this uplink.
"
if(linkedboss)
dat += "Donate TC: 1 | 5 | All"
dat += "
Eject Uplink"
@@ -175,7 +179,8 @@ GLOBAL_LIST_INIT(possible_uplinker_IDs, list("Alfa","Bravo","Charlie","Delta","E
for(var/obj/machinery/computer/telecrystals/uplinker/A in TCstations)
dat += "[A.name] | "
if(A.uplinkholder)
- dat += "[A.uplinkholder.hidden_uplink.telecrystals] telecrystals."
+ GET_COMPONENT_FROM(hidden_uplink, /datum/component/uplink, A.uplinkholder)
+ dat += "[hidden_uplink.telecrystals] telecrystals."
if(storedcrystals)
dat+= "
Add TC: 1 | 5 | 10 | All"
dat += "
"
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 17bb5923741e..df4bd8d4c8b7 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -57,7 +57,6 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
var/slowdown = 0 // How much clothing is slowing you down. Negative values speeds you up
var/armour_penetration = 0 //percentage of armour effectiveness to remove
var/list/allowed = null //suit storage stuff.
- var/obj/item/device/uplink/hidden_uplink = null
var/equip_delay_self = 0 //In deciseconds, how long an item takes to equip; counts only for normal clothing slots, not pockets etc.
var/equip_delay_other = 20 //In deciseconds, how long an item takes to put on another person
var/strip_delay = 40 //In deciseconds, how long an item takes to remove from another person
@@ -228,9 +227,6 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE)
/obj/item/interact(mob/user)
add_fingerprint(user)
- if(hidden_uplink && hidden_uplink.active)
- hidden_uplink.interact(user)
- return 1
ui_interact(user)
/obj/item/ui_act(action, params)
diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm
index 771cdf7c2ee9..1f7fd77c4aca 100644
--- a/code/game/objects/items/devices/PDA/PDA.dm
+++ b/code/game/objects/items/devices/PDA/PDA.dm
@@ -158,15 +158,13 @@ GLOBAL_LIST_EMPTY(PDAs)
to_chat(user, "You don't have the dexterity to do this!")
return
+ . = ..()
+
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/pda)
assets.send(user)
user.set_machine(src)
- if(hidden_uplink && hidden_uplink.active)
- hidden_uplink.interact(user)
- return
-
var/dat = "