[MIRROR] Standardizes attack chain signal returns and fixes a tk bug (#1409)

* Standardizes attack chain signal returns and fixes a tk bug (#54475)

The attack chain is a bit of a mess, and the introduction of signals hasn't helped in simplifying it.

In order to take a step into untangling this, I re-ordered the attack signals to no longer be by source type and instead to be grouped more modularly, as they are all members of the attack chain and function similarly. They all share the trait of potentially ending the attack chain via a return, but had several different names for it. I joined it into one.

Additionally, fixed a tk bug reported by @ Timberpoes by adding a signal return check at the base of /mob/proc/RangedAttack

Lastly, removed the async call of /datum/mutation/human/telekinesis/proc/on_ranged_attack, which was added as a lazy patch to appease the linter complaining about a sleep on a signal handler (namely in /obj/singularity/attack_tk). Fixed the problem using timers.

Also cleaned some code here and there.

* Standardizes attack chain signal returns and fixes a tk bug

Co-authored-by: Rohesie <rohesie@gmail.com>
This commit is contained in:
SkyratBot
2020-10-21 07:39:32 +02:00
committed by GitHub
co-authored by Rohesie
parent fcad7bb4c2
commit 6ecaa9a994
45 changed files with 327 additions and 198 deletions
+36 -40
View File
@@ -149,14 +149,6 @@
#define COMSIG_ATOM_ORBIT_BEGIN "atom_orbit_begin"
///called when an atom stops orbiting another atom: (atom)
#define COMSIG_ATOM_ORBIT_STOP "atom_orbit_stop"
/////////////////
///from base of atom/attack_ghost(): (mob/dead/observer/ghost)
#define COMSIG_ATOM_ATTACK_GHOST "atom_attack_ghost"
///from base of atom/attack_hand(): (mob/user)
#define COMSIG_ATOM_ATTACK_HAND "atom_attack_hand"
///from base of atom/attack_paw(): (mob/user)
#define COMSIG_ATOM_ATTACK_PAW "atom_attack_paw"
#define COMPONENT_NO_ATTACK_HAND (1<<0) //works on all 3.
///from base of atom/set_opacity(): (new_opacity)
#define COMSIG_ATOM_SET_OPACITY "atom_set_opacity"
@@ -327,19 +319,9 @@
#define COMPONENT_BLOCK_MAGIC (1<<0)
///from base of mob/create_mob_hud(): ()
#define COMSIG_MOB_HUD_CREATED "mob_hud_created"
///from base of atom/attack_hand(): (mob/user)
#define COMSIG_MOB_ATTACK_HAND "mob_attack_hand"
///from base of /obj/item/attack(): (mob/M, mob/user)
#define COMSIG_MOB_ITEM_ATTACK "mob_item_attack"
#define COMPONENT_ITEM_NO_ATTACK (1<<0)
///from base of /mob/living/proc/apply_damage(): (damage, damagetype, def_zone)
#define COMSIG_MOB_APPLY_DAMGE "mob_apply_damage"
///from base of obj/item/afterattack(): (atom/target, mob/user, proximity_flag, click_parameters)
#define COMSIG_MOB_ITEM_AFTERATTACK "mob_item_afterattack"
///from base of obj/item/attack_qdeleted(): (atom/target, mob/user, proxiumity_flag, click_parameters)
#define COMSIG_MOB_ITEM_ATTACK_QDELETED "mob_item_attack_qdeleted"
///from base of mob/RangedAttack(): (atom/A, params)
#define COMSIG_MOB_ATTACK_RANGED "mob_attack_ranged"
///from base of /mob/throw_item(): (atom/target)
#define COMSIG_MOB_THROW "mob_throw"
///from base of /mob/verb/examinate(): (atom/target)
@@ -494,21 +476,6 @@
// /obj/item signals
///from base of obj/item/attack(): (/mob/living/target, /mob/living/user)
#define COMSIG_ITEM_ATTACK "item_attack"
///from base of obj/item/attack_self(): (/mob)
#define COMSIG_ITEM_ATTACK_SELF "item_attack_self"
#define COMPONENT_NO_INTERACT (1<<0)
///from base of obj/item/attack_obj(): (/obj, /mob)
#define COMSIG_ITEM_ATTACK_OBJ "item_attack_obj"
#define COMPONENT_NO_ATTACK_OBJ (1<<0)
///from base of obj/item/pre_attack(): (atom/target, mob/user, params)
#define COMSIG_ITEM_PRE_ATTACK "item_pre_attack"
#define COMPONENT_NO_ATTACK (1<<0)
///from base of obj/item/afterattack(): (atom/target, mob/user, params)
#define COMSIG_ITEM_AFTERATTACK "item_afterattack"
///from base of obj/item/attack_qdeleted(): (atom/target, mob/user, params)
#define COMSIG_ITEM_ATTACK_QDELETED "item_attack_qdeleted"
///from base of obj/item/equipped(): (/mob/equipper, slot)
#define COMSIG_ITEM_EQUIPPED "item_equip"
///from base of obj/item/dropped(): (mob/user)
@@ -649,12 +616,6 @@
// /mob/living/carbon/human signals
///from mob/living/carbon/human/UnarmedAttack(): (atom/target, proximity)
#define COMSIG_HUMAN_EARLY_UNARMED_ATTACK "human_early_unarmed_attack"
///from mob/living/carbon/human/UnarmedAttack(): (atom/target, proximity)
#define COMSIG_HUMAN_MELEE_UNARMED_ATTACK "human_melee_unarmed_attack"
///from mob/living/carbon/human/UnarmedAttack(): (mob/living/carbon/human/attacker)
#define COMSIG_HUMAN_MELEE_UNARMED_ATTACKBY "human_melee_unarmed_attackby"
///Hit by successful disarm attack (mob/living/carbon/human/attacker,zone_targeted)
#define COMSIG_HUMAN_DISARM_HIT "human_disarm_hit"
///Whenever EquipRanked is called, called after job is set
@@ -840,3 +801,38 @@
// /datum/component/container_item
/// (atom/container, mob/user) - returns bool
#define COMSIG_CONTAINER_TRY_ATTACH "container_try_attach"
/* Attack signals. They should share the returned flags, to standardize the attack chain. */
#define COMPONENT_CANCEL_ATTACK_CHAIN (1<<0)
///from base of atom/attack_ghost(): (mob/dead/observer/ghost)
#define COMSIG_ATOM_ATTACK_GHOST "atom_attack_ghost"
///from base of atom/attack_hand(): (mob/user)
#define COMSIG_ATOM_ATTACK_HAND "atom_attack_hand"
///from base of atom/attack_paw(): (mob/user)
#define COMSIG_ATOM_ATTACK_PAW "atom_attack_paw"
///from base of obj/item/attack(): (/mob/living/target, /mob/living/user)
#define COMSIG_ITEM_ATTACK "item_attack"
///from base of obj/item/attack_self(): (/mob)
#define COMSIG_ITEM_ATTACK_SELF "item_attack_self"
///from base of obj/item/attack_obj(): (/obj, /mob)
#define COMSIG_ITEM_ATTACK_OBJ "item_attack_obj"
///from base of obj/item/pre_attack(): (atom/target, mob/user, params)
#define COMSIG_ITEM_PRE_ATTACK "item_pre_attack"
///from base of obj/item/afterattack(): (atom/target, mob/user, params)
#define COMSIG_ITEM_AFTERATTACK "item_afterattack"
///from base of obj/item/attack_qdeleted(): (atom/target, mob/user, params)
#define COMSIG_ITEM_ATTACK_QDELETED "item_attack_qdeleted"
///from base of atom/attack_hand(): (mob/user)
#define COMSIG_MOB_ATTACK_HAND "mob_attack_hand"
///from base of /obj/item/attack(): (mob/M, mob/user)
#define COMSIG_MOB_ITEM_ATTACK "mob_item_attack"
///from base of obj/item/afterattack(): (atom/target, mob/user, proximity_flag, click_parameters)
#define COMSIG_MOB_ITEM_AFTERATTACK "mob_item_afterattack"
///from base of obj/item/attack_qdeleted(): (atom/target, mob/user, proxiumity_flag, click_parameters)
#define COMSIG_MOB_ITEM_ATTACK_QDELETED "mob_item_attack_qdeleted"
///from base of mob/RangedAttack(): (atom/A, params)
#define COMSIG_MOB_ATTACK_RANGED "mob_attack_ranged"
///from mob/living/carbon/human/UnarmedAttack(): (atom/target, proximity)
#define COMSIG_HUMAN_EARLY_UNARMED_ATTACK "human_early_unarmed_attack"
///from mob/living/carbon/human/UnarmedAttack(): (atom/target, proximity)
#define COMSIG_HUMAN_MELEE_UNARMED_ATTACK "human_melee_unarmed_attack"
+2 -1
View File
@@ -277,7 +277,8 @@
* animals lunging, etc.
*/
/mob/proc/RangedAttack(atom/A, params)
SEND_SIGNAL(src, COMSIG_MOB_ATTACK_RANGED, A, params)
if(SEND_SIGNAL(src, COMSIG_MOB_ATTACK_RANGED, A, params) & COMPONENT_CANCEL_ATTACK_CHAIN)
return TRUE
/**
+8 -7
View File
@@ -21,7 +21,7 @@
/// Called when the item is in the active hand, and clicked; alternately, there is an 'activate held object' verb or you can hit pagedown.
/obj/item/proc/attack_self(mob/user)
if(SEND_SIGNAL(src, COMSIG_ITEM_ATTACK_SELF, user) & COMPONENT_NO_INTERACT)
if(SEND_SIGNAL(src, COMSIG_ITEM_ATTACK_SELF, user) & COMPONENT_CANCEL_ATTACK_CHAIN)
return
SEND_SIGNAL(user, COMSIG_MOB_ITEM_ATTACK_SELF, src) //SKYRAT EDIT ADDITION - GUNPOINT
interact(user)
@@ -37,7 +37,7 @@
* See: [/obj/item/proc/melee_attack_chain]
*/
/obj/item/proc/pre_attack(atom/A, mob/living/user, params) //do stuff before attackby!
if(SEND_SIGNAL(src, COMSIG_ITEM_PRE_ATTACK, A, user, params) & COMPONENT_NO_ATTACK)
if(SEND_SIGNAL(src, COMSIG_ITEM_PRE_ATTACK, A, user, params) & COMPONENT_CANCEL_ATTACK_CHAIN)
return TRUE
return FALSE //return TRUE to avoid calling attackby after this proc does stuff
@@ -73,21 +73,21 @@
* * mob/living/user - The mob hitting with this item
*/
/obj/item/proc/attack(mob/living/M, mob/living/user)
if(SEND_SIGNAL(src, COMSIG_ITEM_ATTACK, M, user) & COMPONENT_ITEM_NO_ATTACK)
return
if(SEND_SIGNAL(src, COMSIG_ITEM_ATTACK, M, user) & COMPONENT_CANCEL_ATTACK_CHAIN)
return TRUE
SEND_SIGNAL(user, COMSIG_MOB_ITEM_ATTACK, M, user)
if(item_flags & NOBLUDGEON)
return
if(force && HAS_TRAIT(user, TRAIT_PACIFISM))
to_chat(user, "<span class='warning'>You don't want to harm other living beings!</span>")
return
return TRUE
if(item_flags & EYE_STAB && user.zone_selected == BODY_ZONE_PRECISE_EYES)
if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50))
M = user
if(eyestab(M,user))
return
return TRUE
if(!force)
playsound(loc, 'sound/weapons/tap.ogg', get_clamped_volume(), TRUE, -1)
else if(hitsound)
@@ -104,11 +104,12 @@
log_combat(user, M, "attacked", src.name, "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(damtype)])")
add_fingerprint(user)
return TRUE
/// The equivalent of the standard version of [/obj/item/proc/attack] but for object targets.
/obj/item/proc/attack_obj(obj/O, mob/living/user)
if(SEND_SIGNAL(src, COMSIG_ITEM_ATTACK_OBJ, O, user) & COMPONENT_NO_ATTACK_OBJ)
if(SEND_SIGNAL(src, COMSIG_ITEM_ATTACK_OBJ, O, user) & COMPONENT_CANCEL_ATTACK_CHAIN)
return
if(item_flags & NOBLUDGEON)
return
+1 -1
View File
@@ -48,7 +48,7 @@
// Oh by the way this didn't work with old click code which is why clicking shit didn't spam you
/atom/proc/attack_ghost(mob/dead/observer/user)
if(SEND_SIGNAL(src, COMSIG_ATOM_ATTACK_GHOST, user) & COMPONENT_NO_ATTACK_HAND)
if(SEND_SIGNAL(src, COMSIG_ATOM_ATTACK_GHOST, user) & COMPONENT_CANCEL_ATTACK_CHAIN)
return TRUE
if(user.client)
if(user.gas_scan && atmosanalyzer_scan(user, src))
+8 -6
View File
@@ -25,7 +25,7 @@
if(proximity && istype(G) && G.Touch(A,1))
return
//This signal is needed to prevent gloves of the north star + hulk.
if(SEND_SIGNAL(src, COMSIG_HUMAN_EARLY_UNARMED_ATTACK, A, proximity) & COMPONENT_NO_ATTACK_HAND)
if(SEND_SIGNAL(src, COMSIG_HUMAN_EARLY_UNARMED_ATTACK, A, proximity) & COMPONENT_CANCEL_ATTACK_CHAIN)
return
SEND_SIGNAL(src, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, A, proximity)
A.attack_hand(src)
@@ -35,7 +35,7 @@
. = FALSE
if(!(interaction_flags_atom & INTERACT_ATOM_NO_FINGERPRINT_ATTACK_HAND))
add_fingerprint(user)
if(SEND_SIGNAL(src, COMSIG_ATOM_ATTACK_HAND, user) & COMPONENT_NO_ATTACK_HAND)
if(SEND_SIGNAL(src, COMSIG_ATOM_ATTACK_HAND, user) & COMPONENT_CANCEL_ATTACK_CHAIN)
. = TRUE
if(interaction_flags_atom & INTERACT_ATOM_ATTACK_HAND)
. = _try_interact(user)
@@ -82,14 +82,16 @@
/mob/living/carbon/human/RangedAttack(atom/A, mouseparams)
. = ..()
if(.)
return
if(gloves)
var/obj/item/clothing/gloves/G = gloves
if(istype(G) && G.Touch(A,0)) // for magic gloves
return
return TRUE
if(isturf(A) && get_dist(src,A) <= 1)
src.Move_Pulled(A)
return
Move_Pulled(A)
return TRUE
/*
Animals & All Unspecified
@@ -135,7 +137,7 @@
/atom/proc/attack_paw(mob/user)
if(SEND_SIGNAL(src, COMSIG_ATOM_ATTACK_PAW, user) & COMPONENT_NO_ATTACK_HAND)
if(SEND_SIGNAL(src, COMSIG_ATOM_ATTACK_PAW, user) & COMPONENT_CANCEL_ATTACK_CHAIN)
return TRUE
return FALSE
+54 -28
View File
@@ -4,57 +4,74 @@
This needs more thinking out, but I might as well.
*/
/*
Telekinetic attack:
By default, emulate the user's unarmed attack
*/
#define TK_MAXRANGE 15
/**
* Telekinesis attack act, happens when the TK user clicks on a non-adjacent target in range.
*
* * By default, emulates the user's unarmed attack.
* * Called indirectly by the `COMSIG_MOB_ATTACK_RANGED` signal.
* * Returns `COMPONENT_CANCEL_ATTACK_CHAIN` when it performs any action, to further acts on the attack chain.
*/
/atom/proc/attack_tk(mob/user)
if(user.stat || !tkMaxRangeCheck(user, src))
return
new /obj/effect/temp_visual/telekinesis(get_turf(src))
user.UnarmedAttack(src,0) // attack_hand, attack_paw, etc
add_hiddenprint(user)
return
user.UnarmedAttack(src, FALSE) // attack_hand, attack_paw, etc
return COMPONENT_CANCEL_ATTACK_CHAIN
/obj/attack_tk(mob/user)
if(user.stat)
return
if(anchored)
return ..()
attack_tk_grab(user)
return attack_tk_grab(user)
/obj/item/attack_tk(mob/user)
if(user.stat)
return
attack_tk_grab(user)
return attack_tk_grab(user)
/**
* Telekinesis object grab act.
*
* * Called by `/obj/attack_tk()`.
* * Returns `COMPONENT_CANCEL_ATTACK_CHAIN` when it performs any action, to further acts on the attack chain.
*/
/obj/proc/attack_tk_grab(mob/user)
var/obj/item/tk_grab/O = new(src)
O.tk_user = user
if(O.focus_object(src))
user.put_in_active_hand(O)
add_hiddenprint(user)
if(!O.focus_object(src))
return
user.put_in_active_hand(O)
add_hiddenprint(user)
return COMPONENT_CANCEL_ATTACK_CHAIN
/mob/attack_tk(mob/user)
return
/*
This is similar to item attack_self, but applies to anything
that you can grab with a telekinetic grab.
It is used for manipulating things at range, for example, opening and closing closets.
There are not a lot of defaults at this time, add more where appropriate.
*/
/**
* Telekinesis item attack_self act.
*
* * This is similar to item attack_self, but applies to anything that you can grab with a telekinetic grab.
* * It is used for manipulating things at range, for example, opening and closing closets..
* * Defined at the `/atom` level but only used at the `/obj/item` one.
* * Returns `COMPONENT_CANCEL_ATTACK_CHAIN` when it performs any action, to further acts on the attack chain.
*/
/atom/proc/attack_self_tk(mob/user)
return
/obj/item/attack_self_tk(mob/user)
attack_self(user)
if(attack_self(user))
return COMPONENT_CANCEL_ATTACK_CHAIN
/*
@@ -112,44 +129,53 @@
else
return ..()
/obj/item/tk_grab/attack_self(mob/user)
if(!focus)
return
if(QDELETED(focus))
if(QDELING(focus))
qdel(src)
return
focus.attack_self_tk(user)
if(focus.attack_self_tk(user) & COMPONENT_CANCEL_ATTACK_CHAIN)
. = TRUE
update_icon()
/obj/item/tk_grab/afterattack(atom/target, mob/living/carbon/user, proximity, params)//TODO: go over this
. = ..()
if(.)
return
if(!target || !user)
return
if(!focus)
focus_object(target)
return
else if(!check_if_focusable(focus))
return TRUE
if(!check_if_focusable(focus))
return
if(target == focus)
target.attack_self_tk(user)
if(target.attack_self_tk(user) & COMPONENT_CANCEL_ATTACK_CHAIN)
. = TRUE
update_icon()
return
if(!isturf(target) && isitem(focus) && target.Adjacent(focus))
apply_focus_overlay()
var/obj/item/I = focus
I.melee_attack_chain(tk_user, target, params) //isn't copying the attack chain fun. we should do it more often.
. = I.melee_attack_chain(tk_user, target, params) //isn't copying the attack chain fun. we should do it more often.
if(check_if_focusable(focus))
focus.do_attack_animation(target, null, focus)
else
. = TRUE
apply_focus_overlay()
focus.throw_at(target, 10, 1,user)
user.changeNext_move(CLICK_CD_MELEE)
update_icon()
/proc/tkMaxRangeCheck(mob/user, atom/target)
var/d = get_dist(user, target)
if(d > TK_MAXRANGE)
+2 -1
View File
@@ -198,7 +198,8 @@
to_chat(user, "<span class='warning'>The acid on \the [parent_atom] burns your hand!</span>")
playsound(parent_atom, 'sound/weapons/sear.ogg', 50, TRUE)
user.update_damage_overlays()
return COMPONENT_NO_ATTACK_HAND
return COMPONENT_CANCEL_ATTACK_CHAIN
/// Handles searing the feet of whoever walks over this without protection. Only active if the parent is a turf.
/datum/component/acid/proc/on_crossed(atom/parent_atom, mob/living/crosser)
+3 -3
View File
@@ -30,7 +30,7 @@
if(M.stat == DEAD && (M.butcher_results || M.guaranteed_butcher_results)) //can we butcher it?
if(butchering_enabled && (can_be_blunt || source.get_sharpness()))
INVOKE_ASYNC(src, .proc/startButcher, source, M, user)
return COMPONENT_ITEM_NO_ATTACK
return COMPONENT_CANCEL_ATTACK_CHAIN
if(ishuman(M) && source.force && source.get_sharpness())
var/mob/living/carbon/human/H = M
@@ -38,9 +38,9 @@
if(H.has_status_effect(/datum/status_effect/neck_slice))
user.show_message("<span class='warning'>[H]'s neck has already been already cut, you can't make the bleeding any worse!</span>", MSG_VISUAL, \
"<span class='warning'>Their neck has already been already cut, you can't make the bleeding any worse!</span>")
return COMPONENT_ITEM_NO_ATTACK
return COMPONENT_CANCEL_ATTACK_CHAIN
INVOKE_ASYNC(src, .proc/startNeckSlice, source, H, user)
return COMPONENT_ITEM_NO_ATTACK
return COMPONENT_CANCEL_ATTACK_CHAIN
/datum/component/butchering/proc/startButcher(obj/item/source, mob/living/M, mob/living/user)
to_chat(user, "<span class='notice'>You begin to butcher [M]...</span>")
+2 -2
View File
@@ -276,7 +276,7 @@ Behavior that's still missing from this component that original food items had t
return
var/fullness = eater.get_fullness() + 10 //The theoretical fullness of the person eating if they were to eat this
. = COMPONENT_ITEM_NO_ATTACK //Point of no return I suppose
. = COMPONENT_CANCEL_ATTACK_CHAIN //Point of no return I suppose
if(eater == feeder)//If you're eating it yourself.
if(!do_mob(feeder, eater, eat_time)) //Gotta pass the minimal eat time
@@ -416,7 +416,7 @@ Behavior that's still missing from this component that original food items had t
if(bitecount == 0 || prob(50))
L.manual_emote("nibbles away at \the [parent].")
bitecount++
. = COMPONENT_ITEM_NO_ATTACK
. = COMPONENT_CANCEL_ATTACK_CHAIN
L.taste(owner.reagents) // why should carbons get all the fun?
if(bitecount >= 5)
var/satisfaction_text = pick("burps from enjoyment.", "yaps for more!", "woofs twice.", "looks at the area where \the [parent] was.")
@@ -71,7 +71,7 @@
"<span class='notice'>You start to insert the [inserted_item.name] into \the [parent].</span>")
INVOKE_ASYNC(src, .proc/insert_item, inserted_item, user)
return COMPONENT_ITEM_NO_ATTACK
return COMPONENT_CANCEL_ATTACK_CHAIN
/** Begins the process of attempting to remove the stored item.
*
@@ -93,7 +93,7 @@
"<span class='notice'>You start to rip into \the [parent].</span>")
INVOKE_ASYNC(src, .proc/begin_remove_item, user)
return COMPONENT_ITEM_NO_ATTACK
return COMPONENT_CANCEL_ATTACK_CHAIN
/** Inserts the item into the food, after a do_after.
*
+7 -5
View File
@@ -195,7 +195,7 @@
if(!isitem(O) || !click_gather || SEND_SIGNAL(O, COMSIG_CONTAINS_STORAGE))
return FALSE
. = COMPONENT_NO_ATTACK
. = COMPONENT_CANCEL_ATTACK_CHAIN
if(locked)
to_chat(M, "<span class='warning'>[parent] seems to be locked!</span>")
return FALSE
@@ -771,6 +771,7 @@
return TRUE
return TRUE
/datum/component/storage/proc/on_attack_hand(datum/source, mob/user)
SIGNAL_HANDLER_DOES_SLEEP
@@ -780,7 +781,7 @@
if(user.active_storage == src && A.loc == user) //if you're already looking inside the storage item
user.active_storage.close(user)
close(user)
. = COMPONENT_NO_ATTACK_HAND
. = COMPONENT_CANCEL_ATTACK_CHAIN
return
if(rustle_sound)
@@ -789,23 +790,24 @@
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(H.l_store == A && !H.get_active_held_item()) //Prevents opening if it's in a pocket.
. = COMPONENT_NO_ATTACK_HAND
. = COMPONENT_CANCEL_ATTACK_CHAIN
H.put_in_hands(A)
H.l_store = null
return
if(H.r_store == A && !H.get_active_held_item())
. = COMPONENT_NO_ATTACK_HAND
. = COMPONENT_CANCEL_ATTACK_CHAIN
H.put_in_hands(A)
H.r_store = null
return
if(A.loc == user)
. = COMPONENT_NO_ATTACK_HAND
. = COMPONENT_CANCEL_ATTACK_CHAIN
if(locked)
to_chat(user, "<span class='warning'>[parent] seems to be locked!</span>")
else
show_to(user)
/datum/component/storage/proc/signal_on_pickup(datum/source, mob/user)
SIGNAL_HANDLER
+1 -1
View File
@@ -39,7 +39,7 @@
var/mob/living/carbon/carbontarget
var/obj/item/bodypart/affecting
var/selected_zone = user.zone_selected
. = COMPONENT_ITEM_NO_ATTACK
. = COMPONENT_CANCEL_ATTACK_CHAIN
if(iscarbon(livingtarget))
carbontarget = livingtarget
+2 -2
View File
@@ -84,12 +84,12 @@ This component is used in vat growing to swab for microbiological samples which
var/obj/item/I = parent
I.update_icon()
return COMPONENT_NO_ATTACK
return COMPONENT_CANCEL_ATTACK_CHAIN
if(!can_swab(target))
return NONE //Just do the normal attack.
. = COMPONENT_NO_ATTACK //Point of no return. No more attacking after this.
. = COMPONENT_CANCEL_ATTACK_CHAIN //Point of no return. No more attacking after this.
if(LAZYLEN(swabbed_items))
to_chat(user, "<span class='warning'>You cannot collect another sample on [parent]!</span>")
+2 -1
View File
@@ -122,7 +122,8 @@
if(user)
ui_interact(user)
// an unlocked uplink blocks also opening the PDA or headset menu
return COMPONENT_NO_INTERACT
return COMPONENT_CANCEL_ATTACK_CHAIN
/datum/component/uplink/ui_state(mob/user)
return GLOB.inventory_state
+1 -1
View File
@@ -41,7 +41,7 @@
source.do_attack_animation(target, ATTACK_EFFECT_SMASH)
source.changeNext_move(CLICK_CD_MELEE)
return COMPONENT_NO_ATTACK_HAND
return COMPONENT_CANCEL_ATTACK_CHAIN
/**
+2 -3
View File
@@ -29,7 +29,6 @@
return visual_indicators[type][1]
///Triggers on COMSIG_MOB_ATTACK_RANGED. Usually handles stuff like picking up items at range.
/datum/mutation/human/telekinesis/proc/on_ranged_attack(datum/source, atom/target)
/datum/mutation/human/telekinesis/proc/on_ranged_attack(mob/source, atom/target)
SIGNAL_HANDLER
INVOKE_ASYNC(target, /atom.proc/attack_tk, owner)
return target.attack_tk(source)
+2 -1
View File
@@ -100,7 +100,8 @@
INVOKE_ASYNC(victim, /mob.proc/emote, "scream")
victim.Stun(0.5 SECONDS)
limb.receive_damage(brute=rand(3,7))
return COMPONENT_NO_ATTACK_HAND
return COMPONENT_CANCEL_ATTACK_CHAIN
/datum/wound/blunt/receive_damage(wounding_type, wounding_dmg, wound_bonus)
if(!victim || wounding_dmg < WOUND_MINIMUM_DAMAGE)
+3
View File
@@ -93,6 +93,7 @@
removecell()
/obj/machinery/cell_charger/attack_tk(mob/user)
if(!charging)
return
@@ -101,6 +102,8 @@
to_chat(user, "<span class='notice'>You telekinetically remove [charging] from [src].</span>")
removecell()
return COMPONENT_CANCEL_ATTACK_CHAIN
/obj/machinery/cell_charger/attack_ai(mob/user)
return
+3 -1
View File
@@ -177,10 +177,12 @@
return
return try_to_activate_door(user)
/obj/machinery/door/attack_tk(mob/user)
if(requiresID() && !allowed(null))
return
..()
return ..()
/obj/machinery/door/proc/try_to_activate_door(mob/user)
add_fingerprint(user)
+8 -4
View File
@@ -113,11 +113,15 @@
user.put_in_hands(charging)
setCharging(null)
/obj/machinery/recharger/attack_tk(mob/user)
if(charging)
charging.update_icon()
charging.forceMove(drop_location())
setCharging(null)
if(!charging)
return
charging.update_icon()
charging.forceMove(drop_location())
setCharging(null)
return COMPONENT_CANCEL_ATTACK_CHAIN
/obj/machinery/recharger/process(delta_time)
if(machine_stat & (NOPOWER|BROKEN) || !anchored)
+3 -1
View File
@@ -192,9 +192,11 @@ GLOBAL_LIST_EMPTY(PDAs)
return attack_self(M)
return ..()
/obj/item/pda/attack_self_tk(mob/user)
to_chat(user, "<span class='warning'>The PDA's capacitive touch screen doesn't seem to respond!</span>")
return
return COMPONENT_CANCEL_ATTACK_CHAIN
/obj/item/pda/interact(mob/user)
if(!user.IsAdvancedToolUser())
@@ -62,6 +62,8 @@
*/
/obj/item/radio/intercom/attack_tk_grab(mob/user)
interact(user)
return COMPONENT_CANCEL_ATTACK_CHAIN
/obj/item/radio/intercom/attack_ai(mob/user)
interact(user)
+4 -2
View File
@@ -124,8 +124,10 @@
inhand_icon_state = "supermattersliver"
pulseicon = "supermatter_sliver_pulse"
/obj/item/nuke_core/supermatter_sliver/attack_tk() // no TK dusting memes
return FALSE
/obj/item/nuke_core/supermatter_sliver/attack_tk(mob/user) // no TK dusting memes
return
/obj/item/nuke_core/supermatter_sliver/can_be_pulled(user) // no drag memes
return FALSE
+2
View File
@@ -193,6 +193,8 @@
timer = world.time + cooldown
if(!quiet)
playsound(user, 'sound/mecha/mechstep.ogg', 20, TRUE)
return COMPONENT_CANCEL_ATTACK_CHAIN
/**
* Resets the request for battle.
@@ -89,11 +89,13 @@
else
return ..()
/obj/structure/chair/attack_tk(mob/user)
if(!anchored || has_buckled_mobs() || !isturf(user.loc))
..()
else
setDir(turn(dir,-90))
return ..()
setDir(turn(dir,-90))
return COMPONENT_CANCEL_ATTACK_CHAIN
/obj/structure/chair/proc/handle_rotation(direction)
handle_layer()
+3 -2
View File
@@ -393,8 +393,9 @@ LINEN BINS
to_chat(user, "<span class='notice'>[hidden] falls out of [B]!</span>")
hidden = null
add_fingerprint(user)
/obj/structure/bedsheetbin/attack_tk(mob/user)
if(amount >= 1)
amount--
@@ -415,5 +416,5 @@ LINEN BINS
hidden.forceMove(drop_location())
hidden = null
add_fingerprint(user)
return COMPONENT_CANCEL_ATTACK_CHAIN
@@ -374,7 +374,8 @@
// tk grab then use on self
/obj/structure/closet/attack_self_tk(mob/user)
return attack_hand(user)
if(attack_hand(user))
return COMPONENT_CANCEL_ATTACK_CHAIN
/obj/structure/closet/verb/verb_toggleopen()
set src in view(1)
+4 -3
View File
@@ -93,15 +93,16 @@
/obj/structure/extinguisher_cabinet/attack_tk(mob/user)
. = COMPONENT_CANCEL_ATTACK_CHAIN
if(stored_extinguisher)
stored_extinguisher.forceMove(loc)
to_chat(user, "<span class='notice'>You telekinetically remove [stored_extinguisher] from [src].</span>")
stored_extinguisher = null
opened = 1
opened = TRUE
playsound(loc, 'sound/machines/click.ogg', 15, TRUE, -3)
update_icon()
else
toggle_cabinet(user)
return
toggle_cabinet(user)
/obj/structure/extinguisher_cabinet/attack_paw(mob/user)
+5 -4
View File
@@ -131,14 +131,15 @@
toggle_lock(user)
return
/obj/structure/fireaxecabinet/attack_tk(mob/user)
. = COMPONENT_CANCEL_ATTACK_CHAIN
if(locked)
to_chat(user, "<span class='warning'>The [name] won't budge!</span>")
return
else
open = !open
update_icon()
return
open = !open
update_icon()
/obj/structure/fireaxecabinet/update_overlays()
. = ..()
+4 -2
View File
@@ -88,8 +88,10 @@
user.stop_pulling()
return ..()
/obj/structure/table/attack_tk()
return FALSE
/obj/structure/table/attack_tk(mob/user)
return
/obj/structure/table/CanAllowThrough(atom/movable/mover, turf/target)
. = ..()
+3
View File
@@ -130,11 +130,14 @@
return FALSE
return TRUE
/obj/structure/window/attack_tk(mob/user)
user.changeNext_move(CLICK_CD_MELEE)
user.visible_message("<span class='notice'>Something knocks on [src].</span>")
add_fingerprint(user)
playsound(src, knocksound, 50, TRUE)
return COMPONENT_CANCEL_ATTACK_CHAIN
/obj/structure/window/attack_hulk(mob/living/carbon/human/user, does_attack_animation = 0)
if(!can_be_reached(user))
@@ -223,26 +223,29 @@
else
to_chat(human_user,"<span class='danger'>You pull your hand away from the hole as the eldritch energy flails trying to catch onto the existance itself!</span>")
/obj/effect/broken_illusion/attack_tk(mob/user)
if(!ishuman(user))
return
. = COMPONENT_CANCEL_ATTACK_CHAIN
var/mob/living/carbon/human/human_user = user
if(IS_HERETIC(human_user))
to_chat(human_user,"<span class='boldwarning'>You know better than to tempt forces out of your control!</span>")
return
//a very elaborate way to suicide
to_chat(human_user,"<span class='userdanger'>Eldritch energy lashes out, piercing your fragile mind, tearing it to pieces!</span>")
human_user.ghostize()
var/obj/item/bodypart/head/head = locate() in human_user.bodyparts
if(head)
head.dismember()
qdel(head)
else
//a very elaborate way to suicide
to_chat(human_user,"<span class='userdanger'>Eldritch energy lashes out, piercing your fragile mind, tearing it to pieces!</span>")
human_user.ghostize()
var/obj/item/bodypart/head/head = locate() in human_user.bodyparts
if(head)
head.dismember()
qdel(head)
else
human_user.gib()
human_user.gib()
var/datum/effect_system/reagents_explosion/explosion = new()
explosion.set_up(1, get_turf(human_user), TRUE, 0)
explosion.start()
var/datum/effect_system/reagents_explosion/explosion = new()
explosion.set_up(1, get_turf(human_user), 1, 0)
explosion.start()
/obj/effect/broken_illusion/examine(mob/user)
. = ..()
@@ -119,17 +119,21 @@
eat()
return
/obj/singularity/wizard/attack_tk(mob/user)
if(iscarbon(user))
var/mob/living/carbon/C = user
var/datum/component/mood/insaneinthemembrane = C.GetComponent(/datum/component/mood)
if(insaneinthemembrane.sanity < 15)
return //they've already seen it and are about to die, or are just too insane to care
to_chat(C, "<span class='userdanger'>OH GOD! NONE OF IT IS REAL! NONE OF IT IS REEEEEEEEEEEEEEEEEEEEEEEEAL!</span>")
insaneinthemembrane.sanity = 0
for(var/lore in typesof(/datum/brain_trauma/severe))
C.gain_trauma(lore)
addtimer(CALLBACK(src, /obj/singularity/wizard.proc/deranged, C), 100)
if(!iscarbon(user))
return
. = COMPONENT_CANCEL_ATTACK_CHAIN
var/mob/living/carbon/jedi = user
var/datum/component/mood/insaneinthemembrane = jedi.GetComponent(/datum/component/mood)
if(insaneinthemembrane.sanity < 15)
return //they've already seen it and are about to die, or are just too insane to care
to_chat(jedi, "<span class='userdanger'>OH GOD! NONE OF IT IS REAL! NONE OF IT IS REEEEEEEEEEEEEEEEEEEEEEEEAL!</span>")
insaneinthemembrane.sanity = 0
for(var/lore in typesof(/datum/brain_trauma/severe))
jedi.gain_trauma(lore)
addtimer(CALLBACK(src, /obj/singularity/wizard.proc/deranged, jedi), 10 SECONDS)
/obj/singularity/wizard/proc/deranged(mob/living/carbon/C)
if(!C || C.stat == DEAD)
@@ -685,10 +685,10 @@
UnregisterSignal(user, COMSIG_MOVABLE_BUMP)
/obj/item/clothing/gloves/gauntlets/proc/rocksmash(mob/living/carbon/human/H, atom/A, proximity)
if(!istype(A, /turf/closed/mineral))
return
A.attackby(src, H)
return COMPONENT_NO_ATTACK_HAND
if(!istype(A, /turf/closed/mineral))
return
A.attackby(src, H)
return COMPONENT_CANCEL_ATTACK_CHAIN
///Bosses
@@ -62,7 +62,7 @@
//ATTACK HAND IGNORING PARENT RETURN VALUE
/mob/living/silicon/attack_hand(mob/living/carbon/human/M)
. = FALSE
if(SEND_SIGNAL(src, COMSIG_ATOM_ATTACK_HAND, M) & COMPONENT_NO_ATTACK_HAND)
if(SEND_SIGNAL(src, COMSIG_ATOM_ATTACK_HAND, M) & COMPONENT_CANCEL_ATTACK_CHAIN)
. = TRUE
switch(M.a_intent)
if ("help")
@@ -504,12 +504,12 @@
A.attack_animal(src)
return 1
/mob/living/simple_animal/hostile/RangedAttack(atom/A, params) //Player firing
if(ranged && ranged_cooldown <= world.time)
target = A
OpenFire(A)
..()
return ..()
////// AI Status ///////
+6 -3
View File
@@ -79,13 +79,15 @@
dat += "</table></center>"
user << browse("<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'><title>[name]</title></head><body>[dat]</body></html>", "window=filingcabinet;size=350x300")
/obj/structure/filingcabinet/attack_tk(mob/user)
if(anchored)
attack_self_tk(user)
else
..()
return attack_self_tk(user)
return ..()
/obj/structure/filingcabinet/attack_self_tk(mob/user)
. = COMPONENT_CANCEL_ATTACK_CHAIN
if(contents.len)
if(prob(40 + contents.len * 5))
var/obj/item/I = pick(contents)
@@ -96,6 +98,7 @@
return
to_chat(user, "<span class='notice'>You find nothing in [src].</span>")
/obj/structure/filingcabinet/Topic(href, href_list)
if(!usr.canUseTopic(src, BE_CLOSE, ismonkey(usr)))
return
+11 -7
View File
@@ -94,12 +94,16 @@
cell = null
add_fingerprint(user)
/obj/structure/light_construct/attack_tk(mob/user)
if(cell)
to_chat(user, "<span class='notice'>You telekinetically remove [cell].</span>")
cell.forceMove(drop_location())
cell.attack_tk(user)
cell = null
if(!cell)
return
to_chat(user, "<span class='notice'>You telekinetically remove [cell].</span>")
var/obj/item/stock_parts/cell/cell_reference = cell
cell = null
cell_reference.forceMove(drop_location())
return cell_reference.attack_tk(user)
/obj/structure/light_construct/attackby(obj/item/W, mob/user, params)
add_fingerprint(user)
@@ -730,8 +734,8 @@
to_chat(user, "<span class='notice'>You telekinetically remove the light [fitting].</span>")
// create a light tube/bulb item and put it in the user's hand
var/obj/item/light/L = drop_light_tube()
L.attack_tk(user)
var/obj/item/light/light_tube = drop_light_tube()
return light_tube.attack_tk(user)
// break the light and make sparks if was on
+9 -6
View File
@@ -39,10 +39,13 @@
message_admins("A BoH tear has been created at [ADMIN_VERBOSEJMP(T)].")
investigate_log("was created at [AREACOORD(T)].", INVESTIGATE_SINGULO)
/obj/singularity/boh_tear/attack_tk(mob/living/user)
if(!istype(user))
/obj/singularity/boh_tear/attack_tk(mob/user)
if(!isliving(user))
return
to_chat(user, "<span class='userdanger'>You don't feel like you are real anymore.</span>")
user.dust_animation()
user.spawn_dust()
addtimer(CALLBACK(src, .proc/consume, user), 5)
var/mob/living/jedi = user
to_chat(jedi, "<span class='userdanger'>You don't feel like you are real anymore.</span>")
jedi.dust_animation()
jedi.spawn_dust()
addtimer(CALLBACK(src, .proc/consume, jedi), 0.5 SECONDS)
return COMPONENT_CANCEL_ATTACK_CHAIN
+52 -10
View File
@@ -95,19 +95,61 @@
/obj/singularity/blob_act(obj/structure/blob/B)
return
/obj/singularity/attack_tk(mob/user)
if(iscarbon(user))
var/mob/living/carbon/C = user
C.visible_message("<span class='danger'>[C]'s head begins to collapse in on itself!</span>", "<span class='userdanger'>Your head feels like it's collapsing in on itself! This was really not a good idea!</span>", "<span class='hear'>You hear something crack and explode in gore.</span>")
var/turf/T = get_turf(C)
for(var/i in 1 to 3)
C.apply_damage(30, BRUTE, BODY_ZONE_HEAD)
new /obj/effect/gibspawner/generic(T, C)
sleep(1)
C.ghostize()
var/obj/item/bodypart/head/rip_u = C.get_bodypart(BODY_ZONE_HEAD)
if(!iscarbon(user))
return
. = COMPONENT_CANCEL_ATTACK_CHAIN
var/mob/living/carbon/jedi = user
jedi.visible_message(
"<span class='danger'>[jedi]'s head begins to collapse in on itself!</span>",
"<span class='userdanger'>Your head feels like it's collapsing in on itself! This was really not a good idea!</span>",
"<span class='hear'>You hear something crack and explode in gore.</span>"
)
jedi.Stun(3 SECONDS)
new /obj/effect/gibspawner/generic(get_turf(jedi), jedi)
jedi.apply_damage(30, BRUTE, BODY_ZONE_HEAD)
if(QDELETED(jedi))
return // damage was too much
if(jedi.stat == DEAD)
jedi.ghostize()
var/obj/item/bodypart/head/rip_u = jedi.get_bodypart(BODY_ZONE_HEAD)
rip_u.dismember(BURN) //nice try jedi
qdel(rip_u)
return
addtimer(CALLBACK(GLOBAL_PROC, .proc/carbon_tk_part_two, jedi), 0.1 SECONDS)
/obj/singularity/proc/carbon_tk_part_two(mob/living/carbon/jedi)
if(QDELETED(jedi))
return
new /obj/effect/gibspawner/generic(get_turf(jedi), jedi)
jedi.apply_damage(30, BRUTE, BODY_ZONE_HEAD)
if(QDELETED(jedi))
return // damage was too much
if(jedi.stat == DEAD)
jedi.ghostize()
var/obj/item/bodypart/head/rip_u = jedi.get_bodypart(BODY_ZONE_HEAD)
if(rip_u)
rip_u.dismember(BURN)
qdel(rip_u)
return
addtimer(CALLBACK(GLOBAL_PROC, .proc/carbon_tk_part_three, jedi), 0.1 SECONDS)
/obj/singularity/proc/carbon_tk_part_three(mob/living/carbon/jedi)
if(QDELETED(jedi))
return
new /obj/effect/gibspawner/generic(get_turf(jedi), jedi)
jedi.apply_damage(30, BRUTE, BODY_ZONE_HEAD)
if(QDELETED(jedi))
return // damage was too much
jedi.ghostize()
var/obj/item/bodypart/head/rip_u = jedi.get_bodypart(BODY_ZONE_HEAD)
if(rip_u)
rip_u.dismember(BURN)
qdel(rip_u)
/obj/singularity/ex_act(severity, target)
switch(severity)
+11 -6
View File
@@ -850,14 +850,19 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
"<span class='hear'>You hear a loud crack as you are washed with a wave of heat.</span>")
Consume(B)
/obj/machinery/power/supermatter_crystal/attack_tk(mob/user)
if(iscarbon(user))
var/mob/living/carbon/C = user
to_chat(C, "<span class='userdanger'>That was a really dense idea.</span>")
C.ghostize()
var/obj/item/organ/brain/rip_u = locate(/obj/item/organ/brain) in C.internal_organs
rip_u.Remove(C)
if(!iscarbon(user))
return
var/mob/living/carbon/jedi = user
to_chat(jedi, "<span class='userdanger'>That was a really dense idea.</span>")
jedi.ghostize()
var/obj/item/organ/brain/rip_u = locate(/obj/item/organ/brain) in jedi.internal_organs
if(rip_u)
rip_u.Remove(jedi)
qdel(rip_u)
return COMPONENT_CANCEL_ATTACK_CHAIN
/obj/machinery/power/supermatter_crystal/attack_paw(mob/user)
dust_mob(user, cause = "monkey attack")
+11 -6
View File
@@ -145,14 +145,19 @@
/obj/singularity/energy_ball/Bumped(atom/movable/AM)
dust_mobs(AM)
/obj/singularity/energy_ball/attack_tk(mob/user)
if(iscarbon(user))
var/mob/living/carbon/C = user
to_chat(C, "<span class='userdanger'>That was a shockingly dumb idea.</span>")
var/obj/item/organ/brain/rip_u = locate(/obj/item/organ/brain) in C.internal_organs
C.ghostize(0)
if(!iscarbon(user))
return
var/mob/living/carbon/jedi = user
to_chat(jedi, "<span class='userdanger'>That was a shockingly dumb idea.</span>")
var/obj/item/organ/brain/rip_u = locate(/obj/item/organ/brain) in jedi.internal_organs
jedi.ghostize(jedi)
if(rip_u)
qdel(rip_u)
C.death()
jedi.death()
return COMPONENT_CANCEL_ATTACK_CHAIN
/obj/singularity/energy_ball/orbit(obj/singularity/energy_ball/target)
if (istype(target))
@@ -199,6 +199,7 @@
new /obj/effect/decal/cleanable/wrapping(get_turf(user))
qdel(src)
/obj/item/small_delivery/attack_self_tk(mob/user)
if(ismob(loc))
var/mob/M = loc
@@ -214,6 +215,8 @@
new /obj/effect/decal/cleanable/wrapping(get_turf(user))
unwrap_contents()
qdel(src)
return COMPONENT_CANCEL_ATTACK_CHAIN
/obj/item/small_delivery/examine(mob/user)
. = ..()
+1 -2
View File
@@ -27,5 +27,4 @@
/obj/item/clothing/gloves/butchering/proc/butcher_target(mob/user, atom/target, proximity)
if(!isliving(target))
return
if(SEND_SIGNAL(src, COMSIG_ITEM_ATTACK, target, user) & COMPONENT_ITEM_NO_ATTACK)
return COMPONENT_NO_ATTACK_HAND
return SEND_SIGNAL(src, COMSIG_ITEM_ATTACK, target, user)
@@ -46,7 +46,7 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999))
/obj/item/hilbertshotel/attack_tk(mob/user)
to_chat(user, "<span class='notice'>\The [src] actively rejects your mind as the bluespace energies surrounding it disrupt your telekinesis.</span>")
return
return COMPONENT_CANCEL_ATTACK_CHAIN
/obj/item/hilbertshotel/proc/promptAndCheckIn(mob/user, mob/target)
var/chosenRoomNumber