and that just leaves the modules folder
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>")
|
||||
|
||||
@@ -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
|
||||
@@ -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>")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>")
|
||||
Reference in New Issue
Block a user