Refactor, improve, and rename canUseTopic to be can_perform_action (#73434)

This builds on what #69790 did and improved the code even further.
Notable things:
- `Topic()` is a deprecated proc in our codebase (replaced with
Javascript tgui) so it makes sense to rename `canUseTopic` to
`can_perform_action` which is more straightforward in what it does.
- Positional and named arguments have been converted into a easier to
use `action_bitflag`
- The bitflags adds some new checks you can use like: `NEED_GRAVITY |
NEED_LITERACY | NEED_LIGHT` when you want to perform an action.
- Redundant, duplicate, or dead code has been removed.
- Fixes several runtimes where `canUseTopic` was being called without a
proper target (IV drips, gibber, food processor)
- Better documentation for the proc and bitflags with examples
This commit is contained in:
Tim
2023-02-16 20:22:14 -05:00
committed by GitHub
parent 3c22292ce1
commit a1ada2c9ef
181 changed files with 353 additions and 294 deletions
@@ -43,7 +43,7 @@
var/scramble_response = tgui_alert(user, "Turning the scrambler on will make the shuttle trackable by GPS. Are you sure you want to do it?", "Scrambler", list("Yes", "Cancel"))
if(scramble_response != "Yes")
return
if(active || !user.canUseTopic(src, be_close = TRUE))
if(active || !user.can_perform_action(src))
return
toggle_on(user)
update_appearance()
@@ -230,7 +230,7 @@
if(!istype(M))
return ..()
if(!istype(user) || !user.canUseTopic(M, be_close = TRUE))
if(!istype(user) || !user.can_perform_action(M))
return
if(M.stat != DEAD)
+2 -2
View File
@@ -207,7 +207,7 @@
return
var/sniped_amount = painting_metadata.credit_value
var/offer_amount = tgui_input_number(user, "How much do you want to offer?", "Patronage Amount", (painting_metadata.credit_value + 1), account.account_balance, painting_metadata.credit_value)
if(!offer_amount || QDELETED(user) || QDELETED(src) || !usr.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE))
if(!offer_amount || QDELETED(user) || QDELETED(src) || !usr.can_perform_action(src, FORBID_TELEKINESIS_REACH))
return
if(sniped_amount != painting_metadata.credit_value)
return
@@ -324,7 +324,7 @@
if(painting_metadata.loaded_from_json) // No renaming old paintings
return
var/new_name = tgui_input_text(user, "What do you want to name the painting?", "Title Your Masterpiece")
if(new_name != painting_metadata.title && new_name && user.canUseTopic(src, be_close = TRUE))
if(new_name != painting_metadata.title && new_name && user.can_perform_action(src))
painting_metadata.title = new_name
var/sign_choice = tgui_alert(user, "Do you want to sign it or remain anonymous?", "Sign painting?", list("Yes", "No"))
if(sign_choice != "Yes")
+1 -1
View File
@@ -16,7 +16,7 @@
/obj/item/assembly/control/multitool_act(mob/living/user)
var/change_id = tgui_input_number(user, "Set the door controllers ID", "Door ID", id, 100)
if(!change_id || QDELETED(user) || QDELETED(src) || !usr.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE))
if(!change_id || QDELETED(user) || QDELETED(src) || !usr.can_perform_action(src, FORBID_TELEKINESIS_REACH))
return
id = change_id
balloon_alert(user, "id changed")
@@ -64,7 +64,7 @@
. = ..()
if(!can_interact(user))
return
if(!user.canUseTopic(src, !issilicon(user)) || !isturf(loc))
if(!user.can_perform_action(src, ALLOW_SILICON_REACH) || !isturf(loc))
return
togglelock(user)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
@@ -767,7 +767,7 @@ GLOBAL_LIST_INIT(gas_id_to_canister, init_gas_id_to_canister())
timer_set = min(maximum_timer_set, timer_set + 10)
if("input")
var/user_input = tgui_input_number(usr, "Set time to valve toggle", "Canister Timer", timer_set, maximum_timer_set, minimum_timer_set)
if(isnull(user_input) || QDELETED(usr) || QDELETED(src) || !usr.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE))
if(isnull(user_input) || QDELETED(usr) || QDELETED(src) || !usr.can_perform_action(src, FORBID_TELEKINESIS_REACH))
return
timer_set = user_input
log_admin("[key_name(usr)] has activated a prototype valve timer")
@@ -159,7 +159,7 @@
/obj/machinery/portable_atmospherics/AltClick(mob/living/user)
. = ..()
if(!istype(user) || !user.canUseTopic(src, be_close = TRUE, no_dexterity = TRUE, no_tk = FALSE, need_hands = !iscyborg(user)) || !can_interact(user))
if(!istype(user) || !user.can_perform_action(src, NEED_DEXTERITY) || !can_interact(user))
return
if(!holding)
return
+1 -1
View File
@@ -44,7 +44,7 @@
return NONE
/obj/item/toy/cards/cardhand/attack_self(mob/living/user)
if(!isliving(user) || !user.canUseTopic(src, be_close = TRUE, no_dexterity = TRUE, no_tk = TRUE))
if(!isliving(user) || !user.can_perform_action(src, NEED_DEXTERITY| FORBID_TELEKINESIS_REACH))
return
var/list/handradial = list()
+1 -1
View File
@@ -111,7 +111,7 @@
* * obj/item/toy/singlecard/card (optional) - The card drawn from the hand
**/
/obj/item/toy/cards/proc/draw(mob/living/user, obj/item/toy/singlecard/card)
if(!isliving(user) || !user.canUseTopic(src, be_close = TRUE, no_dexterity = TRUE, no_tk = TRUE))
if(!isliving(user) || !user.can_perform_action(src, NEED_DEXTERITY| FORBID_TELEKINESIS_REACH))
return
if(count_cards() == 0)
+2 -2
View File
@@ -143,7 +143,7 @@
other_players = other_players)
/obj/item/toy/cards/deck/attack_hand(mob/living/user, list/modifiers, flip_card = FALSE)
if(!ishuman(user) || !user.canUseTopic(src, be_close = TRUE, no_dexterity = TRUE, no_tk = TRUE, need_hands = !iscyborg(user)))
if(!ishuman(user) || !user.can_perform_action(src, NEED_DEXTERITY|FORBID_TELEKINESIS_REACH))
return
var/obj/item/toy/singlecard/card = draw(user)
@@ -160,7 +160,7 @@
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
/obj/item/toy/cards/deck/AltClick(mob/living/user)
if(user.canUseTopic(src, be_close = TRUE, no_dexterity = TRUE, no_tk = TRUE, need_hands = !iscyborg(user)))
if(user.can_perform_action(src, NEED_DEXTERITY|FORBID_TELEKINESIS_REACH))
if(wielded)
shuffle_cards(user)
else
+3 -3
View File
@@ -209,7 +209,7 @@
return
var/cardtext = stripped_input(user, "What do you wish to write on the card?", "Card Writing", "", 50)
if(!cardtext || !user.canUseTopic(src, be_close = TRUE))
if(!cardtext || !user.can_perform_action(src))
return
cardname = cardtext
@@ -230,7 +230,7 @@
attack_self(user)
/obj/item/toy/singlecard/attack_self(mob/living/carbon/human/user)
if(!ishuman(user) || !user.canUseTopic(src, be_close = TRUE, no_dexterity = TRUE, no_tk = TRUE, need_hands = !iscyborg(user)))
if(!ishuman(user) || !user.can_perform_action(src, NEED_DEXTERITY|FORBID_TELEKINESIS_REACH))
return
Flip()
@@ -238,7 +238,7 @@
user.balloon_alert_to_viewers("flips a card")
/obj/item/toy/singlecard/AltClick(mob/living/carbon/human/user)
if(user.canUseTopic(src, be_close = TRUE, no_dexterity = TRUE, no_tk = TRUE, need_hands = !iscyborg(user)))
if(user.can_perform_action(src, NEED_DEXTERITY|FORBID_TELEKINESIS_REACH))
transform = turn(transform, 90)
// use the simple_rotation component to make this turn with Alt+RMB & Alt+LMB at some point in the future - TimT
return ..()
+2 -2
View File
@@ -80,7 +80,7 @@
to_chat(user, span_notice("[src] linked to [C]."))
/obj/item/supplypod_beacon/AltClick(mob/user)
if (!user.canUseTopic(src, !issilicon(user)))
if (!user.can_perform_action(src, ALLOW_SILICON_REACH))
return
if (express_console)
unlink_console()
@@ -93,7 +93,7 @@
var/new_beacon_name = tgui_input_text(user, "What would you like the tag to be?", "Beacon Tag", max_length = MAX_NAME_LEN)
if(isnull(new_beacon_name))
return
if(!user.canUseTopic(src, be_close = TRUE))
if(!user.can_perform_action(src))
return
name += " ([tag])"
+1 -1
View File
@@ -117,7 +117,7 @@
to_chat(user, span_warning("You must be holding \the [src] to continue!"))
return
var/chosen_price = tgui_input_number(user, "Set price", "Price", new_custom_price)
if(!chosen_price || QDELETED(user) || QDELETED(src) || !user.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE) || loc != user)
if(!chosen_price || QDELETED(user) || QDELETED(src) || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH) || loc != user)
return
new_custom_price = chosen_price
to_chat(user, span_notice("[src] will now give things a [new_custom_price] cr tag."))
+1 -1
View File
@@ -143,7 +143,7 @@
/obj/item/clothing/head/fedora/det_hat/AltClick(mob/user)
. = ..()
if(loc != user || !user.canUseTopic(src, be_close = TRUE, no_dexterity = TRUE, no_tk = FALSE, need_hands = TRUE))
if(loc != user || !user.can_perform_action(src, NEED_DEXTERITY|NEED_HANDS))
return
if(candy_cooldown < world.time)
var/obj/item/food/candy_corn/CC = new /obj/item/food/candy_corn(src)
+1 -1
View File
@@ -25,7 +25,7 @@
/obj/item/clothing/head/soft/AltClick(mob/user)
..()
if(user.canUseTopic(src, be_close = TRUE, no_dexterity = TRUE, no_tk = FALSE, need_hands = !iscyborg(user)))
if(user.can_perform_action(src, NEED_DEXTERITY))
flip(user)
+1 -1
View File
@@ -50,7 +50,7 @@
/obj/item/clothing/head/wig/attack_self(mob/user)
var/new_style = tgui_input_list(user, "Select a hairstyle", "Wig Styling", GLOB.hairstyles_list - "Bald")
var/newcolor = adjustablecolor ? input(usr,"","Choose Color",color) as color|null : null
if(!user.canUseTopic(src, be_close = TRUE))
if(!user.can_perform_action(src))
return
if(new_style && new_style != hairstyle)
hairstyle = new_style
+1 -1
View File
@@ -25,7 +25,7 @@
/obj/item/clothing/mask/breath/AltClick(mob/user)
..()
if(user.canUseTopic(src, be_close = TRUE, no_dexterity = TRUE, no_tk = FALSE, need_hands = !iscyborg(user)))
if(user.can_perform_action(src, NEED_DEXTERITY))
adjustmask(user)
/obj/item/clothing/mask/breath/examine(mob/user)
@@ -190,13 +190,13 @@
/// Open the cell cover when ALT+Click on the suit
/obj/item/clothing/suit/space/AltClick(mob/living/user)
if(!user.canUseTopic(src, be_close = TRUE, no_dexterity = TRUE, no_tk = FALSE, need_hands = !iscyborg(user)))
if(!user.can_perform_action(src, NEED_DEXTERITY))
return ..()
toggle_spacesuit_cell(user)
/// Remove the cell whent he cover is open on CTRL+Click
/obj/item/clothing/suit/space/CtrlClick(mob/living/user)
if(user.canUseTopic(src, be_close = TRUE, no_dexterity = TRUE, no_tk = FALSE, need_hands = !iscyborg(user)))
if(user.can_perform_action(src, NEED_DEXTERITY))
if(cell_cover_open && cell)
remove_cell(user)
return
@@ -85,7 +85,7 @@
. += span_notice("There's nothing placed on the helmet.")
/obj/item/clothing/head/helmet/space/plasmaman/AltClick(mob/user)
if(user.canUseTopic(src, be_close = TRUE))
if(user.can_perform_action(src))
toggle_welding_screen(user)
/obj/item/clothing/head/helmet/space/plasmaman/ui_action_click(mob/user, action)
+1 -1
View File
@@ -310,7 +310,7 @@
if(.)
return
if(!user.canUseTopic(src, be_close = TRUE, no_dexterity = TRUE, no_tk = FALSE, need_hands = !iscyborg(user)))
if(!user.can_perform_action(src, NEED_DEXTERITY))
return
if(attached_accessory)
remove_accessory(user)
+1 -1
View File
@@ -70,7 +70,7 @@
return
/obj/item/clothing/accessory/attack_self_secondary(mob/user)
if(user.canUseTopic(src, be_close = TRUE, no_dexterity = TRUE, no_tk = FALSE, need_hands = !iscyborg(user)))
if(user.can_perform_action(src, NEED_DEXTERITY))
above_suit = !above_suit
to_chat(user, "[src] will be worn [above_suit ? "above" : "below"] your suit.")
return
+4 -4
View File
@@ -83,7 +83,7 @@
safe_scan(user, atom_to_scan = A)
return . | AFTERATTACK_PROCESSED_ITEM
/**
/**
* safe_scan - a wrapper proc for scan()
*
* calls scan(), and should a runtime occur within we can still reset the 'busy' state
@@ -96,7 +96,7 @@
balloon_alert(user, "scanner error!") // but in case it does, we 'error' instead of just bricking the scanner
scanner_busy = FALSE
/**
/**
* scan - scans an atom for forensic data and outputs it to the mob holding the scanner
*
* This should always return TRUE barring a runtime
@@ -107,7 +107,7 @@
return TRUE
scanner_busy = TRUE
user.visible_message(
span_notice("\The [user] points the [src.name] at \the [scanned_atom] and performs a forensic scan."),
@@ -220,7 +220,7 @@
/obj/item/detective_scanner/AltClick(mob/living/user)
// Best way for checking if a player can use while not incapacitated, etc
if(!user.canUseTopic(src, be_close=TRUE))
if(!user.can_perform_action(src))
return
if(!LAZYLEN(log))
balloon_alert(user, "no logs!")
+2 -2
View File
@@ -97,7 +97,7 @@
/// Exit sanity checks
if(!cash_deposit)
return TRUE
if(QDELETED(held_item) || QDELETED(user) || QDELETED(src) || !user.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE))
if(QDELETED(held_item) || QDELETED(user) || QDELETED(src) || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH))
return FALSE
if(!chip.spend(cash_deposit, FALSE))
balloon_alert(user, "insufficient credits")
@@ -267,7 +267,7 @@
/// If the user has enough money, ask them the amount or charge the force fee
var/amount = force_fee || tgui_input_number(user, "How much? (Max: [payee.account_balance])", "Patronage", max_value = payee.account_balance)
/// Exit checks in case the user cancelled or entered an invalid amount
if(!amount || QDELETED(user) || QDELETED(src) || !user.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE))
if(!amount || QDELETED(user) || QDELETED(src) || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH))
return FALSE
if(!payee.adjust_money(-amount, "Holopay: [capitalize(name)]"))
balloon_alert(user, "insufficient credits")
+1 -1
View File
@@ -74,7 +74,7 @@
return
var/recipient = tgui_input_text(user, "Who is receiving this valentine?", "To:", max_length = MAX_NAME_LEN)
var/sender = tgui_input_text(user, "Who is sending this valentine?", "From:", max_length = MAX_NAME_LEN)
if(!user.canUseTopic(src, be_close = TRUE))
if(!user.can_perform_action(src))
return
if(recipient && sender)
name = "valentine - To: [recipient] From: [sender]"
+1 -1
View File
@@ -101,7 +101,7 @@
. += span_notice("Alt-click to [panel_open ? "close" : "open"] the control panel.")
/obj/structure/aquarium/AltClick(mob/user)
if(!user.canUseTopic(src, be_close = TRUE))
if(!user.can_perform_action(src))
return ..()
panel_open = !panel_open
update_appearance()
@@ -126,7 +126,7 @@
. = ..()
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
return
if(!can_interact(user) || !user.canUseTopic(src, !issilicon(user), FALSE, no_tk = TRUE))
if(!can_interact(user) || !user.can_perform_action(src, ALLOW_SILICON_REACH|FORBID_TELEKINESIS_REACH))
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
if(brewing)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
@@ -291,7 +291,7 @@
/obj/machinery/coffeemaker/ui_interact(mob/user) // The microwave Menu //I am reasonably certain that this is not a microwave //I am positively certain that this is not a microwave
. = ..()
if(brewing || !user.canUseTopic(src, !issilicon(user)))
if(brewing || !user.can_perform_action(src, ALLOW_SILICON_REACH))
return
var/list/options = list()
@@ -331,7 +331,7 @@
choice = show_radial_menu(user, src, options, require_near = !issilicon(user))
// post choice verification
if(brewing || (isAI(user) && machine_stat & NOPOWER) || !user.canUseTopic(src, !issilicon(user)))
if(brewing || (isAI(user) && machine_stat & NOPOWER) || !user.can_perform_action(src, ALLOW_SILICON_REACH))
return
switch(choice)
@@ -131,7 +131,7 @@
set src in oview(1)
if (usr.stat != CONSCIOUS || HAS_TRAIT(usr, TRAIT_HANDS_BLOCKED))
return
if(!usr.canUseTopic())
if(!usr.can_perform_action(src))
return
src.go_out()
add_fingerprint(usr)
@@ -182,7 +182,7 @@
/obj/machinery/icecream_vat/AltClick(mob/living/user)
. = ..()
if(!can_interact(user) || !user.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE))
if(!can_interact(user) || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH))
return
replace_beaker(user)
@@ -324,7 +324,7 @@
return ..()
/obj/machinery/microwave/attack_hand_secondary(mob/user, list/modifiers)
if(user.canUseTopic(src, !issilicon(usr)))
if(user.can_perform_action(src, ALLOW_SILICON_REACH))
if(!length(ingredients))
balloon_alert(user, "it's empty!")
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
@@ -334,7 +334,7 @@
/obj/machinery/microwave/ui_interact(mob/user)
. = ..()
if(operating || panel_open || !anchored || !user.canUseTopic(src, !issilicon(user)))
if(operating || panel_open || !anchored || !user.can_perform_action(src, ALLOW_SILICON_REACH))
return
if(isAI(user) && (machine_stat & NOPOWER))
return
@@ -349,7 +349,7 @@
var/choice = show_radial_menu(user, src, isAI(user) ? ai_radial_options : radial_options, require_near = !issilicon(user))
// post choice verification
if(operating || panel_open || !anchored || !user.canUseTopic(src, !issilicon(user)))
if(operating || panel_open || !anchored || !user.can_perform_action(src, ALLOW_SILICON_REACH))
return
if(isAI(user) && (machine_stat & NOPOWER))
return
@@ -170,7 +170,7 @@
set src in oview(1)
if(usr.stat != CONSCIOUS || HAS_TRAIT(usr, TRAIT_HANDS_BLOCKED))
return
if (!usr.canUseTopic())
if(!usr.can_perform_action(src))
return
if(isliving(usr))
var/mob/living/L = usr
@@ -219,7 +219,7 @@
if(!desired)
return FALSE
if(QDELETED(src) || QDELETED(usr) || !usr.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE)) // Sanity checkin' in case stupid stuff happens while we wait for input()
if(QDELETED(src) || QDELETED(usr) || !usr.can_perform_action(src, FORBID_TELEKINESIS_REACH)) // Sanity checkin' in case stupid stuff happens while we wait for input()
return FALSE
for(var/obj/item/dispensed_item in src)
+2 -2
View File
@@ -156,7 +156,7 @@
return
else
bomb_timer = tgui_input_number(user, "Set the bomb timer", "Pizza Bomb", bomb_timer, bomb_timer_max, bomb_timer_min)
if(!bomb_timer || QDELETED(user) || QDELETED(src) || !usr.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE))
if(!bomb_timer || QDELETED(user) || QDELETED(src) || !usr.can_perform_action(src, FORBID_TELEKINESIS_REACH))
return
bomb_defused = FALSE
log_bomber(user, "has trapped a", src, "with [bomb] set to [bomb_timer] seconds")
@@ -221,7 +221,7 @@
return
var/obj/item/pizzabox/box = length(boxes) ? boxes[length(boxes)] : src
box.boxtag += tgui_input_text(user, "Write on [box]'s tag:", box, max_length = 30)
if(!user.canUseTopic(src, be_close = TRUE))
if(!user.can_perform_action(src))
return
balloon_alert(user, "writing box tag...")
boxtag_set = TRUE
@@ -213,7 +213,7 @@
visible_message(span_danger("[user] disturbs the [name] to no effect!"))
else
var/option = tgui_alert(user, "Which piece do you wish to remove?", "Apiary Adjustment", list("Honey Frame", "Queen Bee"))
if(!option || QDELETED(user) || QDELETED(src) || !user.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE))
if(!option || QDELETED(user) || QDELETED(src) || !user.can_perform_action(src, NEED_DEXTERITY))
return
switch(option)
if("Honey Frame")
+1 -1
View File
@@ -222,7 +222,7 @@
/obj/machinery/biogenerator/AltClick(mob/living/user)
. = ..()
if(user.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE) && can_interact(user))
if(user.can_perform_action(src, FORBID_TELEKINESIS_REACH) && can_interact(user))
eject_beaker(user)
+1 -1
View File
@@ -165,7 +165,7 @@
return result
// Make sure they can still interact with the parent hydroponics tray.
if(!user.canUseTopic(parent, be_close = TRUE))
if(!user.can_perform_action(parent))
to_chat(user, text = "You are no longer able to harvest the seeds from [parent]!", type = MESSAGE_TYPE_INFO)
return result
+4 -4
View File
@@ -941,7 +941,7 @@
var/removed_trait = tgui_input_list(user, "Trait to remove from the [myseed.plantname]", "Plant Trait Removal", sort_list(current_traits))
if(isnull(removed_trait))
return
if(!user.canUseTopic(src, be_close = TRUE))
if(!user.can_perform_action(src))
return
if(!myseed)
return
@@ -1021,7 +1021,7 @@
return
if(isnull(fresh_mut_list[locked_mutation]))
return
if(!user.canUseTopic(src, be_close = TRUE))
if(!user.can_perform_action(src))
return
myseed.mutatelist = list(fresh_mut_list[locked_mutation])
myseed.set_endurance(myseed.endurance/2)
@@ -1064,7 +1064,7 @@
/obj/machinery/hydroponics/CtrlClick(mob/user)
. = ..()
if(!user.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE))
if(!user.can_perform_action(src, FORBID_TELEKINESIS_REACH))
return
if(!powered())
to_chat(user, span_warning("[name] has no power."))
@@ -1085,7 +1085,7 @@
if(!anchored)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
var/warning = tgui_alert(user, "Are you sure you wish to empty the tray's nutrient beaker?","Empty Tray Nutrients?", list("Yes", "No"))
if(warning == "Yes" && user.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE))
if(warning == "Yes" && user.can_perform_action(src, FORBID_TELEKINESIS_REACH))
reagents.clear_reagents()
to_chat(user, span_warning("You empty [src]'s nutrient tank."))
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
+4 -4
View File
@@ -456,14 +456,14 @@
var/choice = tgui_input_list(usr, "What would you like to change?", "Seed Alteration", list("Plant Name", "Seed Description", "Product Description"))
if(isnull(choice))
return
if(!user.canUseTopic(src, be_close = TRUE))
if(!user.can_perform_action(src))
return
switch(choice)
if("Plant Name")
var/newplantname = reject_bad_text(tgui_input_text(user, "Write a new plant name", "Plant Name", plantname, 20))
if(isnull(newplantname))
return
if(!user.canUseTopic(src, be_close = TRUE))
if(!user.can_perform_action(src))
return
name = "[lowertext(newplantname)]"
plantname = newplantname
@@ -471,7 +471,7 @@
var/newdesc = tgui_input_text(user, "Write a new seed description", "Seed Description", desc, 180)
if(isnull(newdesc))
return
if(!user.canUseTopic(src, be_close = TRUE))
if(!user.can_perform_action(src))
return
desc = newdesc
if("Product Description")
@@ -480,7 +480,7 @@
var/newproductdesc = tgui_input_text(user, "Write a new product description", "Product Description", productdesc, 180)
if(isnull(newproductdesc))
return
if(!user.canUseTopic(src, be_close = TRUE))
if(!user.can_perform_action(src))
return
productdesc = newproductdesc
+1 -1
View File
@@ -115,7 +115,7 @@
updateDialog(usr) // make sure updates when complete
/datum/song/Topic(href, href_list)
if(!usr.canUseTopic(parent, be_close = TRUE, no_dexterity = FALSE, no_tk = FALSE, need_hands = FALSE, floor_okay = TRUE))
if(!usr.can_perform_action(parent, ALLOW_RESTING))
usr << browse(null, "window=instrument")
usr.unset_machine()
return
+3 -1
View File
@@ -20,7 +20,9 @@
if(!(anchored || can_play_unanchored) || !ismob(music_player))
return STOP_PLAYING
var/mob/user = music_player
if(!user.canUseTopic(src, FALSE, TRUE, FALSE, FALSE)) //can play with TK and while resting because fun.
if(!ISADVANCEDTOOLUSER(user))
to_chat(src, span_warning("You don't have the dexterity to do this!"))
return STOP_PLAYING
/obj/structure/musician/ui_interact(mob/user)
+5 -5
View File
@@ -141,7 +141,7 @@
/obj/item/book/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/pen))
if(!user.canUseTopic(src, be_close = TRUE) || !user.can_write(I))
if(!user.can_perform_action(src) || !user.can_write(I))
return
if(user.is_blind())
to_chat(user, span_warning("As you are trying to write on the book, you suddenly feel very stupid!"))
@@ -153,12 +153,12 @@
var/choice = tgui_input_list(usr, "What would you like to change?", "Book Alteration", list("Title", "Contents", "Author", "Cancel"))
if(isnull(choice))
return
if(!user.canUseTopic(src, be_close = TRUE) || !user.can_write(I))
if(!user.can_perform_action(src) || !user.can_write(I))
return
switch(choice)
if("Title")
var/newtitle = reject_bad_text(tgui_input_text(user, "Write a new title", "Book Title", max_length = 30))
if(!user.canUseTopic(src, be_close = TRUE) || !user.can_write(I))
if(!user.can_perform_action(src) || !user.can_write(I))
return
if (length_char(newtitle) > 30)
to_chat(user, span_warning("That title won't fit on the cover!"))
@@ -170,7 +170,7 @@
book_data.set_title(html_decode(newtitle)) //Don't want to double encode here
if("Contents")
var/content = tgui_input_text(user, "Write your book's contents (HTML NOT allowed)", "Book Contents", multiline = TRUE)
if(!user.canUseTopic(src, be_close = TRUE) || !user.can_write(I))
if(!user.can_perform_action(src) || !user.can_write(I))
return
if(!content)
to_chat(user, span_warning("The content is invalid."))
@@ -178,7 +178,7 @@
book_data.set_content(html_decode(content))
if("Author")
var/author = tgui_input_text(user, "Write the author's name", "Author Name")
if(!user.canUseTopic(src, be_close = TRUE) || !user.can_write(I))
if(!user.can_perform_action(src) || !user.can_write(I))
return
if(!author)
to_chat(user, span_warning("The name is invalid."))
+2 -2
View File
@@ -126,10 +126,10 @@
to_chat(user, span_notice("You empty \the [I] into \the [src]."))
update_appearance()
else if(istype(I, /obj/item/pen))
if(!user.canUseTopic(src, be_close = TRUE) || !user.can_write(I))
if(!user.can_perform_action(src) || !user.can_write(I))
return
var/newname = tgui_input_text(user, "What would you like to title this bookshelf?", "Bookshelf Renaming", max_length = MAX_NAME_LEN)
if(!user.canUseTopic(src, be_close = TRUE) || !user.can_write(I))
if(!user.can_perform_action(src) || !user.can_write(I))
return
if(!newname)
return
+2 -2
View File
@@ -30,7 +30,7 @@
if(locked)
to_chat(user, span_notice("The crate is locked with a Deca-code lock."))
var/input = input(usr, "Enter [codelen] digits. All digits must be unique.", "Deca-Code Lock", "") as text|null
if(user.canUseTopic(src, be_close = TRUE) && locked)
if(user.can_perform_action(src) && locked)
var/list/sanitised = list()
var/sanitycheck = TRUE
var/char = ""
@@ -60,7 +60,7 @@
return ..()
/obj/structure/closet/crate/secure/loot/AltClick(mob/living/user)
if(!user.canUseTopic(src, be_close = TRUE))
if(!user.can_perform_action(src))
return
return attack_hand(user) //this helps you not blow up so easily by overriding unlocking which results in an immediate boom.
@@ -60,12 +60,12 @@ GLOBAL_LIST_INIT(marker_beacon_colors, sort_list(list(
transfer_fingerprints_to(M)
/obj/item/stack/marker_beacon/AltClick(mob/living/user)
if(!istype(user) || !user.canUseTopic(src, be_close = TRUE))
if(!istype(user) || !user.can_perform_action(src))
return
var/input_color = tgui_input_list(user, "Choose a color", "Beacon Color", GLOB.marker_beacon_colors)
if(isnull(input_color))
return
if(!istype(user) || !user.canUseTopic(src, be_close = TRUE))
if(!istype(user) || !user.can_perform_action(src))
return
picked_color = input_color
update_appearance()
@@ -158,12 +158,12 @@ GLOBAL_LIST_INIT(marker_beacon_colors, sort_list(list(
/obj/structure/marker_beacon/AltClick(mob/living/user)
..()
if(!istype(user) || !user.canUseTopic(src, be_close = TRUE))
if(!istype(user) || !user.can_perform_action(src))
return
var/input_color = tgui_input_list(user, "Choose a color", "Beacon Color", GLOB.marker_beacon_colors)
if(isnull(input_color))
return
if(!istype(user) || !user.canUseTopic(src, be_close = TRUE))
if(!istype(user) || !user.can_perform_action(src))
return
picked_color = input_color
update_appearance()
@@ -143,7 +143,7 @@
return . | AFTERATTACK_PROCESSED_ITEM
/obj/item/organ/internal/monster_core/attack_self(mob/user)
if (!user.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE))
if (!user.can_perform_action(src, FORBID_TELEKINESIS_REACH))
return
try_apply(user, user)
+1 -1
View File
@@ -193,7 +193,7 @@
/obj/machinery/mineral/ore_redemption/AltClick(mob/living/user)
. = ..()
if(!user.canUseTopic(src, be_close = TRUE))
if(!user.can_perform_action(src))
return
if(panel_open)
input_dir = turn(input_dir, -90)
+1 -1
View File
@@ -838,7 +838,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
update_appearance()
/mob/dead/observer/canUseTopic(atom/movable/M, be_close=FALSE, no_dexterity=FALSE, no_tk=FALSE, need_hands = FALSE, floor_okay=FALSE)
/mob/dead/observer/can_perform_action(atom/movable/target, action_bitflags)
return isAdminGhostAI(usr)
/mob/dead/observer/is_literate()
+2 -2
View File
@@ -73,12 +73,12 @@ GLOBAL_VAR(posibrain_notify_cooldown)
addtimer(CALLBACK(src, PROC_REF(check_success)), ask_delay)
/obj/item/mmi/posibrain/AltClick(mob/living/user)
if(!istype(user) || !user.canUseTopic(src, be_close = TRUE))
if(!istype(user) || !user.can_perform_action(src))
return
var/input_seed = tgui_input_text(user, "Enter a personality seed", "Enter seed", ask_role, MAX_NAME_LEN)
if(isnull(input_seed))
return
if(!istype(user) || !user.canUseTopic(src, be_close = TRUE))
if(!istype(user) || !user.can_perform_action(src))
return
to_chat(user, span_notice("You set the personality seed to \"[input_seed]\"."))
ask_role = input_seed
+1 -1
View File
@@ -214,7 +214,7 @@
/mob/living/carbon/Topic(href, href_list)
..()
if(href_list["embedded_object"] && usr.canUseTopic(src, be_close = TRUE, no_dexterity = TRUE))
if(href_list["embedded_object"] && usr.can_perform_action(src, NEED_DEXTERITY))
var/obj/item/bodypart/L = locate(href_list["embedded_limb"]) in bodyparts
if(!L)
return
+43 -13
View File
@@ -1202,24 +1202,54 @@
/mob/living/can_hold_items(obj/item/I)
return usable_hands && ..()
/mob/living/canUseTopic(atom/movable/M, be_close=FALSE, no_dexterity=FALSE, no_tk=FALSE, need_hands = FALSE, floor_okay=FALSE)
if(!(mobility_flags & MOBILITY_UI) && !floor_okay)
/mob/living/can_perform_action(atom/movable/target, action_bitflags)
if(!istype(target))
CRASH("Missing target arg for can_perform_action")
// If the MOBILITY_UI bitflag is not set it indicates the mob's hands are cutoff, blocked, or handcuffed
// Note - AI's and borgs have the MOBILITY_UI bitflag set even though they don't have hands
// Also if it is not set, the mob could be incapcitated, knocked out, unconscious, asleep, EMP'd, etc.
if(!(mobility_flags & MOBILITY_UI) && !(action_bitflags & ALLOW_RESTING))
to_chat(src, span_warning("You can't do that right now!"))
return FALSE
if(be_close && !Adjacent(M) && (M.loc != src))
if(no_tk)
to_chat(src, span_warning("You are too far away!"))
// NEED_HANDS is already checked by MOBILITY_UI for humans so this is for silicons
if((action_bitflags & NEED_HANDS))
if(!can_hold_items(isitem(target) ? target : null)) // almost redundant if it weren't for mobs
to_chat(src, span_warning("You don't have the physical ability to do this!"))
return FALSE
var/datum/dna/D = has_dna()
if(!D || !D.check_mutation(/datum/mutation/human/telekinesis) || !tkMaxRangeCheck(src, M))
to_chat(src, span_warning("You are too far away!"))
return FALSE
if(need_hands && !can_hold_items(isitem(M) ? M : null)) //almost redundant if it weren't for mobs,
to_chat(src, span_warning("You don't have the physical ability to do this!"))
return FALSE
if(!no_dexterity && !ISADVANCEDTOOLUSER(src))
if(!Adjacent(target) && (target.loc != src))
if(issilicon(src) && !ispAI(src))
if(!(action_bitflags & ALLOW_SILICON_REACH)) // silicons can ignore range checks (except pAIs)
to_chat(src, span_warning("You are too far away!"))
return FALSE
else // just a normal carbon mob
if((action_bitflags & FORBID_TELEKINESIS_REACH))
to_chat(src, span_warning("You are too far away!"))
return FALSE
var/datum/dna/mob_DNA = has_dna()
if(!mob_DNA || !mob_DNA.check_mutation(/datum/mutation/human/telekinesis) || !tkMaxRangeCheck(src, target))
to_chat(src, span_warning("You are too far away!"))
return FALSE
if((action_bitflags & NEED_DEXTERITY) && !ISADVANCEDTOOLUSER(src))
to_chat(src, span_warning("You don't have the dexterity to do this!"))
return FALSE
if((action_bitflags & NEED_LITERACY) && !is_literate())
to_chat(src, span_warning("You can't comprehend any of this!"))
return FALSE
if((action_bitflags & NEED_LIGHT) && !has_light_nearby() && !has_nightvision())
to_chat(src, span_warning("You need more light to do this!"))
return FALSE
if((action_bitflags & NEED_GRAVITY) && !has_gravity())
to_chat(src, span_warning("You need gravity to do this!"))
return FALSE
return TRUE
/mob/living/proc/can_use_guns(obj/item/G)//actually used for more than guns!
+2 -2
View File
@@ -848,11 +848,11 @@
to_chat(src, "You have been downloaded to a mobile storage device. Remote device connection severed.")
to_chat(user, "[span_boldnotice("Transfer successful")]: [name] ([rand(1000,9999)].exe) removed from host terminal and stored within local memory.")
/mob/living/silicon/ai/canUseTopic(atom/movable/M, be_close=FALSE, no_dexterity=FALSE, no_tk=FALSE, need_hands = FALSE, floor_okay=FALSE)
/mob/living/silicon/ai/can_perform_action(atom/movable/target, action_bitflags)
if(control_disabled)
to_chat(src, span_warning("You can't do that right now!"))
return FALSE
return can_see(M) && ..() //stop AIs from leaving windows open and using then after they lose vision
return can_see(target) && ..() //stop AIs from leaving windows open and using then after they lose vision
/mob/living/silicon/ai/proc/can_see(atom/A)
if(isturf(loc)) //AI in core, check if on cameras
@@ -584,7 +584,7 @@
if(AI_NOTIFICATION_CYBORG_DISCONNECTED) //Tampering with the wires
to_chat(connected_ai, "<br><br>[span_notice("NOTICE - Remote telemetry lost with [name].")]<br>")
/mob/living/silicon/robot/canUseTopic(atom/movable/M, be_close=FALSE, no_dexterity=FALSE, no_tk=FALSE, need_hands = FALSE, floor_okay=FALSE)
/mob/living/silicon/robot/can_perform_action(atom/movable/target, action_bitflags)
if(lockcharge || low_power_mode)
to_chat(src, span_warning("You can't do that right now!"))
return FALSE
@@ -350,7 +350,7 @@
. = ..()
if(!can_interact(user))
return
if(!user.canUseTopic(src, !issilicon(user)))
if(!user.can_perform_action(src, ALLOW_SILICON_REACH))
return
unlock_with_id(user)
@@ -946,7 +946,7 @@ Pass a positive integer as an argument to override a bot's default speed.
return ..()
/mob/living/simple_animal/bot/proc/topic_denied(mob/user) //Access check proc for bot topics! Remember to place in a bot's individual Topic if desired.
if(!user.canUseTopic(src, !issilicon(user)))
if(!user.can_perform_action(src, ALLOW_SILICON_REACH))
return TRUE
// 0 for access, 1 for denied.
if(bot_cover_flags & BOT_COVER_EMAGGED) //An emagged bot cannot be controlled by humans, silicons can if one hacked it.
@@ -99,7 +99,7 @@
RegisterSignal(src, COMSIG_LIVING_BANED, PROC_REF(on_baned))
random_revenant_name()
/mob/living/simple_animal/revenant/canUseTopic(atom/movable/M, be_close=FALSE, no_dexterity=FALSE, no_tk=FALSE, need_hands = FALSE, floor_okay=FALSE)
/mob/living/simple_animal/revenant/can_perform_action(atom/movable/target, action_bitflags)
return FALSE
/mob/living/simple_animal/revenant/proc/random_revenant_name()
+17 -9
View File
@@ -995,16 +995,24 @@
return ISINRANGE(their_turf.x, our_turf.x - interaction_range, our_turf.x + interaction_range) && ISINRANGE(their_turf.y, our_turf.y - interaction_range, our_turf.y + interaction_range)
/**
* Whether the mob can use Topic to interact with machines
* Checks whether a mob can perform an action to interact with an object
*
* Args:
* be_close - Whether you need to be next to/on top of M
* no_dexterity - Whether you need to be an ADVANCEDTOOLUSER
* no_tk - If be_close is TRUE, this will block Telekinesis from bypassing the requirement
* need_hands - Whether you need hands to use this
* floor_okay - Whether mobility flags should be checked for MOBILITY_UI to use.
*/
/mob/proc/canUseTopic(atom/movable/M, be_close=FALSE, no_dexterity=FALSE, no_tk=FALSE, need_hands = FALSE, floor_okay=FALSE)
* The default behavior checks if the mob is:
* * Directly adjacent (1-tile radius)
* * Standing up (not resting)
* * Allows telekinesis to be used to skip adjacent checks (if they have DNA mutation)
* *
* action_bitflags: (see code/__DEFINES/mobs.dm)
* * NEED_GRAVITY - If gravity must be present to perform action (can't use pens without gravity)
* * NEED_LITERACY - If reading is required to perform action (can't read a book if you are illiterate)
* * NEED_LIGHT - If lighting must be present to perform action (can't heal someone in the dark)
* * NEED_DEXTERITY - If other mobs (monkeys, aliens, etc) can perform action (can't use computers if you are a monkey)
* * NEED_HANDS - If hands are required to perform action (can't pickup items if you are a cyborg)
* * FORBID_TELEKINESIS_REACH - If telekinesis is forbidden to perform action from a distance (ex. canisters are blacklisted from telekinesis manipulation)
* * ALLOW_SILICON_REACH - If silicons are allowed to perform action from a distance (silicons can operate airlocks from far away)
* * ALLOW_RESTING - If resting on the floor is allowed to perform action ()
**/
/mob/proc/can_perform_action(atom/movable/target, action_bitflags)
return
///Can this mob use storage
@@ -199,7 +199,7 @@ GLOBAL_LIST_EMPTY(TabletMessengers) // a list of all active messengers, similar
. = ..()
if(issilicon(user))
return FALSE
if(!user.canUseTopic(src, be_close = TRUE))
if(!user.can_perform_action(src))
return FALSE
if(RemoveID(user))
@@ -300,7 +300,7 @@ GLOBAL_LIST_EMPTY(TabletMessengers) // a list of all active messengers, similar
/obj/item/modular_computer/MouseDrop(obj/over_object, src_location, over_location)
var/mob/M = usr
if((!istype(over_object, /atom/movable/screen)) && usr.canUseTopic(src, be_close = TRUE))
if((!istype(over_object, /atom/movable/screen)) && usr.can_perform_action(src))
return attack_self(M)
return ..()
@@ -77,10 +77,10 @@
var/original_host = source
var/fakename = sanitize_name(tgui_input_text(user, "Enter a name for the rigged message.", "Forge Message", max_length = MAX_NAME_LEN), allow_numbers = TRUE)
if(!fakename || source != original_host || !user.canUseTopic(source, be_close = TRUE))
if(!fakename || source != original_host || !user.can_perform_action(source))
return
var/fakejob = sanitize_name(tgui_input_text(user, "Enter a job for the rigged message.", "Forge Message", max_length = MAX_NAME_LEN), allow_numbers = TRUE)
if(!fakejob || source != original_host || !user.canUseTopic(source, be_close = TRUE))
if(!fakejob || source != original_host || !user.can_perform_action(source))
return
var/datum/computer_file/program/messenger/app = locate() in source.stored_files
@@ -84,7 +84,7 @@
return
if(!isturf(loc) && !ismob(loc)) // No opening it in backpack.
return
if(!user.canUseTopic(src, be_close = TRUE))
if(!user.can_perform_action(src))
return
toggle_open(user)
@@ -179,7 +179,7 @@
/obj/item/modular_computer/pda/proc/remove_pen(mob/user)
if(issilicon(user) || !user.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE)) //TK doesn't work even with this removed but here for readability
if(issilicon(user) || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) //TK doesn't work even with this removed but here for readability
return
if(inserted_item)
@@ -237,7 +237,7 @@
if (!input_message || !sending_and_receiving)
return
if(!user.canUseTopic(computer, be_close = TRUE))
if(!user.can_perform_action(computer))
return
return sanitize(input_message)
@@ -400,7 +400,7 @@
if(computer.active_program != src)
if(!computer.open_program(usr, src))
return
if(!href_list["close"] && usr.canUseTopic(computer, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE))
if(!href_list["close"] && usr.can_perform_action(computer, FORBID_TELEKINESIS_REACH))
switch(href_list["choice"])
if("Message")
send_message(usr, list(locate(href_list["target"])))
+4 -3
View File
@@ -146,9 +146,10 @@
return ..()
// See software.dm for Topic()
/mob/living/silicon/pai/canUseTopic(atom/movable/movable, be_close = FALSE, no_dexterity = FALSE, no_tk = FALSE, need_hands = FALSE, floor_okay = FALSE)
// Resting is just an aesthetic feature for them.
return ..(movable, be_close, no_dexterity, no_tk, need_hands, TRUE)
/mob/living/silicon/pai/can_perform_action(atom/movable/target, action_bitflags)
action_bitflags |= ALLOW_RESTING // Resting is just an aesthetic feature for them
action_bitflags &= ~ALLOW_SILICON_REACH // They don't get long reach like the rest of silicons
return ..(target, action_bitflags)
/mob/living/silicon/pai/Destroy()
QDEL_NULL(atmos_analyzer)
+1 -1
View File
@@ -45,7 +45,7 @@
if(!inputvalue)
return
if(user.canUseTopic(src, be_close = TRUE))
if(user.can_perform_action(src))
name = "folder[(inputvalue ? " - '[inputvalue]'" : null)]"
/obj/item/folder/proc/remove_item(obj/item/Item, mob/user)
+1 -1
View File
@@ -113,7 +113,7 @@
. += span_notice("Alt-click [src] to fold it into a paper plane.")
/obj/item/paper/AltClick(mob/living/user, obj/item/I)
if(!user.canUseTopic(src, be_close = TRUE, no_dexterity = TRUE, no_tk = FALSE, need_hands = TRUE))
if(!user.can_perform_action(src, NEED_DEXTERITY|NEED_HANDS))
return
if(istype(src, /obj/item/paper/carbon))
var/obj/item/paper/carbon/Carbon = src
+5 -5
View File
@@ -142,7 +142,7 @@
to_chat(user, span_warning("You must be holding the pen to continue!"))
return
var/deg = tgui_input_number(user, "What angle would you like to rotate the pen head to? (0-360)", "Rotate Pen Head", max_value = 360)
if(isnull(deg) || QDELETED(user) || QDELETED(src) || !user.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE) || loc != user)
if(isnull(deg) || QDELETED(user) || QDELETED(src) || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH) || loc != user)
return
degrees = deg
to_chat(user, span_notice("You rotate the top of the pen to [deg] degrees."))
@@ -169,12 +169,12 @@
//Changing name/description of items. Only works if they have the UNIQUE_RENAME object flag set
if(isobj(O) && (O.obj_flags & UNIQUE_RENAME))
var/penchoice = tgui_input_list(user, "What would you like to edit?", "Pen Setting", list("Rename", "Description", "Reset"))
if(QDELETED(O) || !user.canUseTopic(O, be_close = TRUE))
if(QDELETED(O) || !user.can_perform_action(O))
return
if(penchoice == "Rename")
var/input = tgui_input_text(user, "What do you want to name [O]?", "Object Name", "[O.name]", MAX_NAME_LEN)
var/oldname = O.name
if(QDELETED(O) || !user.canUseTopic(O, be_close = TRUE))
if(QDELETED(O) || !user.can_perform_action(O))
return
if(input == oldname || !input)
to_chat(user, span_notice("You changed [O] to... well... [O]."))
@@ -190,7 +190,7 @@
if(penchoice == "Description")
var/input = tgui_input_text(user, "Describe [O]", "Description", "[O.desc]", 140)
var/olddesc = O.desc
if(QDELETED(O) || !user.canUseTopic(O, be_close = TRUE))
if(QDELETED(O) || !user.can_perform_action(O))
return
if(input == olddesc || !input)
to_chat(user, span_notice("You decide against changing [O]'s description."))
@@ -200,7 +200,7 @@
O.renamedByPlayer = TRUE
if(penchoice == "Reset")
if(QDELETED(O) || !user.canUseTopic(O, be_close = TRUE))
if(QDELETED(O) || !user.can_perform_action(O))
return
qdel(O.GetComponent(/datum/component/rename))
+1 -1
View File
@@ -486,7 +486,7 @@
/obj/machinery/photocopier/MouseDrop_T(mob/target, mob/user)
check_ass() //Just to make sure that you can re-drag somebody onto it after they moved off.
if(!istype(target) || target.anchored || target.buckled || !Adjacent(target) || !user.canUseTopic(src, be_close = TRUE) || target == ass || copier_blocked())
if(!istype(target) || target.anchored || target.buckled || !Adjacent(target) || !user.can_perform_action(src) || target == ass || copier_blocked())
return
add_fingerprint(user)
if(target == user)
+3 -3
View File
@@ -63,17 +63,17 @@
to_chat(user, span_warning("You must be holding the camera to continue!"))
return FALSE
var/desired_x = tgui_input_number(user, "How wide do you want the camera to shoot?", "Zoom", picture_size_x, picture_size_x_max, picture_size_x_min)
if(!desired_x || QDELETED(user) || QDELETED(src) || !user.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE) || loc != user)
if(!desired_x || QDELETED(user) || QDELETED(src) || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH) || loc != user)
return FALSE
var/desired_y = tgui_input_number(user, "How high do you want the camera to shoot", "Zoom", picture_size_y, picture_size_y_max, picture_size_y_min)
if(!desired_y || QDELETED(user) || QDELETED(src) || !user.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE) || loc != user)
if(!desired_y || QDELETED(user) || QDELETED(src) || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH) || loc != user)
return FALSE
picture_size_x = min(clamp(desired_x, picture_size_x_min, picture_size_x_max), CAMERA_PICTURE_SIZE_HARD_LIMIT)
picture_size_y = min(clamp(desired_y, picture_size_y_min, picture_size_y_max), CAMERA_PICTURE_SIZE_HARD_LIMIT)
return TRUE
/obj/item/camera/AltClick(mob/user)
if(!user.canUseTopic(src, be_close = TRUE))
if(!user.can_perform_action(src))
return
adjust_zoom(user)
+1 -1
View File
@@ -71,7 +71,7 @@
if(!user.can_write(P))
return
var/txt = tgui_input_text(user, "What would you like to write on the back?", "Photo Writing", max_length = 128)
if(txt && user.canUseTopic(src, be_close = TRUE))
if(txt && user.can_perform_action(src))
scribble = txt
else
return ..()
+1 -1
View File
@@ -66,7 +66,7 @@
to_chat(user, span_warning("A flashing notification on the screen reads: \"Output location error!\""))
return .
var/new_amount = tgui_input_number(user, "Set Amount to Fill", "Desired Amount", max_value = 100)
if(!new_amount || QDELETED(user) || QDELETED(src) || !user.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE))
if(!new_amount || QDELETED(user) || QDELETED(src) || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH))
return .
wanted_amount = new_amount
to_chat(user, span_notice(" The [src] will now fill for [wanted_amount]u."))
@@ -80,7 +80,7 @@
. = SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
var/new_volume = tgui_input_number(user, "Enter new activation threshold", "Beepityboop", activation_volume, buffer)
if(!new_volume || QDELETED(user) || QDELETED(src) || !user.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE))
if(!new_volume || QDELETED(user) || QDELETED(src) || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH))
return
activation_volume = new_volume
to_chat(user, span_notice("New activation threshold is now [activation_volume]."))
+1 -1
View File
@@ -173,7 +173,7 @@
. = ..()
if(!can_interact(user))
return
if(!user.canUseTopic(src, !issilicon(user)) || !isturf(loc))
if(!user.can_perform_action(src, ALLOW_SILICON_REACH) || !isturf(loc))
return
if(!ishuman(user))
return
+1 -1
View File
@@ -172,7 +172,7 @@ By design, d1 is the smallest direction and d2 is the highest
stored.update_appearance()
/obj/structure/pipe_cleaner/AltClick(mob/living/user)
if(!user.canUseTopic(src, be_close = TRUE))
if(!user.can_perform_action(src))
return
cut_pipe_cleaner(user)
+3 -3
View File
@@ -445,7 +445,7 @@
. = ..()
if(.)
return
if(!user.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE))
if(!user.can_perform_action(src, FORBID_TELEKINESIS_REACH))
return
if(bayonet && can_bayonet) //if it has a bayonet, and the bayonet can be removed
@@ -466,7 +466,7 @@
. = ..()
if(.)
return
if(!user.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE))
if(!user.can_perform_action(src, FORBID_TELEKINESIS_REACH))
return
if(pin && user.is_holding(src))
user.visible_message(span_warning("[user] attempts to remove [pin] from [src] with [I]."),
@@ -483,7 +483,7 @@
. = ..()
if(.)
return
if(!user.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE))
if(!user.can_perform_action(src, FORBID_TELEKINESIS_REACH))
return
if(pin && user.is_holding(src))
user.visible_message(span_warning("[user] attempts to remove [pin] from [src] with [I]."),
+1 -1
View File
@@ -424,7 +424,7 @@
return ..()
/obj/item/gun/ballistic/AltClick(mob/user)
if (unique_reskin && !current_skin && user.canUseTopic(src, be_close = TRUE, no_dexterity = TRUE))
if (unique_reskin && !current_skin && user.can_perform_action(src, NEED_DEXTERITY))
reskin_obj(user)
return
if(loc == user)
@@ -274,7 +274,7 @@
/obj/item/gun/ballistic/automatic/l6_saw/AltClick(mob/user)
if(!user.canUseTopic(src))
if(!user.can_perform_action(src))
return
cover_open = !cover_open
balloon_alert(user, "cover [cover_open ? "opened" : "closed"]")
@@ -119,7 +119,7 @@
balloon_alert(user, "switched to tube A")
/obj/item/gun/ballistic/shotgun/automatic/dual_tube/AltClick(mob/living/user)
if(!user.canUseTopic(src, be_close = TRUE, no_dexterity = TRUE, no_tk = FALSE, need_hands = TRUE))
if(!user.can_perform_action(src, NEED_DEXTERITY|NEED_HANDS))
return
rack()
@@ -275,7 +275,7 @@
/obj/item/gun/ballistic/shotgun/doublebarrel/AltClick(mob/user)
. = ..()
if(unique_reskin && !current_skin && user.canUseTopic(src, be_close = TRUE, no_dexterity = TRUE))
if(unique_reskin && !current_skin && user.can_perform_action(src, NEED_DEXTERITY))
reskin_obj(user)
/obj/item/gun/ballistic/shotgun/doublebarrel/sawoff(mob/user)
+2 -2
View File
@@ -265,7 +265,7 @@
owned = FALSE
return
var/transaction_amount = tgui_input_number(user, "Insert valid deposit amount for gun purchase", "Money Deposit")
if(!transaction_amount || QDELETED(user) || QDELETED(src) || !user.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE))
if(!transaction_amount || QDELETED(user) || QDELETED(src) || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH))
return
pin_owner = id
owned = TRUE
@@ -289,7 +289,7 @@
if(credit_card_details && !active_prompt)
var/license_request = tgui_alert(user, "Do you wish to pay [payment_amount] credit[( payment_amount > 1 ) ? "s" : ""] for [( multi_payment ) ? "each shot of [gun.name]" : "usage license of [gun.name]"]?", "Weapon Purchase", list("Yes", "No"))
active_prompt = TRUE
if(!user.canUseTopic(src, be_close = TRUE))
if(!user.can_perform_action(src))
active_prompt = FALSE
return FALSE
switch(license_request)
@@ -338,7 +338,7 @@
if(!is_operational)
return
var/name = tgui_input_text(usr, "What do you want to name this recipe?", "Recipe Name", MAX_NAME_LEN)
if(!usr.canUseTopic(src, !issilicon(usr)))
if(!usr.can_perform_action(src, ALLOW_SILICON_REACH))
return
if(saved_recipes[name] && tgui_alert(usr, "\"[name]\" already exists, do you want to overwrite it?",, list("Yes", "No")) == "No")
return
@@ -453,7 +453,7 @@
. = ..()
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
return
if(!can_interact(user) || !user.canUseTopic(src, !issilicon(user), FALSE, no_tk = TRUE))
if(!can_interact(user) || !user.can_perform_action(src, ALLOW_SILICON_REACH|FORBID_TELEKINESIS_REACH))
return
replace_beaker(user)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
@@ -64,7 +64,7 @@
. = ..()
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
return
if(!can_interact(user) || !user.canUseTopic(src, !issilicon(user), FALSE, no_tk = TRUE))
if(!can_interact(user) || !user.can_perform_action(src, ALLOW_SILICON_REACH|FORBID_TELEKINESIS_REACH))
return
replace_beaker(user)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
@@ -125,7 +125,7 @@ This will not clean any inverted reagents. Inverted reagents will still be corre
if(processing_reagents)
to_chat(user, "<span class='notice'> The [src] is currently processing a batch!")
return
if(!can_interact(user) || !user.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE))
if(!can_interact(user) || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH))
return ..()
replace_beaker(user, BEAKER1)
@@ -134,7 +134,7 @@ This will not clean any inverted reagents. Inverted reagents will still be corre
if(processing_reagents)
to_chat(user, "<span class='notice'> The [src] is currently processing a batch!")
return
if(!can_interact(user) || !user.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE))
if(!can_interact(user) || !user.can_perform_action(src, FORBID_TELEKINESIS_REACH))
return
replace_beaker(user, BEAKER2)
@@ -143,7 +143,7 @@
. = ..()
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
return
if(!can_interact(user) || !user.canUseTopic(src, !issilicon(user), FALSE, no_tk = TRUE))
if(!can_interact(user) || !user.can_perform_action(src, ALLOW_SILICON_REACH|FORBID_TELEKINESIS_REACH))
return
replace_beaker(user)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
@@ -379,7 +379,7 @@
"Name",
name_default,
MAX_NAME_LEN)
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.can_perform_action(src, ALLOW_SILICON_REACH))
return FALSE
// Start filling
if(item_type == "pill")
@@ -61,7 +61,7 @@
. = ..()
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
return
if(!can_interact(user) || !user.canUseTopic(src, !issilicon(user), FALSE, no_tk = TRUE))
if(!can_interact(user) || !user.can_perform_action(src, ALLOW_SILICON_REACH|FORBID_TELEKINESIS_REACH))
return
eject_beaker()
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
@@ -99,7 +99,7 @@
. = ..()
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
return
if(!can_interact(user) || !user.canUseTopic(src, !issilicon(user), FALSE, no_tk = TRUE))
if(!can_interact(user) || !user.can_perform_action(src, ALLOW_SILICON_REACH|FORBID_TELEKINESIS_REACH))
return
if(operating)
return
@@ -201,7 +201,7 @@
/obj/machinery/reagentgrinder/ui_interact(mob/user) // The microwave Menu //I am reasonably certain that this is not a microwave
. = ..()
if(operating || !user.canUseTopic(src, !issilicon(user)))
if(operating || !user.can_perform_action(src, ALLOW_SILICON_REACH))
return
var/list/options = list()
@@ -232,7 +232,7 @@
choice = show_radial_menu(user, src, options, require_near = !issilicon(user))
// post choice verification
if(operating || (isAI(user) && machine_stat & NOPOWER) || !user.canUseTopic(src, !issilicon(user)))
if(operating || (isAI(user) && machine_stat & NOPOWER) || !user.can_perform_action(src, ALLOW_SILICON_REACH))
return
switch(choice)
@@ -73,7 +73,7 @@
if(!user.can_write(tool))
return
var/custom_label = tgui_input_text(user, "What would you like to label the blood pack?", "Blood Pack", name, MAX_NAME_LEN)
if(!user.canUseTopic(src, be_close = TRUE))
if(!user.can_perform_action(src))
return
if(user.get_active_held_item() != tool)
return
@@ -13,7 +13,7 @@
possible_transfer_amounts = list()
/obj/item/reagent_containers/chem_pack/AltClick(mob/living/user)
if(user.canUseTopic(src, be_close = TRUE, no_dexterity = TRUE) && !sealed)
if(user.can_perform_action(src, NEED_DEXTERITY) && !sealed)
if(iscarbon(user) && (HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50)))
to_chat(user, span_warning("Uh... whoops! You accidentally spill the content of the bag onto yourself."))
SplashReagents(user)
@@ -533,7 +533,7 @@
if(!inputvalue)
return
if(user.canUseTopic(src, be_close = TRUE))
if(user.can_perform_action(src))
name = "[(inputvalue ? "[inputvalue]" : null)] bottle"
//types of syrups
@@ -134,7 +134,7 @@
update_appearance()
/obj/item/reagent_containers/hypospray/medipen/attack_self(mob/user)
if(user.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE, need_hands = FALSE, floor_okay = TRUE))
if(user.can_perform_action(src, FORBID_TELEKINESIS_REACH|ALLOW_RESTING))
inject(user, user)
/obj/item/reagent_containers/hypospray/medipen/update_icon_state()
@@ -401,7 +401,7 @@
"Blue" = "sprayer_med_blue")
/obj/item/reagent_containers/spray/medical/AltClick(mob/user)
if(unique_reskin && !current_skin && user.canUseTopic(src, be_close = TRUE, no_dexterity = TRUE))
if(unique_reskin && !current_skin && user.can_perform_action(src, NEED_DEXTERITY))
reskin_obj(user)
/obj/item/reagent_containers/spray/medical/reskin_obj(mob/M)
+1 -1
View File
@@ -410,7 +410,7 @@ GLOBAL_LIST_EMPTY(conveyors_by_id)
/obj/machinery/conveyor_switch/multitool_act(mob/living/user, obj/item/I)
var/input_speed = tgui_input_number(user, "Set the speed of the conveyor belts in seconds", "Speed", conveyor_speed, 20, 0.2, round_value = FALSE)
if(!input_speed || QDELETED(user) || QDELETED(src) || !usr.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE))
if(!input_speed || QDELETED(user) || QDELETED(src) || !usr.can_perform_action(src, FORBID_TELEKINESIS_REACH))
return
conveyor_speed = input_speed
to_chat(user, span_notice("You change the time between moves to [input_speed] seconds."))
+1 -1
View File
@@ -118,7 +118,7 @@
if(!user.can_write(item))
return
var/str = tgui_input_text(user, "Label text?", "Set label", max_length = MAX_NAME_LEN)
if(!user.canUseTopic(src, be_close = TRUE))
if(!user.can_perform_action(src))
return
if(!str || !length(str))
to_chat(user, span_warning("Invalid text!"))
@@ -186,7 +186,7 @@ Slimecrossing Items
if(M.mind)
to_chat(user, span_notice("You offer the device to [M]."))
if(tgui_alert(M, "Would you like to enter [user]'s capture device?", "Gold Capture Device", list("Yes", "No")) == "Yes")
if(user.canUseTopic(src, be_close = TRUE) && user.canUseTopic(M, be_close = TRUE))
if(user.can_perform_action(src) && user.can_perform_action(M))
to_chat(user, span_notice("You store [M] in the capture device."))
to_chat(M, span_notice("The world warps around you, and you're suddenly in an endless void, with a window to the outside floating in front of you."))
store(M, user)
@@ -176,7 +176,7 @@ Charged extracts:
if(isnull(racechoice))
to_chat(user, span_notice("You decide not to become a slime for now."))
return
if(!user.canUseTopic(src, be_close = TRUE))
if(!user.can_perform_action(src))
return
human_user.set_species(choice_list[racechoice], icon_update=1)
human_user.visible_message(span_warning("[human_user] suddenly shifts form as [src] dissolves into [human_user.p_their()] skin!"))
@@ -152,7 +152,7 @@ Stabilized extracts:
var/choice = tgui_input_list(user, "Which do you want to reset?", "Familiar Adjustment", sort_list(list("Familiar Location", "Familiar Species", "Familiar Sentience", "Familiar Name")))
if(isnull(choice))
return
if(!user.canUseTopic(src, be_close = TRUE))
if(!user.can_perform_action(src))
return
if(isliving(user))
var/mob/living/L = user
@@ -125,7 +125,7 @@
/obj/machinery/mecha_part_fabricator/AltClick(mob/user)
. = ..()
if(!user.canUseTopic(src, be_close = TRUE))
if(!user.can_perform_action(src))
return
if(panel_open)
dir = turn(dir, -90)
+1 -1
View File
@@ -89,7 +89,7 @@
chassis.toggle_strafe()
/obj/vehicle/sealed/mecha/AltClick(mob/living/user)
if(!(user in occupants) || !user.canUseTopic(src))
if(!(user in occupants) || !user.can_perform_action(src))
return
if(!(user in return_controllers_with_flag(VEHICLE_CONTROL_DRIVE)))
to_chat(user, span_warning("You're in the wrong seat to control movement."))
+1 -1
View File
@@ -40,7 +40,7 @@
inserted_key = I
/obj/vehicle/ridden/AltClick(mob/user)
if(!inserted_key || !user.canUseTopic(src, be_close = TRUE, no_dexterity = TRUE, no_tk = FALSE, need_hands = !issilicon(user)))
if(!inserted_key || !user.can_perform_action(src, NEED_DEXTERITY))
return ..()
if(!is_occupant(user))
to_chat(user, span_warning("You must be riding the [src] to remove [src]'s key!"))
+1 -1
View File
@@ -130,7 +130,7 @@
. = ..()
if(over_object != usr || !Adjacent(usr) || !foldabletype)
return FALSE
if(!ishuman(usr) || !usr.canUseTopic(src, be_close = TRUE))
if(!ishuman(usr) || !usr.can_perform_action(src))
return FALSE
if(has_buckled_mobs())
return FALSE
@@ -68,10 +68,10 @@
return
if(!message)
message = "circuit input"
if(!(user.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE)))
if(!(user.can_perform_action(src, FORBID_TELEKINESIS_REACH)))
return
var/picked = tgui_input_list(user, message = message, items = showed_list)
if(!(user.canUseTopic(src, be_close = TRUE, no_dexterity = FALSE, no_tk = TRUE)))
if(!(user.can_perform_action(src, FORBID_TELEKINESIS_REACH)))
return
choose_item(picked, showed_list)