mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-04-24 09:17:33 +01:00
<!-- Write **BELOW** The Headers and **ABOVE** The comments else it may not be viewable. --> <!-- You can view Contributing.MD for a detailed description of the pull request process. --> ## About The Pull Request <!-- Describe The Pull Request. Please be sure every change is documented or this can delay review and even discourage maintainers from merging your PR! --> See title Closes #85542 ## Why It's Good For The Game <!-- Argue for the merits of your changes and how they benefit the game, especially if they are controversial and/or far reaching. If you can't actually explain WHY what you are doing will improve the game, then it probably isn't good for the game in the first place. --> Pretty self-explanatory ## Changelog <!-- If your PR modifies aspects of the game that can be concretely observed by players or admins you should add a changelog. If your change does NOT meet this description, remove this section. Be sure to properly mark your PRs to prevent unnecessary GBP loss. You can read up on GBP and its effects on PRs in the tgstation guides for contributors. Please note that maintainers freely reserve the right to remove and add tags should they deem it appropriate. You can attempt to finagle the system all you want, but it's best to shoot for clear communication right off the bat. --> 🆑 fix: Fixed an infinite TC glitch dupe /🆑 <!-- Both 🆑's are required for the changelog to work! You can put your name to the right of the first 🆑 if you want to overwrite your GitHub username as author ingame. --> <!-- You can use multiple of the same prefix (they're only used for the icon ingame) and delete the unneeded ones. Despite some of the tags, changelogs should generally represent how a player might be affected by the changes rather than a summary of the PR's contents. --> Co-authored-by: Watermelon914 <3052169-Watermelon914@users.noreply.gitlab.com>
526 lines
19 KiB
Plaintext
526 lines
19 KiB
Plaintext
#define PEN_ROTATIONS 2
|
|
|
|
/**
|
|
* 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 its 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
|
|
/// Name of the uplink
|
|
var/name = "syndicate uplink"
|
|
/// Whether the uplink is currently active or not
|
|
var/active = FALSE
|
|
/// Whether this uplink can be locked or not
|
|
var/lockable = TRUE
|
|
/// Whether the uplink is locked or not.
|
|
var/locked = TRUE
|
|
/// Whether this uplink allows restricted items to be accessed
|
|
var/allow_restricted = TRUE
|
|
/// Current owner of the uplink
|
|
var/owner = null
|
|
/// Purchase log, listing all the purchases this uplink has made
|
|
var/datum/uplink_purchase_log/purchase_log
|
|
/// The current linked uplink handler.
|
|
var/datum/uplink_handler/uplink_handler
|
|
/// Code to unlock the uplink.
|
|
var/unlock_code
|
|
/// Used for pen uplink
|
|
var/list/previous_attempts
|
|
|
|
// Not modular variables. These variables should be removed sometime in the future
|
|
|
|
/// The unlock text that is sent to the traitor with this uplink. This is not modular and not recommended to expand upon
|
|
var/unlock_text
|
|
/// The unlock note that is sent to the traitor with this uplink. This is not modular and not recommended to expand upon
|
|
var/unlock_note
|
|
/// The failsafe code that causes this uplink to blow up.
|
|
var/failsafe_code
|
|
|
|
/datum/component/uplink/Initialize(
|
|
owner,
|
|
lockable = TRUE,
|
|
enabled = FALSE,
|
|
uplink_flag = UPLINK_TRAITORS,
|
|
starting_tc = TELECRYSTALS_DEFAULT,
|
|
has_progression = FALSE,
|
|
datum/uplink_handler/uplink_handler_override,
|
|
)
|
|
|
|
if(!isitem(parent))
|
|
return COMPONENT_INCOMPATIBLE
|
|
|
|
RegisterSignal(parent, COMSIG_ATOM_ATTACKBY, PROC_REF(OnAttackBy))
|
|
RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, PROC_REF(interact))
|
|
if(istype(parent, /obj/item/implant))
|
|
RegisterSignal(parent, COMSIG_IMPLANT_ACTIVATED, PROC_REF(implant_activation))
|
|
RegisterSignal(parent, COMSIG_IMPLANT_IMPLANTING, PROC_REF(implanting))
|
|
RegisterSignal(parent, COMSIG_IMPLANT_OTHER, PROC_REF(old_implant))
|
|
RegisterSignal(parent, COMSIG_IMPLANT_EXISTING_UPLINK, PROC_REF(new_implant))
|
|
else if(istype(parent, /obj/item/modular_computer))
|
|
RegisterSignal(parent, COMSIG_TABLET_CHANGE_ID, PROC_REF(new_ringtone))
|
|
RegisterSignal(parent, COMSIG_TABLET_CHECK_DETONATE, PROC_REF(check_detonate))
|
|
else if(istype(parent, /obj/item/radio))
|
|
RegisterSignal(parent, COMSIG_RADIO_NEW_MESSAGE, PROC_REF(new_message))
|
|
else if(istype(parent, /obj/item/pen))
|
|
RegisterSignal(parent, COMSIG_PEN_ROTATED, PROC_REF(pen_rotation))
|
|
else if(istype(parent, /obj/item/uplink/replacement))
|
|
RegisterSignal(parent, COMSIG_MOVABLE_HEAR, PROC_REF(on_heard))
|
|
|
|
if(owner)
|
|
src.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)
|
|
RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine))
|
|
src.lockable = lockable
|
|
src.active = enabled
|
|
if(!uplink_handler_override)
|
|
uplink_handler = new()
|
|
uplink_handler.has_objectives = FALSE
|
|
uplink_handler.uplink_flag = uplink_flag
|
|
uplink_handler.telecrystals = starting_tc
|
|
uplink_handler.has_progression = has_progression
|
|
uplink_handler.purchase_log = purchase_log
|
|
else
|
|
uplink_handler = uplink_handler_override
|
|
RegisterSignal(uplink_handler, COMSIG_UPLINK_HANDLER_ON_UPDATE, PROC_REF(handle_uplink_handler_update))
|
|
RegisterSignal(uplink_handler, COMSIG_UPLINK_HANDLER_REPLACEMENT_ORDERED, PROC_REF(handle_uplink_replaced))
|
|
if(!lockable)
|
|
active = TRUE
|
|
locked = FALSE
|
|
|
|
previous_attempts = list()
|
|
|
|
/datum/component/uplink/proc/handle_uplink_handler_update()
|
|
SIGNAL_HANDLER
|
|
SStgui.update_uis(src)
|
|
|
|
/// When a new uplink is made via the syndicate beacon it locks all lockable uplinks and destroys replacement uplinks
|
|
/datum/component/uplink/proc/handle_uplink_replaced()
|
|
SIGNAL_HANDLER
|
|
if(lockable)
|
|
lock_uplink()
|
|
if(!istype(parent, /obj/item/uplink/replacement))
|
|
return
|
|
var/obj/item/uplink_item = parent
|
|
do_sparks(number = 3, cardinal_only = FALSE, source = uplink_item)
|
|
uplink_item.visible_message(span_warning("The [uplink_item] suddenly combusts!"), vision_distance = COMBAT_MESSAGE_RANGE)
|
|
new /obj/effect/decal/cleanable/ash(get_turf(uplink_item))
|
|
qdel(uplink_item)
|
|
|
|
/datum/component/uplink/InheritComponent(datum/component/uplink/uplink)
|
|
lockable |= uplink.lockable
|
|
active |= uplink.active
|
|
uplink_handler.uplink_flag |= uplink.uplink_handler.uplink_flag
|
|
|
|
/datum/component/uplink/Destroy()
|
|
purchase_log = null
|
|
return ..()
|
|
|
|
/datum/component/uplink/proc/load_tc(mob/user, obj/item/stack/telecrystal/telecrystals, silent = FALSE)
|
|
if(!silent)
|
|
to_chat(user, span_notice("You slot [telecrystals] into [parent] and charge its internal uplink."))
|
|
var/amt = telecrystals.amount
|
|
uplink_handler.add_telecrystals(amt)
|
|
telecrystals.use(amt)
|
|
log_uplink("[key_name(user)] loaded [amt] telecrystals into [parent]'s uplink")
|
|
|
|
/datum/component/uplink/proc/OnAttackBy(datum/source, obj/item/item, mob/user)
|
|
SIGNAL_HANDLER
|
|
if(!active)
|
|
return //no hitting everyone/everything just to try to slot tcs in!
|
|
|
|
if(istype(item, /obj/item/stack/telecrystal))
|
|
load_tc(user, item)
|
|
|
|
if(!istype(item))
|
|
return
|
|
|
|
SEND_SIGNAL(item, COMSIG_ITEM_ATTEMPT_TC_REIMBURSE, user, src)
|
|
|
|
/datum/component/uplink/proc/on_examine(datum/source, mob/user, list/examine_list)
|
|
SIGNAL_HANDLER
|
|
|
|
if(user != owner)
|
|
return
|
|
examine_list += span_warning("[parent] contains your hidden uplink\
|
|
[unlock_code ? ", the code to unlock it is [span_boldwarning(unlock_code)]" : null].")
|
|
|
|
if(failsafe_code)
|
|
examine_list += span_warning("The failsafe code is [span_boldwarning(failsafe_code)].")
|
|
|
|
/datum/component/uplink/proc/interact(datum/source, mob/user)
|
|
SIGNAL_HANDLER
|
|
|
|
if(locked)
|
|
return
|
|
active = TRUE
|
|
if(user)
|
|
INVOKE_ASYNC(src, PROC_REF(ui_interact), user)
|
|
// an unlocked uplink blocks also opening the PDA or headset menu
|
|
return COMPONENT_CANCEL_ATTACK_CHAIN
|
|
|
|
|
|
/datum/component/uplink/ui_state(mob/user)
|
|
return GLOB.inventory_state
|
|
|
|
/datum/component/uplink/ui_interact(mob/user, datum/tgui/ui)
|
|
active = TRUE
|
|
ui = SStgui.try_update_ui(user, src, ui)
|
|
if(!ui)
|
|
ui = new(user, src, "Uplink", name)
|
|
// This UI is only ever opened by one person,
|
|
// and never is updated outside of user input.
|
|
ui.set_autoupdate(FALSE)
|
|
ui.open()
|
|
|
|
/datum/component/uplink/ui_data(mob/user)
|
|
if(!user.mind)
|
|
return
|
|
var/list/data = list()
|
|
data["telecrystals"] = uplink_handler.telecrystals
|
|
data["progression_points"] = uplink_handler.progression_points
|
|
data["current_expected_progression"] = SStraitor.current_global_progression
|
|
data["maximum_active_objectives"] = uplink_handler.maximum_active_objectives
|
|
data["progression_scaling_deviance"] = SStraitor.progression_scaling_deviance
|
|
data["current_progression_scaling"] = SStraitor.current_progression_scaling
|
|
|
|
data["maximum_potential_objectives"] = uplink_handler.maximum_potential_objectives
|
|
if(uplink_handler.has_objectives)
|
|
var/list/primary_objectives = list()
|
|
for(var/datum/objective/task as anything in uplink_handler.primary_objectives)
|
|
var/list/task_data = list()
|
|
if(length(primary_objectives) > length(GLOB.phonetic_alphabet))
|
|
task_data["task_name"] = "DIRECTIVE [length(primary_objectives) + 1]" //The english alphabet is WEAK
|
|
else
|
|
task_data["task_name"] = "DIRECTIVE [uppertext(GLOB.phonetic_alphabet[length(primary_objectives) + 1])]"
|
|
task_data["task_text"] = task.explanation_text
|
|
primary_objectives += list(task_data)
|
|
|
|
var/list/potential_objectives = list()
|
|
for(var/index in 1 to uplink_handler.potential_objectives.len)
|
|
var/datum/traitor_objective/objective = uplink_handler.potential_objectives[index]
|
|
var/list/objective_data = objective.uplink_ui_data(user)
|
|
objective_data["id"] = index
|
|
potential_objectives += list(objective_data)
|
|
|
|
var/list/active_objectives = list()
|
|
for(var/index in 1 to uplink_handler.active_objectives.len)
|
|
var/datum/traitor_objective/objective = uplink_handler.active_objectives[index]
|
|
var/list/objective_data = objective.uplink_ui_data(user)
|
|
objective_data["id"] = index
|
|
active_objectives += list(objective_data)
|
|
|
|
data["primary_objectives"] = primary_objectives
|
|
data["potential_objectives"] = potential_objectives
|
|
data["active_objectives"] = active_objectives
|
|
data["completed_final_objective"] = uplink_handler.final_objective
|
|
|
|
var/list/stock_list = uplink_handler.item_stock.Copy()
|
|
var/list/extra_purchasable_stock = list()
|
|
var/list/extra_purchasable = list()
|
|
for(var/datum/uplink_item/item as anything in uplink_handler.extra_purchasable)
|
|
if(item.stock_key in stock_list)
|
|
extra_purchasable_stock[REF(item)] = stock_list[item.stock_key]
|
|
var/atom/actual_item = item.item
|
|
extra_purchasable += list(list(
|
|
"id" = item.type,
|
|
"name" = item.name,
|
|
"icon" = actual_item.icon,
|
|
"icon_state" = actual_item.icon_state,
|
|
"cost" = item.cost,
|
|
"desc" = item.desc,
|
|
"category" = item.category ? initial(item.category.name) : null,
|
|
"purchasable_from" = item.purchasable_from,
|
|
"restricted" = item.restricted,
|
|
"limited_stock" = item.limited_stock,
|
|
"restricted_roles" = item.restricted_roles,
|
|
"restricted_species" = item.restricted_species,
|
|
"progression_minimum" = item.progression_minimum,
|
|
"ref" = REF(item),
|
|
))
|
|
|
|
var/list/remaining_stock = list()
|
|
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
|
|
data["shop_locked"] = uplink_handler.shop_locked
|
|
data["purchased_items"] = length(uplink_handler.purchase_log?.purchase_log)
|
|
data["can_renegotiate"] = user.mind == uplink_handler.owner && uplink_handler.can_replace_objectives?.Invoke() == TRUE
|
|
return data
|
|
|
|
/datum/component/uplink/ui_static_data(mob/user)
|
|
var/list/data = list()
|
|
data["uplink_flag"] = uplink_handler.uplink_flag
|
|
data["has_progression"] = uplink_handler.has_progression
|
|
data["has_objectives"] = uplink_handler.has_objectives
|
|
data["lockable"] = lockable
|
|
data["assigned_role"] = uplink_handler.assigned_role
|
|
data["assigned_species"] = uplink_handler.assigned_species
|
|
data["debug"] = uplink_handler.debug_mode
|
|
return data
|
|
|
|
/datum/component/uplink/ui_assets(mob/user)
|
|
return list(
|
|
get_asset_datum(/datum/asset/json/uplink),
|
|
)
|
|
|
|
/datum/component/uplink/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
|
|
. = ..()
|
|
if(.)
|
|
return
|
|
if(!active)
|
|
return
|
|
switch(action)
|
|
if("buy")
|
|
var/datum/uplink_item/item
|
|
if(params["ref"])
|
|
item = locate(params["ref"]) in uplink_handler.extra_purchasable
|
|
if(!item)
|
|
return
|
|
else
|
|
var/datum/uplink_item/item_path = text2path(params["path"])
|
|
if(!ispath(item_path, /datum/uplink_item))
|
|
return
|
|
item = SStraitor.uplink_items_by_type[item_path]
|
|
uplink_handler.purchase_item(ui.user, item, parent)
|
|
if("buy_raw_tc")
|
|
if (uplink_handler.telecrystals <= 0)
|
|
return
|
|
var/desired_amount = tgui_input_number(ui.user, "How many raw telecrystals to buy?", "Buy Raw TC", default = uplink_handler.telecrystals, max_value = uplink_handler.telecrystals)
|
|
if(!desired_amount || desired_amount < 1)
|
|
return
|
|
uplink_handler.purchase_raw_tc(ui.user, desired_amount, parent)
|
|
if("lock")
|
|
if(!lockable)
|
|
return TRUE
|
|
lock_uplink()
|
|
if("renegotiate_objectives")
|
|
uplink_handler.replace_objectives?.Invoke()
|
|
SStgui.update_uis(src)
|
|
|
|
if(!uplink_handler.has_objectives)
|
|
return TRUE
|
|
|
|
if(uplink_handler.owner?.current != ui.user || !uplink_handler.can_take_objectives)
|
|
return TRUE
|
|
|
|
switch(action)
|
|
if("regenerate_objectives")
|
|
uplink_handler.generate_objectives()
|
|
return TRUE
|
|
|
|
var/list/objectives
|
|
switch(action)
|
|
if("start_objective")
|
|
objectives = uplink_handler.potential_objectives
|
|
if("objective_act", "finish_objective", "objective_abort")
|
|
objectives = uplink_handler.active_objectives
|
|
|
|
if(!objectives)
|
|
return
|
|
|
|
var/objective_index = round(text2num(params["index"]))
|
|
if(objective_index < 1 || objective_index > length(objectives))
|
|
return TRUE
|
|
var/datum/traitor_objective/objective = objectives[objective_index]
|
|
|
|
// Objective actions
|
|
switch(action)
|
|
if("start_objective")
|
|
uplink_handler.take_objective(ui.user, objective)
|
|
if("objective_act")
|
|
uplink_handler.ui_objective_act(ui.user, objective, params["objective_action"])
|
|
if("finish_objective")
|
|
if(!objective.finish_objective(ui.user))
|
|
return
|
|
uplink_handler.complete_objective(objective)
|
|
if("objective_abort")
|
|
uplink_handler.abort_objective(objective)
|
|
return TRUE
|
|
|
|
/// Proc that locks uplinks
|
|
/datum/component/uplink/proc/lock_uplink()
|
|
active = FALSE
|
|
locked = TRUE
|
|
SStgui.close_uis(src)
|
|
|
|
// Implant signal responses
|
|
/datum/component/uplink/proc/implant_activation()
|
|
SIGNAL_HANDLER
|
|
|
|
var/obj/item/implant/implant = parent
|
|
locked = FALSE
|
|
interact(null, implant.imp_in)
|
|
|
|
/datum/component/uplink/proc/implanting(datum/source, list/arguments)
|
|
SIGNAL_HANDLER
|
|
|
|
var/mob/user = arguments[2]
|
|
owner = user?.key
|
|
if(owner && !purchase_log)
|
|
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)
|
|
|
|
/datum/component/uplink/proc/old_implant(datum/source, list/arguments, obj/item/implant/new_implant)
|
|
SIGNAL_HANDLER
|
|
|
|
// 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/source, datum/component/uplink/uplink)
|
|
SIGNAL_HANDLER
|
|
|
|
return COMPONENT_DELETE_NEW_IMPLANT
|
|
|
|
// PDA signal responses
|
|
|
|
/datum/component/uplink/proc/new_ringtone(datum/source, mob/living/user, new_ring_text)
|
|
SIGNAL_HANDLER
|
|
|
|
if(trim(LOWER_TEXT(new_ring_text)) != trim(LOWER_TEXT(unlock_code)))
|
|
if(trim(LOWER_TEXT(new_ring_text)) == trim(LOWER_TEXT(failsafe_code)))
|
|
failsafe(user)
|
|
return COMPONENT_STOP_RINGTONE_CHANGE
|
|
return
|
|
locked = FALSE
|
|
if(ismob(user))
|
|
interact(null, user)
|
|
to_chat(user, span_hear("The computer softly beeps."))
|
|
return COMPONENT_STOP_RINGTONE_CHANGE
|
|
|
|
/datum/component/uplink/proc/check_detonate()
|
|
SIGNAL_HANDLER
|
|
|
|
return COMPONENT_TABLET_NO_DETONATE
|
|
|
|
// Radio signal responses
|
|
|
|
/datum/component/uplink/proc/new_frequency(datum/source, list/arguments)
|
|
SIGNAL_HANDLER
|
|
|
|
var/obj/item/radio/master = parent
|
|
var/frequency = arguments[1]
|
|
if(frequency != unlock_code)
|
|
if(frequency == failsafe_code)
|
|
failsafe(master.loc)
|
|
return
|
|
locked = FALSE
|
|
if(ismob(master.loc))
|
|
interact(null, master.loc)
|
|
|
|
/datum/component/uplink/proc/new_message(datum/source, mob/living/user, message, channel)
|
|
SIGNAL_HANDLER
|
|
|
|
if(channel != RADIO_CHANNEL_UPLINK)
|
|
return
|
|
|
|
if(!findtext(LOWER_TEXT(message), LOWER_TEXT(unlock_code)))
|
|
if(failsafe_code && findtext(LOWER_TEXT(message), LOWER_TEXT(failsafe_code)))
|
|
failsafe(user) // no point returning cannot radio, youre probably ded
|
|
return
|
|
locked = FALSE
|
|
interact(null, user)
|
|
to_chat(user, "As you whisper the code into your headset, a soft chime fills your ears.")
|
|
return COMPONENT_CANNOT_USE_RADIO
|
|
|
|
// Pen signal responses
|
|
|
|
/datum/component/uplink/proc/pen_rotation(datum/source, degrees, mob/living/carbon/user)
|
|
SIGNAL_HANDLER
|
|
|
|
var/obj/item/pen/master = parent
|
|
previous_attempts += degrees
|
|
if(length(previous_attempts) > PEN_ROTATIONS)
|
|
popleft(previous_attempts)
|
|
|
|
if(compare_list(previous_attempts, unlock_code))
|
|
locked = FALSE
|
|
previous_attempts.Cut()
|
|
master.degrees = 0
|
|
interact(null, user)
|
|
to_chat(user, span_warning("Your pen makes a clicking noise, before quickly rotating back to 0 degrees!"))
|
|
|
|
else if(compare_list(previous_attempts, failsafe_code))
|
|
failsafe(user)
|
|
|
|
/datum/component/uplink/proc/setup_unlock_code()
|
|
unlock_code = generate_code()
|
|
var/obj/item/P = parent
|
|
if(istype(parent,/obj/item/modular_computer))
|
|
unlock_note = "<B>Uplink Passcode:</B> [unlock_code] ([P.name])."
|
|
else if(istype(parent,/obj/item/radio))
|
|
unlock_note = "<B>Radio Passcode:</B> [unlock_code] ([P.name], [RADIO_TOKEN_UPLINK] channel)."
|
|
else if(istype(parent,/obj/item/pen))
|
|
unlock_note = "<B>Uplink Degrees:</B> [english_list(unlock_code)] ([P.name])."
|
|
|
|
/datum/component/uplink/proc/generate_code()
|
|
var/returnable_code = ""
|
|
|
|
if(istype(parent, /obj/item/modular_computer))
|
|
returnable_code = "[rand(100,999)] [pick(GLOB.phonetic_alphabet)]"
|
|
|
|
else if(istype(parent, /obj/item/radio))
|
|
returnable_code = pick(GLOB.phonetic_alphabet)
|
|
|
|
else if(istype(parent, /obj/item/pen))
|
|
returnable_code = list()
|
|
for(var/i in 1 to PEN_ROTATIONS)
|
|
returnable_code += rand(1, 360)
|
|
|
|
if(!unlock_code) // assume the unlock_code is our "base" code that we don't want to duplicate, and if we don't have an unlock code, immediately return out of it since there's nothing to compare to.
|
|
return returnable_code
|
|
|
|
// duplicate checking, re-run the proc if we get a dupe to prevent the failsafe explodey code being the same as the unlock code.
|
|
if(islist(returnable_code))
|
|
if(english_list(returnable_code) == english_list(unlock_code)) // we pass english_list to the user anyways and for later processing, so we can just compare the english_list of the two lists.
|
|
return generate_code()
|
|
|
|
else if(unlock_code == returnable_code)
|
|
return generate_code()
|
|
|
|
return returnable_code
|
|
|
|
/// Proc that unlocks a locked replacement uplink when it hears the unlock code from their datum
|
|
/datum/component/uplink/proc/on_heard(datum/source, list/hearing_args)
|
|
SIGNAL_HANDLER
|
|
if(!locked)
|
|
return
|
|
if(!findtext(hearing_args[HEARING_RAW_MESSAGE], unlock_code))
|
|
return
|
|
var/atom/replacement_uplink = parent
|
|
locked = FALSE
|
|
replacement_uplink.balloon_alert_to_viewers("beep", vision_distance = COMBAT_MESSAGE_RANGE)
|
|
|
|
/datum/component/uplink/proc/failsafe(atom/source)
|
|
if(!parent)
|
|
return
|
|
var/turf/T = get_turf(parent)
|
|
if(!T)
|
|
return
|
|
var/user_deets = "an uplink failsafe explosion has been triggered"
|
|
if(ismob(source))
|
|
user_deets = "[ADMIN_LOOKUPFLW(source)] has triggered an uplink failsafe explosion"
|
|
source.log_message("triggered an uplink failsafe explosion. Uplink owner: [key_name(owner)].", LOG_ATTACK)
|
|
else if(istype(source, /obj/item/circuit_component))
|
|
var/obj/item/circuit_component/circuit = source
|
|
user_deets = "[circuit.parent.get_creator_admin()] has triggered an uplink failsafe explosion"
|
|
else
|
|
source?.log_message("somehow triggered an uplink failsafe explosion. Uplink owner: [key_name(owner)].", LOG_ATTACK)
|
|
message_admins("[user_deets] at [AREACOORD(T)] The owner of the uplink was [ADMIN_LOOKUPFLW(owner)].")
|
|
|
|
explosion(parent, devastation_range = 1, heavy_impact_range = 2, light_impact_range = 3)
|
|
qdel(parent) //Alternatively could brick the uplink.
|
|
|
|
#undef PEN_ROTATIONS
|