and that just leaves the modules folder

This commit is contained in:
deathride58
2018-07-02 00:28:51 -04:00
parent 63013f8964
commit 91805b8789
231 changed files with 1508 additions and 693 deletions
+15 -8
View File
@@ -46,10 +46,13 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo
* `null` means exact match on `type` (default)
* Any other type means that and all subtypes
1. `/datum/component/var/list/signal_procs` (private)
* Associated lazy list of signals -> `/datum/callback`s that will be run when the parent datum recieves that signal
* Associated lazy list of signals -> `/datum/callback`s that will be run when the parent datum receives that signal
1. `/datum/component/var/datum/parent` (protected, read-only)
* The datum this component belongs to
* Never `null` in child procs
1. `report_signal_origin` (protected, boolean)
* If `TRUE`, will invoke the callback when signalled with the signal type as the first argument.
* `FALSE` by default.
### Procs
@@ -61,6 +64,11 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo
* Returns a reference to a component whose type MATCHES component_type if that component exists in the datum, null otherwise
1. `GET_COMPONENT(varname, component_type)` OR `GET_COMPONENT_FROM(varname, component_type, src)`
* Shorthand for `var/component_type/varname = src.GetComponent(component_type)`
1. `SEND_SIGNAL(target, sigtype, ...)` (public, final)
* Use to send signals to target datum
* Extra arguments are to be specified in the signal definition
* Returns a bitflag with signal specific information assembled from all activated components
* Arguments are packaged in a list and handed off to _SendSignal()
1. `/datum/proc/AddComponent(component_type(type), ...) -> datum/component` (public, final)
* Creates an instance of `component_type` in the datum and passes `...` to its `Initialize()` call
* Sends the `COMSIG_COMPONENT_ADDED` signal to the datum
@@ -71,23 +79,22 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo
1. `/datum/proc/LoadComponent(component_type(type), ...) -> datum/component` (public, final)
* Equivalent to calling `GetComponent(component_type)` where, if the result would be `null`, returns `AddComponent(component_type, ...)` instead
1. `/datum/proc/ComponentActivated(datum/component/C)` (abstract, async)
* Called on a component's `parent` after a signal recieved causes it to activate. `src` is the parameter
* Called on a component's `parent` after a signal received causes it to activate. `src` is the parameter
* Will only be called if a component's callback returns `TRUE`
1. `/datum/proc/TakeComponent(datum/component/C)` (public, final)
* Properly transfers ownership of a component from one datum to another
* Signals `COMSIG_COMPONENT_REMOVING` on the parent
* Called on the datum you want to own the component with another datum's component
1. `/datum/proc/SendSignal(signal, ...)` (public, final)
* Call to send a signal to the components of the target datum
* Extra arguments are to be specified in the signal definition
* Returns a bitflag with signal specific information assembled from all activated components
1. `/datum/proc/_SendSignal(signal, list/arguments)` (private, final)
* Handles most of the actual signaling procedure
* Will runtime if used on datums with an empty component list
1. `/datum/component/New(datum/parent, ...)` (private, final)
* Runs internal setup for the component
* Extra arguments are passed to `Initialize()`
1. `/datum/component/Initialize(...)` (abstract, no-sleep)
* Called by `New()` with the same argments excluding `parent`
* Component does not exist in `parent`'s `datum_components` list yet, although `parent` is set and may be used
* Signals will not be recieved while this function is running
* Signals will not be received while this function is running
* Component may be deleted after this function completes without being attached
* Do not call `qdel(src)` from this function
1. `/datum/component/Destroy(force(bool), silent(bool))` (virtual, no-sleep)
@@ -111,7 +118,7 @@ Stands have a lot of procs which mimic mob procs. Rather than inserting hooks fo
1. `/datum/component/proc/RegisterSignal(signal(string/list of strings), proc_ref(type), override(boolean))` (protected, final) (Consider removing for performance gainz)
* If signal is a list it will be as if RegisterSignal was called for each of the entries with the same following arguments
* Makes a component listen for the specified `signal` on it's `parent` datum.
* When that signal is recieved `proc_ref` will be called on the component, along with associated arguments
* When that signal is received `proc_ref` will be called on the component, along with associated arguments
* Example proc ref: `.proc/OnEvent`
* If a previous registration is overwritten by the call, a runtime occurs. Setting `override` to TRUE prevents this
* These callbacks run asyncronously
+6 -10
View File
@@ -56,7 +56,7 @@
if(!force)
_RemoveFromParent()
if(!silent)
P.SendSignal(COMSIG_COMPONENT_REMOVING, src)
SEND_SIGNAL(P, COMSIG_COMPONENT_REMOVING, src)
parent = null
SSdcs.UnregisterSignal(src, signal_procs)
LAZYCLEARLIST(signal_procs)
@@ -96,7 +96,7 @@
if(sig_type[1] == "!")
SSdcs.RegisterSignal(src, sig_type)
procs[sig_type] = proc_or_callback
enabled = TRUE
@@ -125,12 +125,8 @@
current_type = type2parent(current_type)
. += current_type
/datum/proc/SendSignal(sigtype, ...)
var/list/comps = datum_components
if(!comps)
return NONE
var/list/arguments = args.Copy(2)
var/target = comps[/datum/component]
/datum/proc/_SendSignal(sigtype, list/arguments)
var/target = datum_components[/datum/component]
if(!length(target))
var/datum/component/C = target
if(!C.enabled)
@@ -228,7 +224,7 @@
new_comp = new nt(arglist(args)) // Dupes are allowed, act like normal
if(!old_comp && !QDELETED(new_comp)) // Nothing related to duplicate components happened and the new component is healthy
SendSignal(COMSIG_COMPONENT_ADDED, new_comp)
SEND_SIGNAL(src, COMSIG_COMPONENT_ADDED, new_comp)
return new_comp
return old_comp
@@ -243,7 +239,7 @@
var/datum/old_parent = parent
PreTransfer()
_RemoveFromParent()
old_parent.SendSignal(COMSIG_COMPONENT_REMOVING, src)
SEND_SIGNAL(old_parent, COMSIG_COMPONENT_REMOVING, src)
/datum/proc/TakeComponent(datum/component/target)
if(!target)
+7 -7
View File
@@ -12,13 +12,13 @@
if(!isturf(tile))
return
tile.SendSignal(COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
SEND_SIGNAL(tile, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
for(var/A in tile)
if(is_cleanable(A))
qdel(A)
else if(istype(A, /obj/item))
var/obj/item/I = A
I.SendSignal(COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
SEND_SIGNAL(I, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
if(ismob(I.loc))
var/mob/M = I.loc
M.regenerate_icons()
@@ -26,14 +26,14 @@
var/mob/living/carbon/human/cleaned_human = A
if(cleaned_human.lying)
if(cleaned_human.head)
cleaned_human.head.SendSignal(COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
SEND_SIGNAL(cleaned_human.head, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
if(cleaned_human.wear_suit)
cleaned_human.wear_suit.SendSignal(COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
SEND_SIGNAL(cleaned_human.wear_suit, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
else if(cleaned_human.w_uniform)
cleaned_human.w_uniform.SendSignal(COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
SEND_SIGNAL(cleaned_human.w_uniform, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
if(cleaned_human.shoes)
cleaned_human.shoes.SendSignal(COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
cleaned_human.SendSignal(COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
SEND_SIGNAL(cleaned_human.shoes, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
SEND_SIGNAL(cleaned_human, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
cleaned_human.wash_cream()
cleaned_human.regenerate_icons()
to_chat(cleaned_human, "<span class='danger'>[AM] cleans your face!</span>")
+8
View File
@@ -0,0 +1,8 @@
/datum/component/forced_gravity
var/gravity = 1
var/ignore_space = FALSE //If forced gravity should also work on space turfs
/datum/component/forced_gravity/Initialize(forced_value = 1)
if(!isatom(parent))
return COMPONENT_INCOMPATIBLE
gravity = forced_value
+1 -1
View File
@@ -58,7 +58,7 @@
return
if(user.a_intent != INTENT_HELP)
return
if(I.flags_1 & ABSTRACT_1)
if(I.item_flags & ABSTRACT)
return
if((I.flags_1 & HOLOGRAM_1) || (I.item_flags & NO_MAT_REDEMPTION) || (tc && !is_type_in_typecache(I, tc)))
to_chat(user, "<span class='warning'>[parent] won't accept [I]!</span>")
+7 -7
View File
@@ -1,8 +1,8 @@
//Thing meant for allowing datums and objects to access a NTnet network datum.
/datum/proc/ntnet_recieve(datum/netdata/data)
/datum/proc/ntnet_receive(datum/netdata/data)
return
/datum/proc/ntnet_recieve_broadcast(datum/netdata/data)
/datum/proc/ntnet_receive_broadcast(datum/netdata/data)
return
/datum/proc/ntnet_send(datum/netdata/data, netid)
@@ -15,7 +15,7 @@
var/hardware_id //text. this is the true ID. do not change this. stuff like ID forgery can be done manually.
var/network_name = "" //text
var/list/networks_connected_by_id = list() //id = datum/ntnet
var/differentiate_broadcast = TRUE //If false, broadcasts go to ntnet_recieve. NOT RECOMMENDED.
var/differentiate_broadcast = TRUE //If false, broadcasts go to ntnet_receive. NOT RECOMMENDED.
/datum/component/ntnet_interface/Initialize(force_name = "NTNet Device", autoconnect_station_network = TRUE) //Don't force ID unless you know what you're doing!
hardware_id = "[SSnetworks.get_next_HID()]"
@@ -31,12 +31,12 @@
SSnetworks.unregister_interface(src)
return ..()
/datum/component/ntnet_interface/proc/__network_recieve(datum/netdata/data) //Do not directly proccall!
parent.SendSignal(COMSIG_COMPONENT_NTNET_RECIEVE, data)
/datum/component/ntnet_interface/proc/__network_receive(datum/netdata/data) //Do not directly proccall!
SEND_SIGNAL(parent, COMSIG_COMPONENT_NTNET_RECEIVE, data)
if(differentiate_broadcast && data.broadcast)
parent.ntnet_recieve_broadcast(data)
parent.ntnet_receive_broadcast(data)
else
parent.ntnet_recieve(data)
parent.ntnet_receive(data)
/datum/component/ntnet_interface/proc/__network_send(datum/netdata/data, netid) //Do not directly proccall!
// Process data before sending it
+1 -1
View File
@@ -307,7 +307,7 @@
icon = 'icons/obj/items_and_weapons.dmi'
icon_state = "offhand"
w_class = WEIGHT_CLASS_HUGE
flags_1 = ABSTRACT_1 | DROPDEL_1 | NOBLUDGEON_1
item_flags = ABSTRACT | DROPDEL | NOBLUDGEON
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
var/mob/living/carbon/rider
var/mob/living/parent
+18
View File
@@ -59,6 +59,24 @@
if(src.rotation_flags & ROTATION_COUNTERCLOCKWISE)
AM.verbs += /atom/movable/proc/simple_rotate_counterclockwise
/datum/component/simple_rotation/proc/remove_verbs()
if(parent)
var/atom/movable/AM = parent
AM.verbs -= /atom/movable/proc/simple_rotate_flip
AM.verbs -= /atom/movable/proc/simple_rotate_clockwise
AM.verbs -= /atom/movable/proc/simple_rotate_counterclockwise
/datum/component/simple_rotation/Destroy()
remove_verbs()
QDEL_NULL(can_user_rotate)
QDEL_NULL(can_be_rotated)
QDEL_NULL(after_rotation)
. = ..()
/datum/component/simple_rotation/RemoveComponent()
remove_verbs()
. = ..()
/datum/component/simple_rotation/proc/ExamineMessage(mob/user)
if(rotation_flags & ROTATION_ALTCLICK)
to_chat(user, "<span class='notice'>Alt-click to rotate it clockwise.</span>")
@@ -2,7 +2,7 @@
var/atom/A = parent
if((istype(W, /obj/item/storage/backpack/holding) || count_by_type(W.GetAllContents(), /obj/item/storage/backpack/holding)))
var/safety = alert(user, "Doing this will have extremely dire consequences for the station and its crew. Be sure you know what you're doing.", "Put in [A.name]?", "Abort", "Proceed")
if(safety == "Abort" || !in_range(A, user) || !A || !W || user.incapacitated())
if(safety != "Proceed" || QDELETED(A) || QDELETED(W) || QDELETED(user) || !user.canUseTopic(A, BE_CLOSE, iscarbon(user)))
return
var/turf/loccheck = get_turf(A)
if(is_reebe(loccheck.z))
@@ -54,12 +54,18 @@
/datum/component/storage/concrete/pockets/pocketprotector
max_items = 3
max_w_class = WEIGHT_CLASS_TINY
var/atom/original_parent
/datum/component/storage/concrete/pockets/pocketprotector/Initialize()
original_parent = parent
. = ..()
can_hold = typecacheof(list( //Same items as a PDA
/obj/item/pen,
/obj/item/toy/crayon,
/obj/item/lipstick,
/obj/item/flashlight/pen,
/obj/item/clothing/mask/cigarette))
/obj/item/clothing/mask/cigarette))
/datum/component/storage/concrete/pockets/pocketprotector/real_location()
// if the component is reparented to a jumpsuit, the items still go in the protector
return original_parent
@@ -20,7 +20,7 @@
allow_quick_gather = TRUE
allow_quick_empty = TRUE
click_gather = TRUE
max_w_class = WEIGHT_CLASS_NORMAL
max_w_class = WEIGHT_CLASS_BULKY // can fit vending refills
max_combined_w_class = 800
max_items = 400
display_numerical_stacking = TRUE
@@ -29,5 +29,5 @@
. = ..()
if(!I.get_part_rating())
if (!stop_messages)
to_chat(M, "<span class='warning'>[parent] only accepts machine par ts!</span>")
to_chat(M, "<span class='warning'>[parent] only accepts machine parts!</span>")
return FALSE
+13 -14
View File
@@ -98,7 +98,7 @@
RegisterSignal(COMSIG_CLICK_ALT, .proc/on_alt_click)
RegisterSignal(COMSIG_MOUSEDROP_ONTO, .proc/mousedrop_onto)
RegisterSignal(COMSIG_MOUSEDROPPED_ONTO, .proc/mousedrop_recieve)
RegisterSignal(COMSIG_MOUSEDROPPED_ONTO, .proc/mousedrop_receive)
update_actions()
@@ -125,11 +125,13 @@
modeswitch_action.Grant(M)
/datum/component/storage/proc/change_master(datum/component/storage/concrete/new_master)
if(!istype(new_master))
if(new_master == src || (!isnull(new_master) && !istype(new_master)))
return FALSE
master.on_slave_unlink(src)
if(master)
master.on_slave_unlink(src)
master = new_master
master.on_slave_link(src)
if(master)
master.on_slave_link(src)
return TRUE
/datum/component/storage/proc/master()
@@ -149,7 +151,7 @@
quick_empty(M)
/datum/component/storage/proc/preattack_intercept(obj/O, mob/M, params)
if(!isitem(O) || !click_gather || O.SendSignal(COMSIG_CONTAINS_STORAGE))
if(!isitem(O) || !click_gather || SEND_SIGNAL(O, COMSIG_CONTAINS_STORAGE))
return FALSE
. = COMPONENT_NO_ATTACK
if(locked)
@@ -466,7 +468,7 @@
if(recursive)
for(var/i in ret.Copy())
var/atom/A = i
A.SendSignal(COMSIG_TRY_STORAGE_RETURN_INVENTORY, ret, TRUE)
SEND_SIGNAL(A, COMSIG_TRY_STORAGE_RETURN_INVENTORY, ret, TRUE)
return ret
/datum/component/storage/proc/contents() //ONLY USE IF YOU NEED TO COPY CONTENTS OF REAL LOCATION, COPYING IS NOT AS FAST AS DIRECT ACCESS!
@@ -517,19 +519,19 @@
if(force || M.CanReach(parent, view_only = TRUE))
show_to(M)
/datum/component/storage/proc/mousedrop_recieve(atom/movable/O, mob/M)
/datum/component/storage/proc/mousedrop_receive(atom/movable/O, mob/M)
if(isitem(O))
var/obj/item/I = O
if(iscarbon(M) || isdrone(M))
var/mob/living/L = M
if(!L.incapacitated() && I == L.get_active_held_item())
if(!I.SendSignal(COMSIG_CONTAINS_STORAGE) && can_be_inserted(I, FALSE)) //If it has storage it should be trying to dump, not insert.
if(!SEND_SIGNAL(I, COMSIG_CONTAINS_STORAGE) && can_be_inserted(I, FALSE)) //If it has storage it should be trying to dump, not insert.
handle_item_insertion(I, FALSE, L)
//This proc return 1 if the item can be picked up and 0 if it can't.
//Set the stop_messages to stop it from printing messages
/datum/component/storage/proc/can_be_inserted(obj/item/I, stop_messages = FALSE, mob/M)
if(!istype(I) || (I.flags_1 & ABSTRACT_1))
if(!istype(I) || (I.item_flags & ABSTRACT))
return FALSE //Not an item
if(I == parent)
return FALSE //no paradoxes for you
@@ -573,7 +575,7 @@
if(!stop_messages)
to_chat(M, "<span class='warning'>[IP] cannot hold [I] as it's a storage item of the same size!</span>")
return FALSE //To prevent the stacking of same sized storage items.
if(I.flags_1 & NODROP_1) //SHOULD be handled in unEquip, but better safe than sorry.
if(I.item_flags & NODROP) //SHOULD be handled in unEquip, but better safe than sorry.
to_chat(M, "<span class='warning'>\the [I] is stuck to your hand, you can't put it in \the [host]!</span>")
return FALSE
var/datum/component/storage/concrete/master = master()
@@ -639,10 +641,7 @@
/datum/component/storage/proc/signal_take_type(type, atom/destination, amount = INFINITY, check_adjacent = FALSE, force = FALSE, mob/user, list/inserted)
if(!force)
if(check_adjacent)
if(user)
if(!user.CanReach(destination) || !user.CanReach(parent))
return FALSE
else if(!destination.CanReachStorage(parent))
if(!user || !user.CanReach(destination) || !user.CanReach(parent))
return FALSE
var/list/taking = typecache_filter_list(contents(), typecacheof(type))
if(length(taking) > amount)
+1 -1
View File
@@ -60,7 +60,7 @@
if(amount >= 50)
var/burning_time = max(100, 100-amount)
master = master.ScrapeAway()
master = master.Melt()
master.burn_tile()
if(user)
master.add_hiddenprint(user)
+250
View File
@@ -0,0 +1,250 @@
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/allow_restricted = TRUE
var/telecrystals
var/selected_cat
var/owner = null
var/datum/game_mode/gamemode
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
RegisterSignal(COMSIG_PARENT_ATTACKBY, .proc/OnAttackBy)
RegisterSignal(COMSIG_ITEM_ATTACK_SELF, .proc/interact)
if(istype(parent, /obj/item/implant))
RegisterSignal(COMSIG_IMPLANT_ACTIVATED, .proc/implant_activation)
RegisterSignal(COMSIG_IMPLANT_IMPLANTING, .proc/implanting)
RegisterSignal(COMSIG_IMPLANT_OTHER, .proc/old_implant)
RegisterSignal(COMSIG_IMPLANT_EXISTING_UPLINK, .proc/new_implant)
else if(istype(parent, /obj/item/pda))
RegisterSignal(COMSIG_PDA_CHANGE_RINGTONE, .proc/new_ringtone)
else if(istype(parent, /obj/item/radio))
RegisterSignal(COMSIG_RADIO_NEW_FREQUENCY, .proc/new_frequency)
else if(istype(parent, /obj/item/pen))
RegisterSignal(COMSIG_PEN_ROTATED, .proc/pen_rotation)
GLOB.uplinks += src
uplink_items = get_uplink_items(gamemode, TRUE, allow_restricted)
if(_owner)
owner = _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, "<span class='notice'>You slot [TC] into [parent] and charge its internal uplink.</span>")
var/amt = TC.amount
telecrystals += amt
TC.use(amt)
/datum/component/uplink/proc/set_gamemode(_gamemode)
gamemode = _gamemode
uplink_items = get_uplink_items(gamemode, TRUE, allow_restricted)
/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/category in uplink_items)
for(var/item in uplink_items[category])
var/datum/uplink_item/UI = uplink_items[category][item]
var/path = UI.refund_path || UI.item
var/cost = UI.refund_amount || UI.cost
if(I.type == path && UI.refundable && I.check_uplink_validity())
telecrystals += cost
purchase_log.total_spent -= cost
to_chat(user, "<span class='notice'>[I] refunded.</span>")
qdel(I)
return
/datum/component/uplink/proc/interact(mob/user)
if(locked)
return
active = TRUE
if(user)
ui_interact(user)
// an unlocked uplink blocks also opening the PDA or headset menu
return COMPONENT_NO_INTERACT
/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
U.purchase(user, src)
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]"))
return TRUE
// Implant signal responses
/datum/component/uplink/proc/implant_activation()
var/obj/item/implant/implant = parent
locked = FALSE
interact(implant.imp_in)
/datum/component/uplink/proc/implanting(list/arguments)
var/mob/user = arguments[2]
owner = "[user.key]"
/datum/component/uplink/proc/old_implant(list/arguments, obj/item/implant/new_implant)
// It kinda has to be weird like this until implants are components
return SEND_SIGNAL(new_implant, COMSIG_IMPLANT_EXISTING_UPLINK, src)
/datum/component/uplink/proc/new_implant(datum/component/uplink/uplink)
uplink.telecrystals += telecrystals
return COMPONENT_DELETE_NEW_IMPLANT
// PDA signal responses
/datum/component/uplink/proc/new_ringtone(mob/living/user, new_ring_text)
var/obj/item/pda/master = parent
if(trim(lowertext(new_ring_text)) != trim(lowertext(master.lock_code))) //why is the lock code stored on the pda?
return
locked = FALSE
interact(user)
to_chat(user, "The PDA softly beeps.")
user << browse(null, "window=pda")
master.mode = 0
return COMPONENT_STOP_RINGTONE_CHANGE
// Radio signal responses
/datum/component/uplink/proc/new_frequency(list/arguments)
var/obj/item/radio/master = parent
var/frequency = arguments[1]
if(frequency != master.traitor_frequency)
return
locked = FALSE
if(ismob(master.loc))
interact(master.loc)
// Pen signal responses
/datum/component/uplink/proc/pen_rotation(degrees, mob/living/carbon/user)
var/obj/item/pen/master = parent
if(degrees != master.traitor_unlock_degrees)
return
locked = FALSE
master.degrees = 0
interact(user)
to_chat(user, "<span class='warning'>Your pen makes a clicking noise, before quickly rotating back to 0 degrees!</span>")