Afterattack is dead, long live Afterattack (#83818)

## About The Pull Request

- Afterattack is a very simple proc now: All it does is this, and all
it's used for is for having a convenient place to put effects an item
does after a successful attack (IE, the attack was not blocked)


![image](https://github.com/tgstation/tgstation/assets/51863163/1e70f7be-0990-4827-a60a-0c9dd0e0ee49)

- An overwhelming majority of afterattack implementations have been
moved to `interact_with_atom` or the new `ranged_interact_with_atom`

I have manually tested many of the refactored procs but there was 200+
so it's kinda hard

## Why It's Good For The Game

Afterattack is one of the worst parts of the attack chain, as it
simultaneously serves as a way of doing random interactions NOT AT ALL
related to attacks (despite the name) while ALSO serving as the defacto
way to do a ranged interaction with an item

This means careless coders (most of them) may throw stuff in afterattack
without realizing how wide reaching it is, which causes bugs. By making
two well defined, separate procs for handing adjacent vs ranged
interactions, it becomes WAY WAY WAY more easy to develop for.

If you want to do something when you click on something else and you're
adjacent, use `interact_with_atom`
If you want to do something when you click on something else and you're
not adjacent, use 'ranged_interact_with_atom`

This does result in some instances of boilerplate as shown here:


![image](https://github.com/tgstation/tgstation/assets/51863163/a7e469dd-115e-4e5b-88e0-0c664619c878)

But I think it's acceptable, feel free to oppose if you don't I'm sure
we can think of another solution

~~Additionally it makes it easier to implement swing combat. That's a
bonus I guess~~

## Changelog

🆑 Melbert
refactor: Over 200 item interactions have been refactored to use a
newer, easier-to-use system. Report any oddities with using items on
other objects you may see (such as surgery, reagent containers like cups
and spray bottles, or construction devices), especially using something
at range (such as guns or chisels)
refactor: Item-On-Modsuit interactions have changed slightly. While on
combat mode, you will attempt to "use" the item on the suit instead of
inserting it into the suit's storage. This means being on combat mode
while the suit's panel is open will block you from inserting items
entirely via click (but other methods such as hotkey, clicking on the
storage boxes, and mousedrop will still work).
refactor: The detective's scanner will now be inserted into storage
items if clicked normally, and will scan the storage item if on combat
mode
/🆑
This commit is contained in:
MrMelbert
2024-06-11 23:58:09 -05:00
committed by GitHub
parent efe3f3dfef
commit ff6b41aa07
235 changed files with 3211 additions and 3231 deletions
+11 -2
View File
@@ -1,8 +1,17 @@
// Cleaning flags
///Whether we should not attempt to clean.
#define DO_NOT_CLEAN "do_not_clean"
/// Return to prevent clean attempts
#define CLEAN_BLOCKED (1<<0)
/// Return to allow clean attempts
/// This is (currently) the same as returning null / none but more explicit
#define CLEAN_ALLOWED (1<<1)
/// Return to prevent XP gain
/// Only does anything if [CLEAN_ALLOWED] is also returned
#define CLEAN_NO_XP (1<<2)
/// Return to stop cleaner component from blocking interaction chain further
/// Only does anything if [CLEAN_BLOCKED] is also returned
#define CLEAN_DONT_BLOCK_INTERACTION (1<<3)
// Different kinds of things that can be cleaned.
// Use these when overriding the wash proc or registering for the clean signals to check if your thing should be cleaned
-7
View File
@@ -319,13 +319,6 @@ GLOBAL_LIST_INIT(leg_zones, list(BODY_ZONE_R_LEG, BODY_ZONE_L_LEG))
/// Proceed with the attack chain, but don't call the normal methods.
#define SECONDARY_ATTACK_CONTINUE_CHAIN 3
/// Flag for when /afterattack potentially acts on an item.
/// Used for the swap hands/drop tutorials to know when you might just be trying to do something normally.
/// Does not necessarily imply success, or even that it did hit an item, just intent.
// This is intentionally not (1 << 0) because some stuff currently erroneously returns TRUE/FALSE for afterattack.
// Doesn't need to be set if proximity flag is FALSE.
#define AFTERATTACK_PROCESSED_ITEM (1 << 1)
//Autofire component
/// Compatible firemode is in the gun. Wait until it's held in the user hands.
#define AUTOFIRE_STAT_IDLE (1<<0)
@@ -6,7 +6,7 @@
#define COMSIG_ATOM_ATTACKBY "atom_attackby"
/// From base of [atom/proc/attacby_secondary()]: (/obj/item/weapon, /mob/user, params)
#define COMSIG_ATOM_ATTACKBY_SECONDARY "atom_attackby_secondary"
///from [/item/afterattack()], sent by an atom which was just attacked by an item: (/obj/item/weapon, /mob/user, proximity_flag, click_parameters)
/// From [/item/attack()], sent by an atom which was just attacked by an item: (/obj/item/weapon, /mob/user, proximity_flag, click_parameters)
#define COMSIG_ATOM_AFTER_ATTACKEDBY "atom_after_attackby"
/// From base of [/atom/proc/attack_hand_secondary]: (mob/user, list/modifiers) - Called when the atom receives a secondary unarmed attack.
#define COMSIG_ATOM_ATTACK_HAND_SECONDARY "atom_attack_hand_secondary"
@@ -56,6 +56,8 @@
/// Args: (mob/living/user, obj/item/tool, list/modifiers)
/// Return any ITEM_INTERACT_ flags as relevant (see tools.dm)
#define COMSIG_ATOM_ITEM_INTERACTION_SECONDARY "atom_item_interaction_secondary"
/// Sent from [atom/proc/item_interaction], to a mob clicking on an atom with an item
#define COMSIG_USER_ITEM_INTERACTION "user_item_interaction"
/// Sent from [atom/proc/item_interaction], to an item clicking on an atom
/// Args: (mob/living/user, atom/interacting_with, list/modifiers)
/// Return any ITEM_INTERACT_ flags as relevant (see tools.dm)
@@ -64,6 +66,8 @@
/// Args: (mob/living/user, atom/interacting_with, list/modifiers)
/// Return any ITEM_INTERACT_ flags as relevant (see tools.dm)
#define COMSIG_ITEM_INTERACTING_WITH_ATOM_SECONDARY "item_interacting_with_atom_secondary"
/// Sent from [atom/proc/item_interaction], when this atom is right-clicked on by a mob with a tool
#define COMSIG_USER_ITEM_INTERACTION_SECONDARY "user_item_interaction_secondary"
/// Sent from [atom/proc/item_interaction], when this atom is left-clicked on by a mob with a tool of a specific tool type
/// Args: (mob/living/user, obj/item/tool, list/recipes)
/// Return any ITEM_INTERACT_ flags as relevant (see tools.dm)
@@ -72,3 +76,20 @@
/// Args: (mob/living/user, obj/item/tool)
/// Return any ITEM_INTERACT_ flags as relevant (see tools.dm)
#define COMSIG_ATOM_SECONDARY_TOOL_ACT(tooltype) "tool_secondary_act_[tooltype]"
/// Sent from [atom/proc/ranged_item_interaction], when this atom is left-clicked on by a mob with an item while not adjacent
#define COMSIG_ATOM_RANGED_ITEM_INTERACTION "atom_ranged_item_interaction"
/// Sent from [atom/proc/ranged_item_interaction], when this atom is right-clicked on by a mob with an item while not adjacent
#define COMSIG_ATOM_RANGED_ITEM_INTERACTION_SECONDARY "atom_ranged_item_interaction_secondary"
/// Sent from [atom/proc/ranged_item_interaction], when a mob is using this item while left-clicking on by an atom while not adjacent
#define COMSIG_RANGED_ITEM_INTERACTING_WITH_ATOM "ranged_item_interacting_with_atom"
/// Sent from [atom/proc/ranged_item_interaction], when a mob is using this item while right-clicking on by an atom while not adjacent
#define COMSIG_RANGED_ITEM_INTERACTING_WITH_ATOM_SECONDARY "ranged_item_interacting_with_atom_secondary"
/// Sent from [atom/proc/item_interaction], when this atom is used as a tool and an event occurs
#define COMSIG_ITEM_TOOL_ACTED "tool_item_acted"
/// This is sent via item interaction (IE, item clicking on atom) right before the item's inserted into the atom's storage
/// Args: (obj/item/inserting, mob/living/user)
#define COMSIG_ATOM_STORAGE_ITEM_INTERACT_INSERT "atom_storage_item_interact_insert"
#define BLOCK_STORAGE_INSERT (1<<0)
@@ -1,15 +1,15 @@
/// Heretic signals
/// From /obj/item/melee/touch_attack/mansus_fist/on_mob_hit : (mob/living/source, mob/living/target)
/// From /datum/action/cooldown/spell/touch/mansus_grasp/cast_on_hand_hit : (mob/living/source, mob/living/target)
#define COMSIG_HERETIC_MANSUS_GRASP_ATTACK "mansus_grasp_attack"
/// Default behavior is to use the hand, so return this to blocks the mansus fist from being consumed after use.
#define COMPONENT_BLOCK_HAND_USE (1<<0)
/// From /obj/item/melee/touch_attack/mansus_fist/afterattack_secondary : (mob/living/source, atom/target)
/// From /datum/action/cooldown/spell/touch/mansus_grasp/cast_on_secondary_hand_hit : (mob/living/source, atom/target)
#define COMSIG_HERETIC_MANSUS_GRASP_ATTACK_SECONDARY "mansus_grasp_attack_secondary"
/// Default behavior is to continue attack chain and do nothing else, so return this to use up the hand after use.
#define COMPONENT_USE_HAND (1<<0)
/// From /obj/item/melee/sickly_blade/afterattack (with proximity) : (mob/living/source, mob/living/target)
/// From /obj/item/melee/sickly_blade/afterattack : (mob/living/source, mob/living/target)
#define COMSIG_HERETIC_BLADE_ATTACK "blade_attack"
/// From /obj/item/melee/sickly_blade/afterattack (without proximity) : (mob/living/source, mob/living/target)
/// From /obj/item/melee/sickly_blade/ranged_interact_with_atom (without proximity) : (mob/living/source, mob/living/target)
#define COMSIG_HERETIC_RANGED_BLADE_ATTACK "ranged_blade_attack"
@@ -43,10 +43,12 @@
#define COMSIG_LIVING_SET_BUCKLED "living_set_buckled"
///from base of mob/living/set_body_position()
#define COMSIG_LIVING_SET_BODY_POSITION "living_set_body_position"
/// Sent to a mob being injected with a syringe when the do_after initiates
#define COMSIG_LIVING_TRY_SYRINGE_INJECT "living_try_syringe_inject"
/// Sent to a mob being withdrawn from with a syringe when the do_after initiates
#define COMSIG_LIVING_TRY_SYRINGE_WITHDRAW "living_try_syringe_withdraw"
///from base of mob/living/set_usable_legs()
#define COMSIG_LIVING_LIMBLESS_SLOWDOWN "living_limbless_slowdown"
///From post-can inject check of syringe after attack (mob/user)
#define COMSIG_LIVING_TRY_SYRINGE "living_try_syringe"
///From living/Life(). (deltatime, times_fired)
#define COMSIG_LIVING_LIFE "living_life"
/// Block the Life() proc from proceeding... this should really only be done in some really wacky situations.
@@ -181,10 +181,6 @@
#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, obj/item/weapon, proximity_flag, click_parameters)
#define COMSIG_MOB_ITEM_AFTERATTACK "mob_item_afterattack"
///from base of obj/item/afterattack_secondary(): (atom/target, obj/item/weapon, proximity_flag, click_parameters)
#define COMSIG_MOB_ITEM_AFTERATTACK_SECONDARY "mob_item_afterattack_secondary"
///from base of mob/RangedAttack(): (atom/A, modifiers)
#define COMSIG_MOB_ATTACK_RANGED "mob_attack_ranged"
///from base of mob/ranged_secondary_attack(): (atom/target, modifiers)
+4 -15
View File
@@ -9,7 +9,7 @@
#define COMSIG_OBJ_DEFAULT_UNFASTEN_WRENCH "obj_default_unfasten_wrench"
///from base of /turf/proc/levelupdate(). (intact) true to hide and false to unhide
#define COMSIG_OBJ_HIDE "obj_hide"
/// from /obj/item/toy/crayon/spraycan/afterattack: (user, spraycan, color_is_dark)
/// from /obj/item/toy/crayon/spraycan/use_on: (user, spraycan, color_is_dark)
#define COMSIG_OBJ_PAINTED "obj_painted"
#define DONT_USE_SPRAYCAN_CHARGES (1<<0)
/// from /obj/obj_reskin: (mob/user, skin)
@@ -161,9 +161,6 @@
/// Return to prevent the default behavior (attack_selfing) from ocurring.
#define COMPONENT_ITEM_ACTION_SLOT_INVALID (1<<0)
/// Sent from /obj/item/attack_atom(): (atom/attacked_atom, mob/living/user)
#define COMSIG_ITEM_POST_ATTACK_ATOM "item_post_attack_atom"
///from base of mob/living/carbon/attacked_by(): (mob/living/carbon/target, mob/living/user, hit_zone)
#define COMSIG_ITEM_ATTACK_ZONE "item_attack_zone"
///from base of obj/item/hit_reaction(): (owner, hitby, attack_text, final_block_chance, damage, attack_type, damage_type)
@@ -208,7 +205,7 @@
#define COMSIG_STACK_CAN_MERGE "stack_can_merge"
#define CANCEL_STACK_MERGE (1<<0)
///from /obj/item/book/bible/afterattack(): (mob/user, proximity)
///from /obj/item/book/bible/interact_with_atom(): (mob/user)
#define COMSIG_BIBLE_SMACKED "bible_smacked"
///stops the bible chain from continuing. When all of the effects of the bible smacking have been moved to a signal we can kill this
#define COMSIG_END_BIBLE_CHAIN (1<<0)
@@ -450,8 +447,6 @@
///from base of /obj/item/attack(): (mob/living, mob/living, params)
#define COMSIG_ITEM_ATTACK "item_attack"
///from base of /obj/item/attack(): (mob/living, mob/living, params)
#define COMSIG_ITEM_POST_ATTACK "item_post_attack" // called only if the attack was executed
///from base of obj/item/attack_self(): (/mob)
#define COMSIG_ITEM_ATTACK_SELF "item_attack_self"
//from base of obj/item/attack_self_secondary(): (/mob)
@@ -467,14 +462,8 @@
#define COMPONENT_SECONDARY_CALL_NORMAL_ATTACK_CHAIN (1<<2)
/// From base of [/obj/item/proc/attack_secondary()]: (atom/target, mob/user, params)
#define COMSIG_ITEM_ATTACK_SECONDARY "item_attack_secondary"
///from base of obj/item/afterattack(): (atom/target, mob/user, proximity_flag, click_parameters)
///from base of [obj/item/attack()]: (atom/target, mob/user, proximity_flag, click_parameters)
#define COMSIG_ITEM_AFTERATTACK "item_afterattack"
/// Flag for when /afterattack potentially acts on an item.
/// Used for the swap hands/drop tutorials to know when you might just be trying to do something normally.
/// Does not necessarily imply success, or even that it did hit an item, just intent.
#define COMPONENT_AFTERATTACK_PROCESSED_ITEM (1<<0)
///from base of obj/item/afterattack_secondary(): (atom/target, mob/user, proximity_flag, click_parameters)
#define COMSIG_ITEM_AFTERATTACK_SECONDARY "item_afterattack_secondary"
///from base of obj/item/embedded(): (atom/target, obj/item/bodypart/part)
#define COMSIG_ITEM_EMBEDDED "item_embedded"
///from base of datum/component/embedded/safeRemove(): (mob/living/carbon/victim)
@@ -495,7 +484,7 @@
///from base of /obj/item/mmi/set_brainmob(): (mob/living/brain/new_brainmob)
#define COMSIG_MMI_SET_BRAINMOB "mmi_set_brainmob"
/// from base of /obj/item/slimepotion/speed/afterattack(): (obj/target, /obj/src, mob/user)
/// from base of /obj/item/slimepotion/speed/interact_with_atom(): (obj/target, /obj/src, mob/user)
#define COMSIG_SPEED_POTION_APPLIED "speed_potion"
#define SPEED_POTION_STOP (1<<0)
+2
View File
@@ -31,6 +31,8 @@
/// Return to prevent the rest of the attack chain from being executed / preventing the item user from thwacking the target.
/// Similar to [ITEM_INTERACT_SUCCESS], but does not necessarily indicate success.
#define ITEM_INTERACT_BLOCKING (1<<1)
/// Only for people who get confused by the naming scheme
#define ITEM_INTERACT_FAILURE ITEM_INTERACT_BLOCKING
/// Return to skip the rest of the interaction chain, going straight to attack.
#define ITEM_INTERACT_SKIP_TO_ATTACK (1<<2)
+11
View File
@@ -325,3 +325,14 @@ rough example of the "cone" made by the 3 dirs checked
"x" = icon_width > world.icon_size && pixel_x != 0 ? (icon_width - world.icon_size) * 0.5 : 0,
"y" = icon_height > world.icon_size && pixel_y != 0 ? (icon_height - world.icon_size) * 0.5 : 0,
)
/**
* Called before an item is put into this atom's storage datum via the item clicking on this atom
*
* This can be used to add item-atom interactions that you want handled before inserting something into storage
* (But it's also fairly snowflakey)
*
* Returning FALSE will block that item from being put into our storage
*/
/atom/proc/storage_insert_on_interacted_with(datum/storage, obj/item/inserted, mob/living/user)
return TRUE
+3 -10
View File
@@ -53,11 +53,10 @@
/**
* Standard mob ClickOn()
* Handles exceptions: Buildmode, middle click, modified clicks, mech actions
*
* After that, mostly just check your state, check whether you're holding an item,
* check whether you're adjacent to the target, then pass off the click to whoever
* is receiving it.
* check whether you're adjacent to the target, then pass off the click to whoever is receiving it.
*
* The most common are:
* * [mob/proc/UnarmedAttack] (atom,adjacent) - used here only when adjacent, with no item in hand; in the case of humans, checks gloves
* * [atom/proc/attackby] (item,user) - used only when adjacent
@@ -167,13 +166,7 @@
UnarmedAttack(A, TRUE, modifiers)
else
if(W)
if(LAZYACCESS(modifiers, RIGHT_CLICK))
var/after_attack_secondary_result = W.afterattack_secondary(A, src, FALSE, params)
if(after_attack_secondary_result == SECONDARY_ATTACK_CALL_NORMAL)
W.afterattack(A, src, FALSE, params)
else
W.afterattack(A, src, FALSE, params)
A.base_ranged_item_interaction(src, W, modifiers)
else
if(LAZYACCESS(modifiers, RIGHT_CLICK))
ranged_secondary_attack(A, modifiers)
+1 -7
View File
@@ -84,13 +84,7 @@
W.melee_attack_chain(src, A, params)
return
else if(isturf(A) || isturf(A.loc))
if(LAZYACCESS(modifiers, RIGHT_CLICK))
var/after_attack_secondary_result = W.afterattack_secondary(A, src, FALSE, params)
if(after_attack_secondary_result == SECONDARY_ATTACK_CALL_NORMAL)
W.afterattack(A, src, FALSE, params)
else
W.afterattack(A, src, FALSE, params)
A.base_ranged_item_interaction(src, W, modifiers)
//Give cyborgs hotkey clicks without breaking existing uses of hotkey clicks
// for non-doors/apcs
+36 -61
View File
@@ -17,6 +17,8 @@
if(item_interact_result & ITEM_INTERACT_BLOCKING)
return FALSE
// At this point it means we're not doing a non-combat interaction so let's just try to bash it
var/pre_attack_result
if (is_right_clicking)
switch (pre_attack_secondary(target, user, params))
@@ -34,8 +36,9 @@
if(pre_attack_result)
return TRUE
var/attackby_result
// At this point the attack is really about to happen
var/attackby_result
if (is_right_clicking)
switch (target.attackby_secondary(src, user, params))
if (SECONDARY_ATTACK_CALL_NORMAL)
@@ -50,24 +53,19 @@
attackby_result = target.attackby(src, user, params)
if (attackby_result)
// This means the attack failed or was handled for whatever reason
return TRUE
if (is_right_clicking)
var/after_attack_secondary_result = afterattack_secondary(target, user, TRUE, params)
// At this point it means the attack was "successful", or at least unhandled, in some way
// This can mean nothing happened, this can mean the target took damage, etc.
// There's no chain left to continue at this point, so CANCEL_ATTACK_CHAIN and CONTINUE_CHAIN are functionally the same.
if (after_attack_secondary_result == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN || after_attack_secondary_result == SECONDARY_ATTACK_CONTINUE_CHAIN)
return TRUE
var/afterattack_result = afterattack(target, user, TRUE, params)
if (!(afterattack_result & AFTERATTACK_PROCESSED_ITEM) && isitem(target))
if (isnull(user.get_inactive_held_item()))
if(user.client && isitem(target))
if(isnull(user.get_inactive_held_item()))
SStutorials.suggest_tutorial(user, /datum/tutorial/switch_hands, params2list(params))
else
SStutorials.suggest_tutorial(user, /datum/tutorial/drop, params2list(params))
return afterattack_result & TRUE //this is really stupid but its needed because afterattack can return TRUE | FLAGS.
return TRUE
/// 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, modifiers)
@@ -160,16 +158,6 @@
return attacking_item.attack_atom(src, user, params)
/mob/living/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
// Surgery and such happens very high up in the interaction chain, before parent call
var/attempt_tending = item_tending(user, tool, modifiers)
if(attempt_tending & ITEM_INTERACT_ANY_BLOCKER)
return attempt_tending
return ..() | attempt_tending
/// Handles any use of using a surgical tool or item on a mob to tend to them.
/// The sole reason this is a separate proc is so carbons can tend wounds AFTER the check for surgery.
/mob/living/proc/item_tending(mob/living/user, obj/item/tool, list/modifiers)
for(var/datum/surgery/operation as anything in surgeries)
if(IS_IN_INVALID_SURGICAL_POSITION(src, operation))
continue
@@ -211,21 +199,21 @@
if(signal_return & COMPONENT_CANCEL_ATTACK_CHAIN)
return TRUE
if(signal_return & COMPONENT_SKIP_ATTACK)
return
return FALSE
SEND_SIGNAL(user, COMSIG_MOB_ITEM_ATTACK, target_mob, user, params)
if(item_flags & NOBLUDGEON)
return
return FALSE
if(damtype != STAMINA && force && HAS_TRAIT(user, TRAIT_PACIFISM))
to_chat(user, span_warning("You don't want to harm other living beings!"))
return
return FALSE
if(!force && !HAS_TRAIT(src, TRAIT_CUSTOM_TAP_SOUND))
playsound(loc, 'sound/weapons/tap.ogg', get_clamped_volume(), TRUE, -1)
playsound(src, 'sound/weapons/tap.ogg', get_clamped_volume(), TRUE, -1)
else if(hitsound)
playsound(loc, hitsound, get_clamped_volume(), TRUE, extrarange = stealthy_audio ? SILENCED_SOUND_EXTRARANGE : -1, falloff_distance = 0)
playsound(src, hitsound, get_clamped_volume(), TRUE, extrarange = stealthy_audio ? SILENCED_SOUND_EXTRARANGE : -1, falloff_distance = 0)
target_mob.lastattacker = user.real_name
target_mob.lastattackerckey = user.ckey
@@ -233,14 +221,18 @@
if(force && target_mob == user && user.client)
user.client.give_award(/datum/award/achievement/misc/selfouch, user)
user.do_attack_animation(target_mob)
if(get(src, /mob/living) == user) // telekinesis.
user.do_attack_animation(target_mob)
if(!target_mob.attacked_by(src, user))
return TRUE
SEND_SIGNAL(src, COMSIG_ITEM_POST_ATTACK, target_mob, user, params)
SEND_SIGNAL(src, COMSIG_ITEM_AFTERATTACK, target_mob, user, params)
SEND_SIGNAL(target_mob, COMSIG_ATOM_AFTER_ATTACKEDBY, src, user, params)
afterattack(target_mob, user, params)
log_combat(user, target_mob, "attacked", src.name, "(COMBAT MODE: [uppertext(user.combat_mode)]) (DAMTYPE: [uppertext(damtype)])")
add_fingerprint(user)
return FALSE // unhandled
/// The equivalent of [/obj/item/proc/attack] but for alternate attacks, AKA right clicking
/obj/item/proc/attack_secondary(mob/living/victim, mob/living/user, params)
@@ -256,14 +248,21 @@
/// The equivalent of the standard version of [/obj/item/proc/attack] but for non mob targets.
/obj/item/proc/attack_atom(atom/attacked_atom, mob/living/user, params)
if(SEND_SIGNAL(src, COMSIG_ITEM_ATTACK_ATOM, attacked_atom, user) & COMPONENT_CANCEL_ATTACK_CHAIN)
return
var/signal_return = SEND_SIGNAL(src, COMSIG_ITEM_ATTACK_ATOM, attacked_atom, user)
if(signal_return & COMPONENT_SKIP_ATTACK)
return TRUE
if(signal_return & COMPONENT_CANCEL_ATTACK_CHAIN)
return FALSE
if(item_flags & NOBLUDGEON)
return
return FALSE
user.changeNext_move(attack_speed)
user.do_attack_animation(attacked_atom)
if(get(src, /mob/living) == user) // telekinesis.
user.do_attack_animation(attacked_atom)
attacked_atom.attacked_by(src, user)
SEND_SIGNAL(src, COMSIG_ITEM_POST_ATTACK_ATOM, attacked_atom, user)
SEND_SIGNAL(src, COMSIG_ITEM_AFTERATTACK, attacked_atom, user, params)
SEND_SIGNAL(attacked_atom, COMSIG_ATOM_AFTER_ATTACKEDBY, src, user, params)
afterattack(attacked_atom, user, params)
return FALSE // unhandled
/// Called from [/obj/item/proc/attack_atom] and [/obj/item/proc/attack] if the attack succeeds
/atom/proc/attacked_by(obj/item/attacking_item, mob/living/user)
@@ -443,33 +442,9 @@
* * proximity_flag - is 1 if this afterattack was called on something adjacent, in your square, or on your person.
* * click_parameters - is the params string from byond [/atom/proc/Click] code, see that documentation.
*/
/obj/item/proc/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = NONE
. |= SEND_SIGNAL(src, COMSIG_ITEM_AFTERATTACK, target, user, proximity_flag, click_parameters)
SEND_SIGNAL(user, COMSIG_MOB_ITEM_AFTERATTACK, target, src, proximity_flag, click_parameters)
SEND_SIGNAL(target, COMSIG_ATOM_AFTER_ATTACKEDBY, src, user, proximity_flag, click_parameters)
return .
/**
* Called at the end of the attack chain if the user right-clicked.
*
* Arguments:
* * atom/target - The thing that was hit
* * mob/user - The mob doing the hitting
* * proximity_flag - is 1 if this afterattack was called on something adjacent, in your square, or on your person.
* * click_parameters - is the params string from byond [/atom/proc/Click] code, see that documentation.
*/
/obj/item/proc/afterattack_secondary(atom/target, mob/user, proximity_flag, click_parameters)
var/signal_result = SEND_SIGNAL(src, COMSIG_ITEM_AFTERATTACK_SECONDARY, target, user, proximity_flag, click_parameters)
SEND_SIGNAL(user, COMSIG_MOB_ITEM_AFTERATTACK_SECONDARY, target, src, proximity_flag, click_parameters)
if(signal_result & COMPONENT_SECONDARY_CANCEL_ATTACK_CHAIN)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
if(signal_result & COMPONENT_SECONDARY_CONTINUE_ATTACK_CHAIN)
return SECONDARY_ATTACK_CONTINUE_CHAIN
return SECONDARY_ATTACK_CALL_NORMAL
/obj/item/proc/afterattack(atom/target, mob/user, click_parameters)
PROTECTED_PROC(TRUE)
return
/obj/item/proc/get_clamped_volume()
if(w_class)
+26 -62
View File
@@ -71,7 +71,7 @@
/obj/item/attack_self_tk(mob/user)
if(attack_self(user))
return COMPONENT_CANCEL_ATTACK_CHAIN
return ITEM_INTERACT_BLOCKING
/atom/proc/attack_self_secondary_tk(mob/user)
return
@@ -79,7 +79,7 @@
/obj/item/attack_self_secondary_tk(mob/user)
if(attack_self_secondary(user))
return COMPONENT_CANCEL_ATTACK_CHAIN
return ITEM_INTERACT_BLOCKING
/*
@@ -146,81 +146,45 @@
if(QDELING(focus))
qdel(src)
return
if(focus.attack_self_tk(user) & COMPONENT_CANCEL_ATTACK_CHAIN)
if(focus.attack_self_tk(user) & ITEM_INTERACT_ANY_BLOCKER)
. = TRUE
update_appearance()
/obj/item/tk_grab/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return ranged_interact_with_atom(interacting_with, user, modifiers)
/obj/item/tk_grab/afterattack(atom/target, mob/living/carbon/user, proximity, params)//TODO: go over this
. = ..()
if(.)
return
if(!target || !user)
return
/obj/item/tk_grab/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!focus)
focus_object(target)
return TRUE
focus_object(interacting_with)
return ITEM_INTERACT_BLOCKING
if(!check_if_focusable(focus))
return
return NONE
if(target == focus)
if(target.attack_self_tk(user) & COMPONENT_CANCEL_ATTACK_CHAIN)
. = TRUE
update_appearance()
return
if(interacting_with == focus)
if(LAZYACCESS(modifiers, RIGHT_CLICK))
. = focus.attack_self_secondary_tk(user) || NONE
else
. = interacting_with.attack_self_tk(user) || NONE
if(isitem(focus))
var/obj/item/I = focus
else if(isitem(focus))
var/obj/item/focused_item = focus
apply_focus_overlay()
if(target.Adjacent(focus))
. = I.melee_attack_chain(tk_user, target, params) //isn't copying the attack chain fun. we should do it more often.
if(interacting_with.Adjacent(focus))
. = focused_item.melee_attack_chain(user, interacting_with, list2params(modifiers)) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING
if(check_if_focusable(focus))
focus.do_attack_animation(target, null, focus)
else if(isgun(I)) //I've only tested this with guns, and it took some doing to make it work
. = I.afterattack(target, tk_user, 0, params)
. |= AFTERATTACK_PROCESSED_ITEM
focus.do_attack_animation(interacting_with, null, focus)
// isgun check lets us shoot guns at range
// quoting the old comment: "I've only tested this with guns, and it took some doing to make it work"
// reader beware if trying to add other snowflake cases
else if(isgun(focused_item))
. = interacting_with.base_ranged_item_interaction(user, focus, modifiers)
user.changeNext_move(CLICK_CD_MELEE)
update_appearance()
return .
/obj/item/tk_grab/afterattack_secondary(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
return
if(!target || !user)
return
if(!focus)
focus_object(target)
return TRUE
if(!check_if_focusable(focus))
return
if(target == focus)
if(target.attack_self_secondary_tk(user) & COMPONENT_CANCEL_ATTACK_CHAIN)
. = TRUE
update_appearance()
return
if(isitem(focus))
var/obj/item/I = focus
apply_focus_overlay()
if(target.Adjacent(focus))
. = I.melee_attack_chain(tk_user, target, click_parameters) //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 if(isgun(I)) //I've only tested this with guns, and it took some doing to make it work
. = I.afterattack_secondary(target, tk_user, 0, click_parameters)
user.changeNext_move(CLICK_CD_MELEE)
update_appearance()
/obj/item/tk_grab/on_thrown(mob/living/carbon/user, atom/target)
if(!target || !user)
return
@@ -232,7 +196,7 @@
return
if(target == focus)
if(target.attack_self_tk(user) & COMPONENT_CANCEL_ATTACK_CHAIN)
if(target.attack_self_tk(user) & ITEM_INTERACT_ANY_BLOCKER)
return
update_appearance()
return
+1 -1
View File
@@ -197,7 +197,7 @@
var/can_shoot = gun?.can_shoot() || FALSE
if(gun && controller.blackboard[BB_MONKEY_GUN_WORKED] && prob(95))
// We attempt to attack even if we can't shoot so we get the effects of pulling the trigger
gun.afterattack(real_target, living_pawn, FALSE)
gun.melee_attack_chain(living_pawn, real_target)
controller.set_blackboard_key(BB_MONKEY_GUN_WORKED, can_shoot ? TRUE : prob(80)) // Only 20% likely to notice it didn't work
if(can_shoot)
controller.set_blackboard_key(BB_MONKEY_GUN_NEURONS_ACTIVATED, TRUE)
+3 -2
View File
@@ -80,7 +80,7 @@ have ways of interacting with a specific mob and control it.
living_pawn.AddElement(/datum/element/relay_attackers)
RegisterSignal(new_pawn, COMSIG_ATOM_WAS_ATTACKED, PROC_REF(on_attacked))
RegisterSignal(new_pawn, COMSIG_LIVING_START_PULL, PROC_REF(on_startpulling))
RegisterSignal(new_pawn, COMSIG_LIVING_TRY_SYRINGE, PROC_REF(on_try_syringe))
RegisterSignals(new_pawn, list(COMSIG_LIVING_TRY_SYRINGE_INJECT, COMSIG_LIVING_TRY_SYRINGE_WITHDRAW), PROC_REF(on_try_syringe))
RegisterSignal(new_pawn, COMSIG_CARBON_CUFF_ATTEMPTED, PROC_REF(on_attempt_cuff))
RegisterSignal(new_pawn, COMSIG_MOB_MOVESPEED_UPDATED, PROC_REF(update_movespeed))
@@ -92,7 +92,8 @@ have ways of interacting with a specific mob and control it.
UnregisterSignal(pawn, list(
COMSIG_ATOM_WAS_ATTACKED,
COMSIG_LIVING_START_PULL,
COMSIG_LIVING_TRY_SYRINGE,
COMSIG_LIVING_TRY_SYRINGE_INJECT,
COMSIG_LIVING_TRY_SYRINGE_WITHDRAW,
COMSIG_CARBON_CUFF_ATTEMPTED,
COMSIG_MOB_MOVESPEED_UPDATED,
))
+23 -25
View File
@@ -35,16 +35,16 @@
return ..()
/datum/component/cleaner/RegisterWithParent()
if(isbot(parent))
if(ismob(parent))
RegisterSignal(parent, COMSIG_LIVING_UNARMED_ATTACK, PROC_REF(on_unarmed_attack))
return
RegisterSignal(parent, COMSIG_ITEM_AFTERATTACK, PROC_REF(on_afterattack))
if(isitem(parent))
RegisterSignal(parent, COMSIG_ITEM_INTERACTING_WITH_ATOM, PROC_REF(on_interaction))
/datum/component/cleaner/UnregisterFromParent()
if(isbot(parent))
UnregisterSignal(parent, COMSIG_LIVING_UNARMED_ATTACK)
return
UnregisterSignal(parent, COMSIG_ITEM_AFTERATTACK)
UnregisterSignal(parent, list(
COMSIG_ITEM_INTERACTING_WITH_ATOM,
COMSIG_LIVING_UNARMED_ATTACK,
))
/**
* Handles the COMSIG_LIVING_UNARMED_ATTACK signal used for cleanbots
@@ -52,29 +52,27 @@
*/
/datum/component/cleaner/proc/on_unarmed_attack(datum/source, atom/target, proximity_flags, modifiers)
SIGNAL_HANDLER
return on_afterattack(source, target, parent, proximity_flags, modifiers)
if(on_interaction(source, source, target, modifiers) & ITEM_INTERACT_ANY_BLOCKER)
return COMPONENT_CANCEL_ATTACK_CHAIN
return NONE
/**
* Handles the COMSIG_ITEM_AFTERATTACK signal by calling the clean proc.
*
* Arguments
* * source the datum that sent the signal to start cleaning
* * target the thing being cleaned
* * user the person doing the cleaning
* * clean_target set this to false if the target should not be washed and if experience should not be awarded to the user
* Handles the COMSIG_ITEM_INTERACTING_WITH_ATOM signal by calling the clean proc.
*/
/datum/component/cleaner/proc/on_afterattack(datum/source, atom/target, mob/user, proximity_flag, click_parameters)
/datum/component/cleaner/proc/on_interaction(datum/source, mob/living/user, atom/target, list/modifiers)
SIGNAL_HANDLER
if(!proximity_flag)
return
. |= COMPONENT_AFTERATTACK_PROCESSED_ITEM
var/clean_target
// By default, give XP
var/give_xp = TRUE
if(pre_clean_callback)
clean_target = pre_clean_callback?.Invoke(source, target, user)
if(clean_target == DO_NOT_CLEAN)
return .
INVOKE_ASYNC(src, PROC_REF(clean), source, target, user, clean_target) //signal handlers can't have do_afters inside of them
return .
var/callback_return = pre_clean_callback.Invoke(source, target, user)
if(callback_return & CLEAN_BLOCKED)
return (callback_return & CLEAN_DONT_BLOCK_INTERACTION) ? NONE : ITEM_INTERACT_BLOCKING
if(callback_return & CLEAN_NO_XP)
give_xp = FALSE
INVOKE_ASYNC(src, PROC_REF(clean), source, target, user, give_xp)
return ITEM_INTERACT_SUCCESS
/**
* Cleans something using this cleaner.
+1 -4
View File
@@ -20,13 +20,10 @@
/datum/component/igniter/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_ITEM_AFTERATTACK, COMSIG_HOSTILE_POST_ATTACKINGTARGET, COMSIG_PROJECTILE_ON_HIT))
/datum/component/igniter/proc/item_afterattack(obj/item/source, atom/target, mob/user, proximity_flag, click_parameters)
/datum/component/igniter/proc/item_afterattack(obj/item/source, atom/target, mob/user, click_parameters)
SIGNAL_HANDLER
if(!proximity_flag)
return
do_igniter(target)
return COMPONENT_AFTERATTACK_PROCESSED_ITEM
/datum/component/igniter/proc/hostile_attackingtarget(mob/living/simple_animal/hostile/attacker, atom/target, success)
SIGNAL_HANDLER
+5 -6
View File
@@ -118,17 +118,16 @@
try_infect(target, hit_zone)
/datum/component/infective/proc/try_infect_attack_zone(datum/source, mob/living/carbon/target, mob/living/user, hit_zone)
/datum/component/infective/proc/try_infect_attack_zone(obj/item/source, mob/living/carbon/target, mob/living/user, hit_zone)
SIGNAL_HANDLER
try_infect(user, BODY_ZONE_L_ARM)
try_infect(target, hit_zone)
/datum/component/infective/proc/try_infect_attack(datum/source, mob/living/target, mob/living/user)
/datum/component/infective/proc/try_infect_attack(obj/item/source, mob/living/target, mob/living/user)
SIGNAL_HANDLER
if(!iscarbon(target)) //this case will be handled by try_infect_attack_zone
try_infect(target)
try_infect(user, BODY_ZONE_L_ARM)
if(source.loc == user)
var/obj/item/bodypart/hand = user.get_active_hand()
try_infect(user, hand.body_zone)
/datum/component/infective/proc/try_infect_equipped(datum/source, mob/living/L, slot)
SIGNAL_HANDLER
+2 -2
View File
@@ -44,7 +44,7 @@
RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine))
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(on_equip))
RegisterSignal(parent, COMSIG_ITEM_DROPPED, PROC_REF(on_drop))
RegisterSignal(parent, COMSIG_ITEM_POST_ATTACK, PROC_REF(on_successful_attack))
RegisterSignal(parent, COMSIG_ITEM_AFTERATTACK, PROC_REF(on_successful_attack))
RegisterSignal(parent, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform))
/datum/component/jousting/UnregisterFromParent()
@@ -53,7 +53,7 @@
COMSIG_ATOM_EXAMINE,
COMSIG_ITEM_EQUIPPED,
COMSIG_ITEM_DROPPED,
COMSIG_ITEM_POST_ATTACK,
COMSIG_ITEM_AFTERATTACK,
COMSIG_TRANSFORMING_ON_TRANSFORM,
))
@@ -47,6 +47,7 @@
if(can_hack_open)
RegisterSignal(parent, COMSIG_ATOM_TOOL_ACT(TOOL_SCREWDRIVER), PROC_REF(on_screwdriver_act))
RegisterSignal(parent, COMSIG_ATOM_TOOL_ACT(TOOL_MULTITOOL), PROC_REF(on_multitool_act))
RegisterSignal(parent, COMSIG_ATOM_STORAGE_ITEM_INTERACT_INSERT, PROC_REF(block_insert))
RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine))
RegisterSignal(parent, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM, PROC_REF(on_requesting_context_from_item))
@@ -62,6 +63,7 @@
UnregisterSignal(parent, list(
COMSIG_ATOM_TOOL_ACT(TOOL_SCREWDRIVER),
COMSIG_ATOM_TOOL_ACT(TOOL_MULTITOOL),
COMSIG_ATOM_STORAGE_ITEM_INTERACT_INSERT,
))
UnregisterSignal(parent, list(
COMSIG_ATOM_EXAMINE,
@@ -140,6 +142,15 @@
source.balloon_alert(user, "hacked")
lock_code = null
/// Stops you from shoving your tools into the storage if you're trying to hack it
/datum/component/lockable_storage/proc/block_insert(atom/source, obj/item/inserting, mob/living/user)
SIGNAL_HANDLER
if(!can_hack_open || !source.atom_storage.locked)
return NONE // allow insert
if(inserting.tool_behaviour == TOOL_MULTITOOL || inserting.tool_behaviour == TOOL_SCREWDRIVER)
return BLOCK_STORAGE_INSERT // block insert
return NONE
///Updates the icon state depending on if we're locked or not.
/datum/component/lockable_storage/proc/on_update_icon_state(obj/source)
SIGNAL_HANDLER
-1
View File
@@ -58,7 +58,6 @@
if(!extra_check_callback.Invoke(user, target, source))
return
on_hit_callback.Invoke(source, user, target, user.zone_selected)
return COMPONENT_AFTERATTACK_PROCESSED_ITEM
/datum/component/on_hit_effect/proc/hostile_attackingtarget(mob/living/attacker, atom/target, success)
SIGNAL_HANDLER
+2 -4
View File
@@ -33,11 +33,11 @@
return ..()
/datum/component/reagent_refiller/RegisterWithParent()
RegisterSignal(parent, COMSIG_ITEM_AFTERATTACK, PROC_REF(refill))
RegisterSignal(parent, COMSIG_ITEM_INTERACTING_WITH_ATOM, PROC_REF(refill))
RegisterSignal(parent, COMSIG_ATOM_EXITED, PROC_REF(delete_self))
/datum/component/reagent_refiller/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_ITEM_AFTERATTACK, COMSIG_ATOM_EXITED))
UnregisterSignal(parent, list(COMSIG_ITEM_INTERACTING_WITH_ATOM, COMSIG_ATOM_EXITED))
/datum/component/reagent_refiller/proc/delete_self()
SIGNAL_HANDLER
@@ -48,8 +48,6 @@
/datum/component/reagent_refiller/proc/refill()
SIGNAL_HANDLER
. |= COMPONENT_AFTERATTACK_PROCESSED_ITEM
var/obj/item/reagent_containers/container = parent
var/amount = min((container.amount_per_transfer_from_this + container.reagents.total_volume), container.reagents.total_volume)
if (amount == 0)
+4 -4
View File
@@ -27,7 +27,7 @@
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(on_move))
switch(zoom_method)
if(ZOOM_METHOD_RIGHT_CLICK)
RegisterSignal(parent, COMSIG_ITEM_AFTERATTACK_SECONDARY, PROC_REF(on_secondary_afterattack))
RegisterSignal(parent, COMSIG_RANGED_ITEM_INTERACTING_WITH_ATOM_SECONDARY, PROC_REF(do_secondary_zoom))
if(ZOOM_METHOD_WIELD)
RegisterSignal(parent, SIGNAL_ADDTRAIT(TRAIT_WIELDED), PROC_REF(on_wielded))
RegisterSignal(parent, SIGNAL_REMOVETRAIT(TRAIT_WIELDED), PROC_REF(on_unwielded))
@@ -46,7 +46,7 @@
parent_item.remove_item_action(scope)
UnregisterSignal(parent, list(
COMSIG_MOVABLE_MOVED,
COMSIG_ITEM_AFTERATTACK_SECONDARY,
COMSIG_RANGED_ITEM_INTERACTING_WITH_ATOM_SECONDARY,
SIGNAL_ADDTRAIT(TRAIT_WIELDED),
SIGNAL_REMOVETRAIT(TRAIT_WIELDED),
COMSIG_GUN_TRY_FIRE,
@@ -71,14 +71,14 @@
return
stop_zooming(tracker.owner)
/datum/component/scope/proc/on_secondary_afterattack(datum/source, atom/target, mob/user, proximity_flag, click_parameters)
/datum/component/scope/proc/do_secondary_zoom(datum/source, mob/user, atom/target, click_parameters)
SIGNAL_HANDLER
if(tracker)
stop_zooming(user)
else
zoom(user)
return COMPONENT_SECONDARY_CANCEL_ATTACK_CHAIN
return ITEM_INTERACT_BLOCKING
/datum/component/scope/proc/on_action_trigger(datum/action/source)
SIGNAL_HANDLER
+7 -6
View File
@@ -22,9 +22,10 @@
/datum/component/soul_stealer/RegisterWithParent()
RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine))
RegisterSignal(parent, COMSIG_ITEM_AFTERATTACK, PROC_REF(on_afterattack))
RegisterSignal(parent, COMSIG_ITEM_INTERACTING_WITH_ATOM, PROC_REF(try_transfer_soul))
/datum/component/soul_stealer/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_ATOM_EXAMINE, COMSIG_ITEM_AFTERATTACK))
UnregisterSignal(parent, list(COMSIG_ATOM_EXAMINE, COMSIG_ITEM_AFTERATTACK, COMSIG_ITEM_INTERACTING_WITH_ATOM))
///signal called on parent being examined
/datum/component/soul_stealer/proc/on_examine(datum/source, mob/user, list/examine_list)
@@ -41,15 +42,15 @@
if(10 to INFINITY)
examine_list += span_notice("A staggering <b>[num_souls]</b> souls have been claimed by it! And it hungers for more!")
/datum/component/soul_stealer/proc/on_afterattack(obj/item/source, atom/target, mob/living/user, proximity_flag, click_parameters)
/datum/component/soul_stealer/proc/on_afterattack(obj/item/source, atom/target, mob/living/user, click_parameters)
SIGNAL_HANDLER
if(!proximity_flag)
return
if(ishuman(target))
INVOKE_ASYNC(src, PROC_REF(try_capture), target, user)
/datum/component/soul_stealer/proc/try_transfer_soul(obj/item/source, mob/user, atom/target, click_parameters)
SIGNAL_HANDLER
if(istype(target, /obj/structure/constructshell) && length(soulstones))
var/obj/item/soulstone/soulstone = soulstones[1]
INVOKE_ASYNC(soulstone, TYPE_PROC_REF(/obj/item/soulstone, transfer_to_construct), target, user)
@@ -58,7 +59,7 @@
else if(!length(soulstone.contents)) // something fucky happened
qdel(soulstone)
soulstones -= soulstone
return ITEM_INTERACT_SUCCESS
/datum/component/soul_stealer/proc/try_capture(mob/living/carbon/human/victim, mob/living/captor)
if(victim.stat == CONSCIOUS)
+1 -1
View File
@@ -115,7 +115,7 @@
SIGNAL_HANDLER
return COMSIG_BLOCK_RELAYMOVE
/datum/component/spirit_holding/proc/on_bible_smacked(datum/source, mob/living/user, direction)
/datum/component/spirit_holding/proc/on_bible_smacked(datum/source, mob/living/user, ...)
SIGNAL_HANDLER
INVOKE_ASYNC(src, PROC_REF(attempt_exorcism), user)
+7 -6
View File
@@ -97,7 +97,7 @@
src.multitooled = multitooled
/datum/component/style/RegisterWithParent()
RegisterSignal(parent, COMSIG_MOB_ITEM_AFTERATTACK, PROC_REF(hotswap))
RegisterSignal(parent, COMSIG_USER_ITEM_INTERACTION, PROC_REF(hotswap))
RegisterSignal(parent, COMSIG_MOB_MINED, PROC_REF(on_mine))
RegisterSignal(parent, COMSIG_MOB_APPLY_DAMAGE, PROC_REF(on_take_damage))
RegisterSignal(parent, COMSIG_MOB_EMOTED("flip"), PROC_REF(on_flip))
@@ -126,7 +126,7 @@
/datum/component/style/UnregisterFromParent()
UnregisterSignal(parent, COMSIG_MOB_ITEM_AFTERATTACK)
UnregisterSignal(parent, COMSIG_USER_ITEM_INTERACTION)
UnregisterSignal(parent, COMSIG_MOB_MINED)
UnregisterSignal(parent, COMSIG_MOB_APPLY_DAMAGE)
UnregisterSignal(parent, list(COMSIG_MOB_EMOTED("flip"), COMSIG_MOB_EMOTED("spin")))
@@ -319,26 +319,27 @@
return "#364866"
/// A proc that lets a user, when their rank >= `hotswap_rank`, swap items in storage with what's in their hands, simply by clicking on the stored item with a held item
/datum/component/style/proc/hotswap(mob/living/source, atom/target, obj/item/weapon, proximity_flag, click_parameters)
/datum/component/style/proc/hotswap(mob/living/source, atom/target, obj/item/weapon, click_parameters)
SIGNAL_HANDLER
if((rank < hotswap_rank) || !isitem(target) || !(target in source.get_all_contents()))
return
return NONE
var/obj/item/item_target = target
if(!(item_target.item_flags & IN_STORAGE))
return
return NONE
var/datum/storage/atom_storage = item_target.loc.atom_storage
if(!atom_storage.can_insert(weapon, source, messages = FALSE))
source.balloon_alert(source, "unable to hotswap!")
return
return NONE
atom_storage.attempt_insert(weapon, source, override = TRUE)
INVOKE_ASYNC(source, TYPE_PROC_REF(/mob/living, put_in_hands), target)
source.visible_message(span_notice("[source] quickly swaps [weapon] out with [target]!"), span_notice("You quickly swap [weapon] with [target]."))
return ITEM_INTERACT_BLOCKING
// Point givers
/datum/component/style/proc/on_punch(mob/living/carbon/human/punching_person, atom/attacked_atom, proximity)
+1 -4
View File
@@ -49,13 +49,10 @@
/datum/component/summoning/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_ITEM_AFTERATTACK, COMSIG_HOSTILE_POST_ATTACKINGTARGET, COMSIG_PROJECTILE_ON_HIT))
/datum/component/summoning/proc/item_afterattack(obj/item/source, atom/target, mob/user, proximity_flag, click_parameters)
/datum/component/summoning/proc/item_afterattack(obj/item/source, atom/target, mob/user, click_parameters)
SIGNAL_HANDLER
if(!proximity_flag)
return
do_spawn_mob(get_turf(target), user)
return COMPONENT_AFTERATTACK_PROCESSED_ITEM
/datum/component/summoning/proc/hostile_attackingtarget(mob/living/simple_animal/hostile/attacker, atom/target, success)
SIGNAL_HANDLER
+9 -12
View File
@@ -349,26 +349,23 @@
. = ..()
AddElement(/datum/element/openspace_item_click_handler)
/obj/item/trapdoor_kit/handle_openspace_click(turf/target, mob/user, proximity_flag, click_parameters)
afterattack(target, user, proximity_flag, click_parameters)
/obj/item/trapdoor_kit/handle_openspace_click(turf/target, mob/user, click_parameters)
interact_with_atom(target, user, click_parameters)
/obj/item/trapdoor_kit/afterattack(atom/target, mob/user, proximity_flag)
. = ..()
if(!proximity_flag)
return
var/turf/target_turf = get_turf(target)
/obj/item/trapdoor_kit/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
var/turf/target_turf = get_turf(interacting_with)
if(!isopenspaceturf(target_turf))
return
return NONE
in_use = TRUE
balloon_alert(user, "constructing trapdoor")
if(!do_after(user, 5 SECONDS, target = target))
if(!do_after(user, 5 SECONDS, interacting_with))
in_use = FALSE
return
return ITEM_INTERACT_BLOCKING
in_use = FALSE
if(!isopenspaceturf(target_turf)) // second check to make sure nothing changed during constructions
return
return ITEM_INTERACT_BLOCKING
var/turf/new_turf = target_turf.place_on_top(/turf/open/floor/plating, flags = CHANGETURF_INHERIT_AIR)
new_turf.AddComponent(/datum/component/trapdoor, starts_open = FALSE, conspicuous = TRUE)
balloon_alert(user, "trapdoor constructed")
qdel(src)
return
return ITEM_INTERACT_SUCCESS
+1 -1
View File
@@ -31,7 +31,7 @@
RegisterSignal(target, COMSIG_MOVABLE_IMPACT, PROC_REF(on_throw_impact))
RegisterSignal(target, COMSIG_ATOM_ON_Z_IMPACT, PROC_REF(on_z_impact))
if(shatters_as_weapon)
RegisterSignal(target, COMSIG_ITEM_POST_ATTACK_ATOM, PROC_REF(on_post_attack_atom))
RegisterSignal(target, COMSIG_ITEM_AFTERATTACK, PROC_REF(on_post_attack_atom))
/datum/element/can_shatter/Detach(datum/target)
. = ..()
+10 -7
View File
@@ -17,18 +17,21 @@
src.break_chance = break_chance
RegisterSignal(target, COMSIG_ITEM_AFTERATTACK, PROC_REF(on_afterattack))
RegisterSignal(target, COMSIG_ITEM_TOOL_ACTED, PROC_REF(on_tool_use))
/datum/element/easily_fragmented/Detach(datum/target)
. = ..()
UnregisterSignal(target, COMSIG_ITEM_AFTERATTACK)
UnregisterSignal(target, list(COMSIG_ITEM_AFTERATTACK, COMSIG_ITEM_TOOL_ACTED))
/datum/element/easily_fragmented/proc/on_afterattack(datum/source, atom/target, mob/user, proximity_flag, click_parameters)
/datum/element/easily_fragmented/proc/on_afterattack(datum/source, atom/target, mob/user, click_parameters)
SIGNAL_HANDLER
try_break(source, user)
var/obj/item/item = source
/datum/element/easily_fragmented/proc/on_tool_use(datum/source, atom/target, mob/user, tool_type, result)
SIGNAL_HANDLER
try_break(source, user)
/datum/element/easily_fragmented/proc/try_break(obj/item/source, mob/user)
if(prob(break_chance))
user.visible_message(span_danger("[user]'s [item.name] snap[item.p_s()] into tiny pieces in [user.p_their()] hand."))
item.deconstruct(disassembled = FALSE)
return COMPONENT_AFTERATTACK_PROCESSED_ITEM
user.visible_message(span_danger("[user]'s [source.name] snap[source.p_s()] into tiny pieces in [user.p_their()] hand."))
source.deconstruct(disassembled = FALSE)
+8 -9
View File
@@ -15,7 +15,7 @@
if(!istype(target, /obj/item/ammo_casing))
return ELEMENT_INCOMPATIBLE
src.amount_allowed = amount_allowed
RegisterSignal(target, COMSIG_ITEM_AFTERATTACK, PROC_REF(on_afterattack))
RegisterSignal(target, COMSIG_ITEM_INTERACTING_WITH_ATOM, PROC_REF(handle_interaction))
RegisterSignal(target, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine_before_dip))
/datum/element/envenomable_casing/Detach(datum/target)
@@ -23,28 +23,29 @@
UnregisterSignal(target, list(COMSIG_ITEM_AFTERATTACK, COMSIG_ATOM_EXAMINE))
///signal called on the parent attacking an item
/datum/element/envenomable_casing/proc/on_afterattack(obj/item/ammo_casing/casing, atom/target, mob/user, proximity_flag, click_parameters)
/datum/element/envenomable_casing/proc/handle_interaction(obj/item/ammo_casing/casing, mob/user, atom/target, click_parameters)
SIGNAL_HANDLER
if(!is_reagent_container(target))
return
return NONE
var/obj/item/reagent_containers/venom_container = target
if(!casing.loaded_projectile)
user.balloon_alert(user, "casing is already spent!")
return
return ITEM_INTERACT_BLOCKING
if(!(venom_container.reagent_flags & OPENCONTAINER))
user.balloon_alert(user, "open the container!")
return
return ITEM_INTERACT_BLOCKING
var/datum/reagent/venom_applied = venom_container.reagents.get_master_reagent()
if(!venom_applied)
return
return ITEM_INTERACT_BLOCKING
var/amount_applied = min(venom_applied.volume, amount_allowed)
casing.loaded_projectile.AddElement(/datum/element/venomous, venom_applied.type, amount_applied)
to_chat(user, span_notice("You coat [casing] in [venom_applied]."))
venom_container.reagents.remove_reagent(venom_applied.type, amount_applied)
///stops further poison application
UnregisterSignal(casing, COMSIG_ITEM_AFTERATTACK)
UnregisterSignal(casing, COMSIG_ITEM_INTERACTING_WITH_ATOM)
RegisterSignal(casing, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine_after_dip), override = TRUE)
return ITEM_INTERACT_SUCCESS
///signal called on parent being examined while not coated
/datum/element/envenomable_casing/proc/on_examine_before_dip(obj/item/ammo_casing/casing, mob/user, list/examine_list)
@@ -55,5 +56,3 @@
/datum/element/envenomable_casing/proc/on_examine_after_dip(obj/item/ammo_casing/casing, mob/user, list/examine_list)
SIGNAL_HANDLER
examine_list += span_warning("It's coated in some kind of chemical...")
+8 -10
View File
@@ -10,29 +10,27 @@
if(!isitem(target))
return ELEMENT_INCOMPATIBLE
dunk_amount = amount_per_dunk
RegisterSignal(target, COMSIG_ITEM_AFTERATTACK, PROC_REF(get_dunked))
RegisterSignal(target, COMSIG_ITEM_INTERACTING_WITH_ATOM, PROC_REF(get_dunked))
/datum/element/dunkable/Detach(datum/target)
. = ..()
UnregisterSignal(target, COMSIG_ITEM_AFTERATTACK)
UnregisterSignal(target, COMSIG_ITEM_INTERACTING_WITH_ATOM)
/datum/element/dunkable/proc/get_dunked(datum/source, atom/target, mob/user, proximity_flag)
/datum/element/dunkable/proc/get_dunked(datum/source, mob/user, atom/target, params)
SIGNAL_HANDLER
if(!proximity_flag) // if the user is not adjacent to the container
return
var/obj/item/reagent_containers/container = target // the container we're trying to dunk into
if(istype(container) && container.reagent_flags & DUNKABLE) // container should be a valid target for dunking
. = COMPONENT_AFTERATTACK_PROCESSED_ITEM
if(istype(container) && (container.reagent_flags & DUNKABLE)) // container should be a valid target for dunking
if(!container.is_drainable())
to_chat(user, span_warning("[container] is unable to be dunked in!"))
return COMPONENT_AFTERATTACK_PROCESSED_ITEM
return ITEM_INTERACT_BLOCKING
var/obj/item/I = source // the item that has the dunkable element
if(container.reagents.trans_to(I, dunk_amount, transferred_by = user)) //if reagents were transferred, show the message
to_chat(user, span_notice("You dunk \the [I] into \the [container]."))
return COMPONENT_AFTERATTACK_PROCESSED_ITEM
return ITEM_INTERACT_SUCCESS
if(!container.reagents.total_volume)
to_chat(user, span_warning("[container] is empty!"))
else
to_chat(user, span_warning("[I] is full!"))
return COMPONENT_AFTERATTACK_PROCESSED_ITEM
return ITEM_INTERACT_BLOCKING
return NONE
+1 -4
View File
@@ -30,13 +30,10 @@
return ..()
/// triggered after an item attacks something
/datum/element/knockback/proc/item_afterattack(obj/item/source, atom/target, mob/user, proximity_flag, click_parameters)
/datum/element/knockback/proc/item_afterattack(obj/item/source, atom/target, mob/user, click_parameters)
SIGNAL_HANDLER
if(!proximity_flag)
return
do_knockback(target, user, get_dir(source, target))
return COMPONENT_AFTERATTACK_PROCESSED_ITEM
/// triggered after a hostile simplemob attacks something
/datum/element/knockback/proc/hostile_attackingtarget(mob/living/simple_animal/hostile/attacker, atom/target, success)
+1 -4
View File
@@ -126,12 +126,9 @@
* - [user][/mob/living]: The mob using the source to strike the target
* - proximity: Whether the strike was in melee range so you can't eat lights from cameras
*/
/datum/element/light_eater/proc/on_afterattack(obj/item/source, atom/target, mob/living/user, proximity)
/datum/element/light_eater/proc/on_afterattack(obj/item/source, atom/target, mob/living/user)
SIGNAL_HANDLER
if(!proximity)
return NONE
eat_lights(target, source)
return COMPONENT_AFTERATTACK_PROCESSED_ITEM
/**
* Called when a source object is used to block a thrown object, projectile, or attack
@@ -8,22 +8,22 @@
. = ..()
if(!isitem(target))
return ELEMENT_INCOMPATIBLE
RegisterSignal(target, COMSIG_ITEM_AFTERATTACK, PROC_REF(on_afterattack))
RegisterSignal(target, COMSIG_ITEM_INTERACTING_WITH_ATOM, PROC_REF(divert_interaction))
/datum/element/openspace_item_click_handler/Detach(datum/source)
UnregisterSignal(source, COMSIG_ITEM_AFTERATTACK)
UnregisterSignal(source, COMSIG_ITEM_INTERACTING_WITH_ATOM)
return ..()
//Invokes the proctype with a turf above as target.
/datum/element/openspace_item_click_handler/proc/on_afterattack(obj/item/source, atom/target, mob/user, proximity_flag, click_parameters)
/datum/element/openspace_item_click_handler/proc/divert_interaction(obj/item/source, mob/user, atom/target, click_parameters)
SIGNAL_HANDLER
if(target.z == user.z)
return
return NONE
var/turf/checked_turf = get_turf(target)
while(!isnull(checked_turf))
checked_turf = GET_TURF_ABOVE(checked_turf)
if(checked_turf?.z == user.z)
INVOKE_ASYNC(source, TYPE_PROC_REF(/obj/item, handle_openspace_click), checked_turf, user, user.CanReach(checked_turf, source), click_parameters)
if(checked_turf?.z == user.z && user.CanReach(checked_turf, source))
INVOKE_ASYNC(source, TYPE_PROC_REF(/obj/item, handle_openspace_click), checked_turf, user, click_parameters)
break
return COMPONENT_AFTERATTACK_PROCESSED_ITEM
return ITEM_INTERACT_BLOCKING
+7 -10
View File
@@ -36,19 +36,16 @@ clamping the Knockback_Force value below. */
else
return default_speed
/datum/element/selfknockback/proc/Item_SelfKnockback(obj/item/I, atom/attacktarget, mob/usertarget, proximity_flag)
/datum/element/selfknockback/proc/Item_SelfKnockback(obj/item/I, atom/attacktarget, mob/usertarget)
SIGNAL_HANDLER
if(isturf(attacktarget) && !attacktarget.density)
return
if(proximity_flag || (get_dist(attacktarget, usertarget) <= I.reach))
var/knockback_force = Get_Knockback_Force(clamp(CEILING((I.force / 10), 1), 1, 5))
var/knockback_speed = Get_Knockback_Speed(clamp(knockback_force, 1, 5))
var/knockback_force = Get_Knockback_Force(clamp(CEILING((I.force / 10), 1), 1, 5))
var/knockback_speed = Get_Knockback_Speed(clamp(knockback_force, 1, 5))
var/target_angle = get_angle(attacktarget, usertarget)
var/move_target = get_ranged_target_turf(usertarget, angle2dir(target_angle), knockback_force)
usertarget.throw_at(move_target, knockback_force, knockback_speed)
usertarget.visible_message(span_warning("[usertarget] gets thrown back by the force of \the [I] impacting \the [attacktarget]!"), span_warning("The force of \the [I] impacting \the [attacktarget] sends you flying!"))
var/target_angle = get_angle(attacktarget, usertarget)
var/move_target = get_ranged_target_turf(usertarget, angle2dir(target_angle), knockback_force)
usertarget.throw_at(move_target, knockback_force, knockback_speed)
usertarget.visible_message(span_warning("[usertarget] gets thrown back by the force of \the [I] impacting \the [attacktarget]!"), span_warning("The force of \the [I] impacting \the [attacktarget] sends you flying!"))
/datum/element/selfknockback/proc/Projectile_SelfKnockback(obj/projectile/P)
SIGNAL_HANDLER
+26 -1
View File
@@ -1,13 +1,38 @@
//entirely neutral or internal status effects go here
/datum/status_effect/crusher_damage //tracks the damage dealt to this mob by kinetic crushers
/datum/status_effect/crusher_damage
id = "crusher_damage"
duration = -1
tick_interval = -1
status_type = STATUS_EFFECT_UNIQUE
alert_type = null
/// How much damage?
var/total_damage = 0
/datum/status_effect/crusher_damage/on_apply()
RegisterSignal(owner, COMSIG_MOB_AFTER_APPLY_DAMAGE, PROC_REF(damage_taken))
return TRUE
/datum/status_effect/crusher_damage/on_remove()
UnregisterSignal(owner, COMSIG_MOB_AFTER_APPLY_DAMAGE)
/datum/status_effect/crusher_damage/proc/damage_taken(
datum/source,
damage_dealt,
damagetype,
def_zone,
blocked,
wound_bonus,
bare_wound_bonus,
sharpness,
attack_direction,
attacking_item,
)
SIGNAL_HANDLER
if(istype(attacking_item, /obj/item/kinetic_crusher))
total_damage += damage_dealt
/datum/status_effect/syphon_mark
id = "syphon_mark"
duration = 50
+17 -9
View File
@@ -199,14 +199,14 @@
parent = new_parent
// a few of theses should probably be on the real_location rather than the parent
RegisterSignal(parent, COMSIG_ATOM_ATTACKBY, PROC_REF(on_attackby))
RegisterSignal(parent, COMSIG_ATOM_ITEM_INTERACTION, PROC_REF(on_item_interact))
RegisterSignals(parent, list(COMSIG_ATOM_ATTACK_PAW, COMSIG_ATOM_ATTACK_HAND), PROC_REF(on_attack))
RegisterSignal(parent, COMSIG_MOUSEDROP_ONTO, PROC_REF(on_mousedrop_onto))
RegisterSignal(parent, COMSIG_MOUSEDROPPED_ONTO, PROC_REF(on_mousedropped_onto))
RegisterSignal(parent, COMSIG_ITEM_PRE_ATTACK, PROC_REF(on_preattack))
RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, PROC_REF(mass_empty))
RegisterSignals(parent, list(COMSIG_ATOM_ATTACK_GHOST, COMSIG_ATOM_ATTACK_HAND_SECONDARY), PROC_REF(open_storage_on_signal))
RegisterSignal(parent, COMSIG_ATOM_ATTACKBY_SECONDARY, PROC_REF(open_storage_attackby_secondary))
RegisterSignal(parent, COMSIG_ATOM_ITEM_INTERACTION_SECONDARY, PROC_REF(on_item_interact_secondary))
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(close_distance))
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(update_actions))
RegisterSignal(parent, COMSIG_TOPIC, PROC_REF(topic_handle))
@@ -795,17 +795,23 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches)
attempt_insert(dropping, user)
/// Signal handler for whenever we're attacked by an object.
/datum/storage/proc/on_attackby(datum/source, obj/item/thing, mob/user, params)
/datum/storage/proc/on_item_interact(datum/source, mob/user, obj/item/thing, params)
SIGNAL_HANDLER
if(!insert_on_attack || !thing.attackby_storage_insert(src, parent, user))
return
if(!insert_on_attack)
return NONE
if(!thing.storage_insert_on_interaction(src, parent, user))
return NONE
if(!parent.storage_insert_on_interacted_with(src, thing, user))
return NONE
if(SEND_SIGNAL(parent, COMSIG_ATOM_STORAGE_ITEM_INTERACT_INSERT, thing, user) & BLOCK_STORAGE_INSERT)
return NONE
if(iscyborg(user))
return COMPONENT_NO_AFTERATTACK
return ITEM_INTERACT_BLOCKING
attempt_insert(thing, user)
return COMPONENT_NO_AFTERATTACK
return ITEM_INTERACT_SUCCESS
/// Signal handler for whenever we're attacked by a mob.
/datum/storage/proc/on_attack(datum/source, mob/user)
@@ -915,14 +921,16 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches)
/// Signal handler for when we get attacked with secondary click by an item.
/datum/storage/proc/open_storage_attackby_secondary(datum/source, atom/weapon, mob/user)
/datum/storage/proc/on_item_interact_secondary(datum/source, mob/user, atom/weapon)
SIGNAL_HANDLER
if(istype(weapon, /obj/item/chameleon))
var/obj/item/chameleon/chameleon_weapon = weapon
chameleon_weapon.make_copy(source, user)
return open_storage_on_signal(source, user)
if(open_storage_on_signal(source, user))
return ITEM_INTERACT_BLOCKING
return NONE
/// Signal handler to open up the storage when we receive a signal.
/datum/storage/proc/open_storage_on_signal(datum/source, mob/to_show)
@@ -7,6 +7,8 @@
locked = STORAGE_FULLY_LOCKED
rustle_sound = FALSE
silent = TRUE
// Snowflake so you can feed it
insert_on_attack = FALSE
/datum/storage/extract_inventory/New(
atom/parent,
+101 -2
View File
@@ -13,11 +13,23 @@
var/is_left_clicking = !is_right_clicking
var/early_sig_return = NONE
if(is_left_clicking)
/*
* This is intentionally using `||` instead of `|` to short-circuit the signal calls
* This is because we want to return early if ANY of these signals return a value
*
* This puts priority on the atom's signals, then the tool's signals, then the user's signals
* So stuff like storage can be handled before stuff the item wants to do like cleaner component
*
* Future idea: Being on combat mode could change/reverse the priority of these signals
*/
early_sig_return = SEND_SIGNAL(src, COMSIG_ATOM_ITEM_INTERACTION, user, tool, modifiers) \
| SEND_SIGNAL(tool, COMSIG_ITEM_INTERACTING_WITH_ATOM, user, src, modifiers)
|| SEND_SIGNAL(tool, COMSIG_ITEM_INTERACTING_WITH_ATOM, user, src, modifiers) \
|| SEND_SIGNAL(user, COMSIG_USER_ITEM_INTERACTION, src, tool, modifiers)
else
// See above
early_sig_return = SEND_SIGNAL(src, COMSIG_ATOM_ITEM_INTERACTION_SECONDARY, user, tool, modifiers) \
| SEND_SIGNAL(tool, COMSIG_ITEM_INTERACTING_WITH_ATOM_SECONDARY, user, src, modifiers)
|| SEND_SIGNAL(tool, COMSIG_ITEM_INTERACTING_WITH_ATOM_SECONDARY, user, src, modifiers) \
|| SEND_SIGNAL(user, COMSIG_USER_ITEM_INTERACTION_SECONDARY, src, tool, modifiers)
if(early_sig_return)
return early_sig_return
@@ -76,6 +88,7 @@
else
log_tool("[key_name(user)] used [tool] on [src] (right click) at [AREACOORD(src)]")
SEND_SIGNAL(tool, COMSIG_TOOL_ATOM_ACTED_SECONDARY(tool_type), src)
SEND_SIGNAL(tool, COMSIG_ITEM_TOOL_ACTED, src, user, tool_type, act_result)
return act_result
/**
@@ -121,6 +134,92 @@
/obj/item/proc/interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
return interact_with_atom(interacting_with, user, modifiers)
/**
* ## Ranged item interaction
*
* Handles non-combat ranged interactions of a tool on this atom,
* such as shooting a gun in the direction of someone*,
* having a scanner you can point at someone to scan them at any distance,
* or pointing a laser pointer at something.
*
* *While this intuitively sounds combat related, it is not,
* because a "combat use" of a gun is gun-butting.
*/
/atom/proc/base_ranged_item_interaction(mob/living/user, obj/item/tool, list/modifiers)
SHOULD_CALL_PARENT(TRUE)
PROTECTED_PROC(TRUE)
var/is_right_clicking = LAZYACCESS(modifiers, RIGHT_CLICK)
var/is_left_clicking = !is_right_clicking
var/early_sig_return = NONE
if(is_left_clicking)
// See [base_item_interaction] for defails on why this is using `||` (TL;DR it's short circuiting)
early_sig_return = SEND_SIGNAL(src, COMSIG_ATOM_RANGED_ITEM_INTERACTION, user, tool, modifiers) \
|| SEND_SIGNAL(tool, COMSIG_RANGED_ITEM_INTERACTING_WITH_ATOM, user, src, modifiers)
else
// See above
early_sig_return = SEND_SIGNAL(src, COMSIG_ATOM_RANGED_ITEM_INTERACTION_SECONDARY, user, tool, modifiers) \
|| SEND_SIGNAL(tool, COMSIG_RANGED_ITEM_INTERACTING_WITH_ATOM_SECONDARY, user, src, modifiers)
if(early_sig_return)
return early_sig_return
var/self_interaction = is_left_clicking \
? ranged_item_interaction(user, tool, modifiers) \
: ranged_item_interaction_secondary(user, tool, modifiers)
if(self_interaction)
return self_interaction
var/interact_return = is_left_clicking \
? tool.ranged_interact_with_atom(src, user, modifiers) \
: tool.ranged_interact_with_atom_secondary(src, user, modifiers)
if(interact_return)
return interact_return
return NONE
/**
* Called when this atom has an item used on it from a distance.
* IE, a mob is clicking on this atom with an item and is not adjacent.
*
* Does NOT include Telekinesis users, they are considered adjacent generally.
*
* Return an ITEM_INTERACT_ flag in the event the interaction was handled, to cancel further interaction code.
*/
/atom/proc/ranged_item_interaction(mob/living/user, obj/item/tool, list/modifiers)
return NONE
/**
* Called when this atom has an item used on it from a distance WITH RIGHT CLICK,
* IE, a mob is right clicking on this atom with an item and is not adjacent.
*
* Default behavior has it run the same code as left click.
*
* Return an ITEM_INTERACT_ flag in the event the interaction was handled, to cancel further interaction code.
*/
/atom/proc/ranged_item_interaction_secondary(mob/living/user, obj/item/tool, list/modifiers)
return ranged_item_interaction(user, tool, modifiers)
/**
* Called when this item is being used to interact with an atom from a distance,
* IE, a mob is clicking on an atom with this item and is not adjacent.
*
* Does NOT include Telekinesis users, they are considered adjacent generally
* (so long as this item is adjacent to the atom).
*
* Return an ITEM_INTERACT_ flag in the event the interaction was handled, to cancel further interaction code.
*/
/obj/item/proc/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return NONE
/**
* Called when this item is being used to interact with an atom from a distance WITH RIGHT CLICK,
* IE, a mob is right clicking on an atom with this item and is not adjacent.
*
* Default behavior has it run the same code as left click.
*/
/obj/item/proc/ranged_interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
return ranged_interact_with_atom(interacting_with, user, modifiers)
/*
* Tool-specific behavior procs.
*
+9 -9
View File
@@ -350,15 +350,15 @@
user.transferItemToLoc(src, pad, TRUE)
atom_storage.close_all()
/obj/item/storage/briefcase/launchpad/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/launchpad_remote))
var/obj/item/launchpad_remote/L = I
if(L.pad == WEAKREF(src.pad)) //do not attempt to link when already linked
return ..()
L.pad = WEAKREF(src.pad)
to_chat(user, span_notice("You link [pad] to [L]."))
else
return ..()
/obj/item/storage/briefcase/launchpad/storage_insert_on_interacted_with(datum/storage, obj/item/inserted, mob/living/user)
if(istype(inserted, /obj/item/launchpad_remote))
var/obj/item/launchpad_remote/remote = inserted
if(remote.pad == WEAKREF(src.pad))
return TRUE
remote.pad = WEAKREF(src.pad)
to_chat(user, span_notice("You link [pad] to [remote]."))
return FALSE // no insert
return TRUE
/obj/item/launchpad_remote
name = "folder"
+1 -1
View File
@@ -413,7 +413,7 @@
//Dropper tools
if(beaker)
if(is_type_in_list(item, list(/obj/item/reagent_containers/dropper, /obj/item/ph_meter, /obj/item/ph_paper, /obj/item/reagent_containers/syringe)))
item.afterattack(beaker, user, 1)
item.interact_with_atom(beaker, user)
return
/obj/machinery/space_heater/improvised_chem_heater/on_deconstruction(disassembled = TRUE)
+8 -3
View File
@@ -1410,7 +1410,7 @@
mob_loc.update_clothing(slot_flags)
/// Called on [/datum/element/openspace_item_click_handler/proc/on_afterattack]. Check the relative file for information.
/obj/item/proc/handle_openspace_click(turf/target, mob/user, proximity_flag, click_parameters)
/obj/item/proc/handle_openspace_click(turf/target, mob/user, click_parameters)
stack_trace("Undefined handle_openspace_click() behaviour. Ascertain the openspace_item_click_handler element has been attached to the right item and that its proc override doesn't call parent.")
/**
@@ -1444,8 +1444,13 @@
SHOULD_CALL_PARENT(TRUE)
SEND_SIGNAL(src, COMSIG_ITEM_EQUIPPED_AS_OUTFIT, outfit_wearer, visuals_only, item_slot)
/// Whether or not this item can be put into a storage item through attackby
/obj/item/proc/attackby_storage_insert(datum/storage, atom/storage_holder, mob/user)
/**
* Called before this item is placed into a storage container
* via the item clicking on the target atom
*
* Returning FALSE will prevent the item from being stored
*/
/obj/item/proc/storage_insert_on_interaction(datum/storage, atom/storage_holder, mob/user)
return TRUE
/obj/item/proc/do_pickup_animation(atom/target, turf/source)
+5 -8
View File
@@ -219,14 +219,11 @@
. = ..()
stored_custom_color = stored_color
/obj/item/airlock_painter/decal/afterattack(atom/target, mob/user, proximity)
. = ..()
if(!proximity)
balloon_alert(user, "get closer!")
return
if(isfloorturf(target) && use_paint(user))
paint_floor(target)
/obj/item/airlock_painter/decal/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(isfloorturf(interacting_with) && use_paint(user))
paint_floor(interacting_with)
return ITEM_INTERACT_SUCCESS
return NONE
/**
* Actually add current decal to the floor.
+17 -19
View File
@@ -5,23 +5,21 @@
icon = 'icons/obj/tools.dmi'
icon_state = "bear_armor_upgrade"
/obj/item/bear_armor/afterattack(atom/target, mob/user, proximity_flag)
. = ..()
if(!proximity_flag)
return
if(!istype(target, /mob/living/basic/bear))
return
var/mob/living/basic/bear/bear_target = target
if(bear_target.armored)
to_chat(user, span_warning("[bear_target] has already been armored up!"))
return
bear_target.armored = TRUE
bear_target.maxHealth += 60
bear_target.health += 60
bear_target.armour_penetration += 20
bear_target.melee_damage_lower += 3
bear_target.melee_damage_upper += 5
bear_target.wound_bonus += 5
bear_target.update_icons()
to_chat(user, span_info("You strap the armor plating to [bear_target] and sharpen [bear_target.p_their()] claws with the nail filer. This was a great idea."))
/obj/item/bear_armor/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!istype(interacting_with, /mob/living/basic/bear))
return NONE
var/mob/living/basic/bear/bear = interacting_with
if(bear.armored)
to_chat(user, span_warning("[bear] has already been armored up!"))
return ITEM_INTERACT_BLOCKING
bear.armored = TRUE
bear.maxHealth += 60
bear.health += 60
bear.armour_penetration += 20
bear.melee_damage_lower += 3
bear.melee_damage_upper += 5
bear.wound_bonus += 5
bear.update_icons()
to_chat(user, span_info("You strap the armor plating to [bear] and sharpen [bear.p_their()] claws with the nail filer. This was a great idea."))
qdel(src)
return ITEM_INTERACT_SUCCESS
+1
View File
@@ -19,6 +19,7 @@
deploy_bodybag(user, interacting_with)
return ITEM_INTERACT_SUCCESS
return NONE
/obj/item/bodybag/attempt_pickup(mob/user)
// can't pick ourselves up if we are inside of the bodybag, else very weird things may happen
if(contains(user))
+3 -6
View File
@@ -54,12 +54,9 @@
/obj/item/pushbroom/proc/on_unwield(obj/item/source, mob/user)
UnregisterSignal(user, COMSIG_MOVABLE_PRE_MOVE)
/obj/item/pushbroom/afterattack(atom/A, mob/user, proximity)
. = ..()
if(!proximity)
return
sweep(user, A)
return . | AFTERATTACK_PROCESSED_ITEM
/obj/item/pushbroom/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
sweep(user, interacting_with)
return NONE // I guess
/**
* Attempts to push up to BROOM_PUSH_LIMIT atoms from a given location the user's faced direction
+30 -41
View File
@@ -425,13 +425,11 @@
user.visible_message(span_notice("[user] shows you: [icon2html(src, viewers(user))] [src.name][minor]."), span_notice("You show \the [src.name][minor]."))
add_fingerprint(user)
/obj/item/card/id/afterattack_secondary(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
return
if(!proximity_flag || !check_allowed_items(target) || !isfloorturf(target))
return
try_project_paystand(user, target)
/obj/item/card/id/interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
if(!check_allowed_items(interacting_with) || !isfloorturf(interacting_with))
return NONE
try_project_paystand(user, interacting_with)
return ITEM_INTERACT_SUCCESS
/obj/item/card/id/attack_self_secondary(mob/user, modifiers)
. = ..()
@@ -1396,68 +1394,59 @@
theft_target = null
return ..()
/obj/item/card/id/advanced/chameleon/afterattack(atom/target, mob/user, proximity, click_parameters)
. = ..()
if(!proximity)
return
if(isidcard(target))
theft_target = WEAKREF(target)
/obj/item/card/id/advanced/chameleon/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(isidcard(interacting_with))
theft_target = WEAKREF(interacting_with)
ui_interact(user)
return . | AFTERATTACK_PROCESSED_ITEM
/obj/item/card/id/advanced/chameleon/pre_attack_secondary(atom/target, mob/living/user, params)
. = ..()
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
return .
return ITEM_INTERACT_SUCCESS
return NONE
/obj/item/card/id/advanced/chameleon/interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
// If we're attacking a human, we want it to be covert. We're not ATTACKING them, we're trying
// to sneakily steal their accesses by swiping our agent ID card near them. As a result, we
// return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN to cancel any part of the following the attack chain.
if(ishuman(target))
target.balloon_alert(user, "scanning ID card...")
// return ITEM_INTERACT_BLOCKING to cancel any part of the following the attack chain.
if(ishuman(interacting_with))
interacting_with.balloon_alert(user, "scanning ID card...")
if(!do_after(user, 2 SECONDS, target))
target.balloon_alert(user, "interrupted!")
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
var/mob/living/carbon/human/human_target = target
if(!do_after(user, 2 SECONDS, interacting_with))
interacting_with.balloon_alert(user, "interrupted!")
return ITEM_INTERACT_BLOCKING
var/mob/living/carbon/human/human_target = interacting_with
var/list/target_id_cards = human_target.get_all_contents_type(/obj/item/card/id)
if(!length(target_id_cards))
target.balloon_alert(user, "no IDs!")
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
interacting_with.balloon_alert(user, "no IDs!")
return ITEM_INTERACT_BLOCKING
var/selected_id = pick(target_id_cards)
target.balloon_alert(user, UNLINT("IDs synced"))
interacting_with.balloon_alert(user, UNLINT("IDs synced"))
theft_target = WEAKREF(selected_id)
ui_interact(user)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
return ITEM_INTERACT_SUCCESS
if(isitem(target))
var/obj/item/target_item = target
if(isitem(interacting_with))
var/obj/item/target_item = interacting_with
target.balloon_alert(user, "scanning ID card...")
interacting_with.balloon_alert(user, "scanning ID card...")
var/list/target_id_cards = target_item.get_all_contents_type(/obj/item/card/id)
var/target_item_id = target_item.GetID()
if(target_item_id)
target_id_cards |= target_item_id
if(!length(target_id_cards))
target.balloon_alert(user, "no IDs!")
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
interacting_with.balloon_alert(user, "no IDs!")
return ITEM_INTERACT_BLOCKING
var/selected_id = pick(target_id_cards)
target.balloon_alert(user, UNLINT("IDs synced"))
interacting_with.balloon_alert(user, UNLINT("IDs synced"))
theft_target = WEAKREF(selected_id)
ui_interact(user)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
return ITEM_INTERACT_SUCCESS
return .
return NONE
/obj/item/card/id/advanced/chameleon/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
+6 -7
View File
@@ -276,12 +276,12 @@ CIGARETTE PACKETS ARE IN FANCY.DM
var/mob/living/carbon/the_smoker = user
return the_smoker.can_breathe_helmet()
/obj/item/clothing/mask/cigarette/afterattack(obj/item/reagent_containers/cup/glass, mob/user, proximity)
. = ..()
if(!proximity || lit) //can't dip if cigarette is lit (it will heat the reagents in the glass instead)
return
/obj/item/clothing/mask/cigarette/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(lit) //can't dip if cigarette is lit (it will heat the reagents in the glass instead)
return NONE
var/obj/item/reagent_containers/cup/glass = interacting_with
if(!istype(glass)) //you can dip cigarettes into beakers
return
return NONE
if(glass.reagents.trans_to(src, chem_volume, transferred_by = user)) //if reagents were transferred, show the message
to_chat(user, span_notice("You dip \the [src] into \the [glass]."))
@@ -290,8 +290,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
to_chat(user, span_warning("[glass] is empty!"))
else
to_chat(user, span_warning("[src] is full!"))
return AFTERATTACK_PROCESSED_ITEM
return ITEM_INTERACT_SUCCESS
/obj/item/clothing/mask/cigarette/update_icon_state()
. = ..()
+12 -8
View File
@@ -26,20 +26,23 @@
. += span_notice("Then, click solid ground adjacent to the hole above you.")
. += span_notice("The rope looks like you could use it [uses] times before it falls apart.")
/obj/item/climbing_hook/afterattack(turf/open/target, mob/user, proximity_flag, click_parameters)
. = ..()
if(target.z == user.z)
return
/obj/item/climbing_hook/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return ranged_interact_with_atom(interacting_with, user, modifiers)
/obj/item/climbing_hook/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(interacting_with.z == user.z)
return NONE
var/turf/open/target = interacting_with
if(!istype(target) || isopenspaceturf(target))
return
return ITEM_INTERACT_BLOCKING
var/turf/user_turf = get_turf(user)
var/turf/above = GET_TURF_ABOVE(user_turf)
if(target_blocked(target, above))
return
return ITEM_INTERACT_BLOCKING
if(!isopenspaceturf(above) || !above.Adjacent(target)) //are we below a hole, is the target blocked, is the target adjacent to our hole
balloon_alert(user, "blocked!")
return
return ITEM_INTERACT_BLOCKING
var/away_dir = get_dir(above, target)
user.visible_message(span_notice("[user] begins climbing upwards with [src]."), span_notice("You get to work on properly hooking [src] and going upwards."))
@@ -56,6 +59,7 @@
qdel(src)
QDEL_LIST(effects)
return ITEM_INTERACT_SUCCESS
// didnt want to mess up is_blocked_turf_ignore_climbable
/// checks if our target is blocked, also checks for border objects facing the above turf and climbable stuff
+9 -9
View File
@@ -118,7 +118,9 @@
return TOXLOSS
/obj/item/soap/proc/should_clean(datum/cleaning_source, atom/atom_to_clean, mob/living/cleaner)
return check_allowed_items(atom_to_clean)
. = CLEAN_ALLOWED
if(!check_allowed_items(atom_to_clean))
. |= CLEAN_NO_XP
/**
* Decrease the number of uses the bar of soap has.
@@ -145,17 +147,15 @@
qdel(src)
/obj/item/soap/nanotrasen/cyborg/noUses(mob/user)
to_chat(user, span_warning("The soap has ran out of chemicals"))
to_chat(user, span_warning("[src] has ran out of chemicals! Head to a recharger to refill it."))
/obj/item/soap/nanotrasen/cyborg/afterattack(atom/target, mob/user, proximity)
. = isitem(target) ? AFTERATTACK_PROCESSED_ITEM : NONE
/obj/item/soap/nanotrasen/cyborg/should_clean(datum/cleaning_source, atom/atom_to_clean, mob/living/cleaner)
if(uses <= 0)
to_chat(user, span_warning("No good, you need to recharge!"))
return .
return ..() | .
return CLEAN_BLOCKED
return ..()
/obj/item/soap/attackby_storage_insert(datum/storage, atom/storage_holder, mob/living/user)
return !user?.combat_mode // only cleans a storage item if on combat
/obj/item/soap/storage_insert_on_interaction(datum/storage, atom/storage_holder, mob/living/user)
return !user.combat_mode // only cleans a storage item if on combat
/*
* Bike Horns
+19 -17
View File
@@ -35,35 +35,35 @@
update_icon_state()
balloon_alert(user, "mode: [desc[mode]]")
// Airlock remote works by sending NTNet packets to whatever it's pointed at.
/obj/item/door_remote/afterattack(atom/target, mob/user)
. = ..()
/obj/item/door_remote/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return interact_with_atom(interacting_with, user, modifiers)
/obj/item/door_remote/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
var/obj/machinery/door/door
if (istype(target, /obj/machinery/door))
door = target
if (istype(interacting_with, /obj/machinery/door))
door = interacting_with
if (!door.opens_with_door_remote)
return
return ITEM_INTERACT_BLOCKING
else
for (var/obj/machinery/door/door_on_turf in get_turf(target))
for (var/obj/machinery/door/door_on_turf in get_turf(interacting_with))
if (door_on_turf.opens_with_door_remote)
door = door_on_turf
break
if (isnull(door))
return
return ITEM_INTERACT_BLOCKING
if (!door.check_access_list(access_list) || !door.requiresID())
target.balloon_alert(user, "can't access!")
return
interacting_with.balloon_alert(user, "can't access!")
return ITEM_INTERACT_BLOCKING
var/obj/machinery/door/airlock/airlock = door
if (!door.hasPower() || (istype(airlock) && !airlock.canAIControl()))
target.balloon_alert(user, mode == WAND_OPEN ? "it won't budge!" : "nothing happens!")
return
interacting_with.balloon_alert(user, mode == WAND_OPEN ? "it won't budge!" : "nothing happens!")
return ITEM_INTERACT_BLOCKING
switch (mode)
if (WAND_OPEN)
@@ -73,8 +73,8 @@
door.close()
if (WAND_BOLT)
if (!istype(airlock))
target.balloon_alert(user, "only airlocks!")
return
interacting_with.balloon_alert(user, "only airlocks!")
return ITEM_INTERACT_BLOCKING
if (airlock.locked)
airlock.unbolt()
@@ -84,12 +84,14 @@
log_combat(user, airlock, "bolted", src)
if (WAND_EMERGENCY)
if (!istype(airlock))
target.balloon_alert(user, "only airlocks!")
return
interacting_with.balloon_alert(user, "only airlocks!")
return ITEM_INTERACT_BLOCKING
airlock.emergency = !airlock.emergency
airlock.update_appearance(UPDATE_ICON)
return ITEM_INTERACT_SUCCESS
/obj/item/door_remote/update_icon_state()
var/icon_state_mode
switch(mode)
+20 -32
View File
@@ -421,7 +421,7 @@
return LOWER_TEXT(crayon_regex.Replace(text, ""))
/// Attempts to color the target. Returns how many charges were used.
/obj/item/toy/crayon/proc/use_on(atom/target, mob/user, params)
/obj/item/toy/crayon/proc/use_on(atom/target, mob/user, list/modifiers)
var/static/list/punctuation = list("!","?",".",",","/","+","-","=","%","#","&")
if(istype(target, /obj/effect/decal/cleanable))
@@ -491,7 +491,6 @@
else
graf_rot = 0
var/list/modifiers = params2list(params)
var/clickx
var/clicky
@@ -568,19 +567,12 @@
reagents.expose(draw_turf, methods = TOUCH, volume_modifier = volume_multiplier)
check_empty(user)
/obj/item/toy/crayon/afterattack(atom/target, mob/user, proximity, params)
. = ..()
/obj/item/toy/crayon/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if (!check_allowed_items(interacting_with))
return NONE
if(!proximity)
return
if (isitem(target))
. |= AFTERATTACK_PROCESSED_ITEM
if (!check_allowed_items(target))
return
use_on(target, user, params)
use_on(interacting_with, user, modifiers)
return ITEM_INTERACT_BLOCKING
/obj/item/toy/crayon/get_writing_implement_details()
return list(
@@ -674,7 +666,7 @@
charges = INFINITE_CHARGES
dye_color = DYE_RAINBOW
/obj/item/toy/crayon/rainbow/afterattack(atom/target, mob/user, proximity, params)
/obj/item/toy/crayon/rainbow/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
set_painting_tool_color(rgb(rand(0,255), rand(0,255), rand(0,255)))
return ..()
@@ -833,7 +825,7 @@
. += "It is empty."
. += span_notice("Alt-click [src] to [ is_capped ? "take the cap off" : "put the cap on"]. Right-click a colored object to match its existing color.")
/obj/item/toy/crayon/spraycan/use_on(atom/target, mob/user, params)
/obj/item/toy/crayon/spraycan/use_on(atom/target, mob/user, list/modifiers)
if(is_capped)
balloon_alert(user, "take the cap off first!")
return
@@ -927,17 +919,15 @@
return ..()
/obj/item/toy/crayon/spraycan/afterattack_secondary(atom/target, mob/user, proximity_flag, click_parameters)
if(!proximity_flag)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
/obj/item/toy/crayon/spraycan/interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
if(is_capped)
balloon_alert(user, "take the cap off first!")
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
return ITEM_INTERACT_BLOCKING
if(check_empty(user))
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
return ITEM_INTERACT_BLOCKING
if(isbodypart(target) && actually_paints)
var/obj/item/bodypart/limb = target
if(isbodypart(interacting_with) && actually_paints)
var/obj/item/bodypart/limb = interacting_with
if(!IS_ORGANIC_LIMB(limb))
var/list/skins = list()
var/static/list/style_list_icons = list("standard" = 'icons/mob/augmentation/augments.dmi', "engineer" = 'icons/mob/augmentation/augments_engineer.dmi', "security" = 'icons/mob/augmentation/augments_security.dmi', "mining" = 'icons/mob/augmentation/augments_mining.dmi')
@@ -950,16 +940,14 @@
if(choice && (use_charges(user, 5, requires_full = FALSE)))
playsound(user.loc, 'sound/effects/spray.ogg', 5, TRUE, 5)
limb.change_appearance(style_list_icons[choice], greyscale = FALSE)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
if(target.color)
paint_color = target.color
return ITEM_INTERACT_SUCCESS
if(interacting_with.color)
paint_color = interacting_with.color
balloon_alert(user, "matched colour of target")
update_appearance()
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
else
balloon_alert(user, "can't match those colours!")
return SECONDARY_ATTACK_CONTINUE_CHAIN
return ITEM_INTERACT_BLOCKING
balloon_alert(user, "can't match those colours!")
return ITEM_INTERACT_BLOCKING
/obj/item/toy/crayon/spraycan/click_alt(mob/user)
if(!has_cap)
@@ -969,7 +957,7 @@
update_appearance()
return CLICK_ACTION_SUCCESS
/obj/item/toy/crayon/spraycan/attackby_storage_insert(datum/storage, atom/storage_holder, mob/user)
/obj/item/toy/crayon/spraycan/storage_insert_on_interaction(datum/storage, atom/storage_holder, mob/user)
return is_capped
/obj/item/toy/crayon/spraycan/update_icon_state()
+8 -4
View File
@@ -12,12 +12,16 @@
var/datum/species/selected_species
var/valid_species = list()
/obj/item/debug/human_spawner/afterattack(atom/target, mob/user, proximity)
..()
if(isturf(target))
var/mob/living/carbon/human/H = new /mob/living/carbon/human(target)
/obj/item/debug/human_spawner/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return interact_with_atom(interacting_with, user, modifiers)
/obj/item/debug/human_spawner/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(isturf(interacting_with))
var/mob/living/carbon/human/H = new /mob/living/carbon/human(interacting_with)
if(selected_species)
H.set_species(selected_species)
return ITEM_INTERACT_SUCCESS
return NONE
/obj/item/debug/human_spawner/attack_self(mob/user)
..()
@@ -19,32 +19,28 @@
///Can we be used infinitely?
var/infinite = FALSE
/obj/item/anomaly_releaser/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
if(used || !proximity_flag || !istype(target, /obj/item/assembly/signaler/anomaly))
return
if(!do_after(user, 3 SECONDS, target))
return
/obj/item/anomaly_releaser/interact_with_atom(atom/target, mob/living/user, list/modifiers)
if(!istype(target, /obj/item/assembly/signaler/anomaly))
return NONE
if(used)
return
return ITEM_INTERACT_BLOCKING
if(!do_after(user, 3 SECONDS, target))
return ITEM_INTERACT_BLOCKING
if(used)
return ITEM_INTERACT_BLOCKING
var/obj/item/assembly/signaler/anomaly/core = target
if(!core.anomaly_type)
return
return ITEM_INTERACT_BLOCKING
var/obj/effect/anomaly/anomaly = new core.anomaly_type(get_turf(core))
anomaly.stabilize()
log_combat(user, anomaly, "released", object = src, addition = "in [get_area(target)].")
if(infinite)
return
icon_state = used_icon_state
used = TRUE
name = "used " + name
qdel(core)
if(!infinite)
icon_state = used_icon_state
used = TRUE
name = "used " + name
qdel(core)
return ITEM_INTERACT_SUCCESS
@@ -36,29 +36,25 @@
else
to_chat(user, span_warning("You can't use [src] while inside something!"))
/obj/item/chameleon/afterattack(atom/target, mob/user , proximity)
. = ..()
if(!proximity)
return
. |= AFTERATTACK_PROCESSED_ITEM
/obj/item/chameleon/interact_with_atom(atom/target, mob/living/user, list/modifiers)
if(!check_sprite(target))
return
return ITEM_INTERACT_BLOCKING
if(active_dummy)//I now present you the blackli(f)st
return
return ITEM_INTERACT_BLOCKING
if(isturf(target))
return
return ITEM_INTERACT_BLOCKING
if(ismob(target))
return
return ITEM_INTERACT_BLOCKING
if(istype(target, /obj/structure/falsewall))
return
return ITEM_INTERACT_BLOCKING
if(target.alpha != 255)
return
return ITEM_INTERACT_BLOCKING
if(target.invisibility != 0)
return
if(iseffect(target))
if(!(istype(target, /obj/effect/decal))) //be a footprint
return
return ITEM_INTERACT_BLOCKING
if(iseffect(target) && !istype(target, /obj/effect/decal)) //be a footprint
return ITEM_INTERACT_BLOCKING
make_copy(target, user)
return ITEM_INTERACT_SUCCESS
/obj/item/chameleon/proc/make_copy(atom/target, mob/user)
playsound(get_turf(src), 'sound/weapons/flash.ogg', 100, TRUE, -6)
@@ -55,19 +55,18 @@
addtimer(CALLBACK(src, PROC_REF(recharge)), ROUND_UP(recharge_time))
return TRUE //The actual circuit magic itself is done on a per-object basis
/obj/item/electroadaptive_pseudocircuit/afterattack(atom/target, mob/living/user, proximity)
. = ..()
if(!proximity)
return
. |= AFTERATTACK_PROCESSED_ITEM
if(!is_type_in_typecache(target, recycleable_circuits))
return
/obj/item/electroadaptive_pseudocircuit/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!is_type_in_typecache(interacting_with, recycleable_circuits))
return NONE
circuits++
maptext = MAPTEXT(circuits)
user.visible_message(span_notice("User breaks down [target] with [src]."), \
span_notice("You recycle [target] into [src]. It now has material for <b>[circuits]</b> circuits."))
user.visible_message(
span_notice("User breaks down [interacting_with] with [src]."),
span_notice("You recycle [interacting_with] into [src]. It now has material for <b>[circuits]</b> circuits.")
)
playsound(user, 'sound/items/deconstruct.ogg', 50, TRUE)
qdel(target)
qdel(interacting_with)
return ITEM_INTERACT_SUCCESS
/obj/item/electroadaptive_pseudocircuit/proc/recharge()
playsound(src, 'sound/machines/chime.ogg', 25, TRUE)
+172 -167
View File
@@ -108,162 +108,170 @@
user.visible_message(span_suicide("[user] is putting [src] close to [user.p_their()] eyes and turning it on! It looks like [user.p_theyre()] trying to commit suicide!"))
return FIRELOSS
/obj/item/flashlight/attack(mob/living/carbon/M, mob/living/carbon/human/user)
add_fingerprint(user)
if(istype(M) && light_on && (user.zone_selected in list(BODY_ZONE_PRECISE_EYES, BODY_ZONE_PRECISE_MOUTH)))
/obj/item/flashlight/proc/eye_examine(mob/living/carbon/human/M, mob/living/user)
. = list()
if((M.head && M.head.flags_cover & HEADCOVERSEYES) || (M.wear_mask && M.wear_mask.flags_cover & MASKCOVERSEYES) || (M.glasses && M.glasses.flags_cover & GLASSESCOVERSEYES))
to_chat(user, span_warning("You're going to need to remove that [(M.head && M.head.flags_cover & HEADCOVERSEYES) ? "helmet" : (M.wear_mask && M.wear_mask.flags_cover & MASKCOVERSEYES) ? "mask": "glasses"] first!"))
return
if((HAS_TRAIT(user, TRAIT_CLUMSY) || HAS_TRAIT(user, TRAIT_DUMB)) && prob(50)) //too dumb to use flashlight properly
return ..() //just hit them in the head
var/obj/item/organ/internal/eyes/E = M.get_organ_slot(ORGAN_SLOT_EYES)
var/obj/item/organ/internal/brain = M.get_organ_slot(ORGAN_SLOT_BRAIN)
if(!E)
to_chat(user, span_warning("[M] doesn't have any eyes!"))
return
if(!ISADVANCEDTOOLUSER(user))
to_chat(user, span_warning("You don't have the dexterity to do this!"))
return
M.flash_act(visual = TRUE, length = (user.combat_mode) ? 2.5 SECONDS : 1 SECONDS) // Apply a 1 second flash effect to the target. The duration increases to 2.5 Seconds if you have combat mode on.
if(!M.get_bodypart(BODY_ZONE_HEAD))
to_chat(user, span_warning("[M] doesn't have a head!"))
return
if(M == user) //they're using it on themselves
user.visible_message(span_warning("[user] shines [src] into [M.p_their()] eyes."), ignored_mobs = user)
. += span_info("You direct [src] to into your eyes:\n")
if(light_power < 1)
to_chat(user, "[span_warning("\The [src] isn't bright enough to see anything!")] ")
return
var/render_list = list()//information will be packaged in a list for clean display to the user
switch(user.zone_selected)
if(BODY_ZONE_PRECISE_EYES)
if((M.head && M.head.flags_cover & HEADCOVERSEYES) || (M.wear_mask && M.wear_mask.flags_cover & MASKCOVERSEYES) || (M.glasses && M.glasses.flags_cover & GLASSESCOVERSEYES))
to_chat(user, span_warning("You're going to need to remove that [(M.head && M.head.flags_cover & HEADCOVERSEYES) ? "helmet" : (M.wear_mask && M.wear_mask.flags_cover & MASKCOVERSEYES) ? "mask": "glasses"] first!"))
return
var/obj/item/organ/internal/eyes/E = M.get_organ_slot(ORGAN_SLOT_EYES)
var/obj/item/organ/internal/brain = M.get_organ_slot(ORGAN_SLOT_BRAIN)
if(!E)
to_chat(user, span_warning("[M] doesn't have any eyes!"))
return
M.flash_act(visual = TRUE, length = (user.combat_mode) ? 2.5 SECONDS : 1 SECONDS) // Apply a 1 second flash effect to the target. The duration increases to 2.5 Seconds if you have combat mode on.
if(M == user) //they're using it on themselves
user.visible_message(span_warning("[user] shines [src] into [M.p_their()] eyes."), ignored_mobs = user)
render_list += span_info("You direct [src] to into your eyes:\n")
if(M.is_blind())
render_list += "<span class='notice ml-1'>You're not entirely certain what you were expecting...</span>\n"
else
render_list += "<span class='notice ml-1'>Trippy!</span>\n"
else
user.visible_message(span_warning("[user] directs [src] to [M]'s eyes."), ignored_mobs = user)
render_list += span_info("You direct [src] to [M]'s eyes:\n")
if(M.stat == DEAD || M.is_blind() || M.get_eye_protection() > FLASH_PROTECTION_WELDER)
render_list += "<span class='danger ml-1'>[M.p_Their()] pupils don't react to the light!</span>\n"//mob is dead
else if(brain.damage > 20)
render_list += "<span class='danger ml-1'>[M.p_Their()] pupils contract unevenly!</span>\n"//mob has sustained damage to their brain
else
render_list += "<span class='notice ml-1'>[M.p_Their()] pupils narrow.</span>\n"//they're okay :D
if(M.dna && M.dna.check_mutation(/datum/mutation/human/xray))
render_list += "<span class='danger ml-1'>[M.p_Their()] pupils give an eerie glow!</span>\n"//mob has X-ray vision
//display our packaged information in an examine block for easy reading
to_chat(user, examine_block(jointext(render_list, "")), type = MESSAGE_TYPE_INFO)
if(BODY_ZONE_PRECISE_MOUTH)
if(M.is_mouth_covered())
to_chat(user, span_warning("You're going to need to remove that [(M.head && M.head.flags_cover & HEADCOVERSMOUTH) ? "helmet" : "mask"] first!"))
return
var/list/mouth_organs = new
for(var/obj/item/organ/organ as anything in M.organs)
if(organ.zone == BODY_ZONE_PRECISE_MOUTH)
mouth_organs.Add(organ)
var/organ_list = ""
var/organ_count = LAZYLEN(mouth_organs)
if(organ_count)
for(var/I in 1 to organ_count)
if(I > 1)
if(I == mouth_organs.len)
organ_list += ", and "
else
organ_list += ", "
var/obj/item/organ/O = mouth_organs[I]
organ_list += (O.gender == "plural" ? O.name : "\an [O.name]")
var/pill_count = 0
for(var/datum/action/item_action/hands_free/activate_pill/AP in M.actions)
pill_count++
if(M == user)//if we're looking on our own mouth
var/can_use_mirror = FALSE
if(isturf(user.loc))
var/obj/structure/mirror/mirror = locate(/obj/structure/mirror, user.loc)
if(mirror)
switch(user.dir)
if(NORTH)
can_use_mirror = mirror.pixel_y > 0
if(SOUTH)
can_use_mirror = mirror.pixel_y < 0
if(EAST)
can_use_mirror = mirror.pixel_x > 0
if(WEST)
can_use_mirror = mirror.pixel_x < 0
M.visible_message(span_notice("[M] directs [src] to [ M.p_their()] mouth."), ignored_mobs = user)
render_list += span_info("You point [src] into your mouth:\n")
if(!can_use_mirror)
to_chat(user, span_notice("You can't see anything without a mirror."))
return
if(organ_count)
render_list += "<span class='notice ml-1'>Inside your mouth [organ_count > 1 ? "are" : "is"] [organ_list].</span>\n"
else
render_list += "<span class='notice ml-1'>There's nothing inside your mouth.</span>\n"
if(pill_count)
render_list += "<span class='notice ml-1'>You have [pill_count] implanted pill[pill_count > 1 ? "s" : ""].</span>\n"
else //if we're looking in someone elses mouth
user.visible_message(span_notice("[user] directs [src] to [M]'s mouth."), ignored_mobs = user)
render_list += span_info("You point [src] into [M]'s mouth:\n")
if(organ_count)
render_list += "<span class='notice ml-1'>Inside [ M.p_their()] mouth [organ_count > 1 ? "are" : "is"] [organ_list].</span>\n"
else
render_list += "<span class='notice ml-1'>[M] doesn't have any organs in [ M.p_their()] mouth.</span>\n"
if(pill_count)
render_list += "<span class='notice ml-1'>[M] has [pill_count] pill[pill_count > 1 ? "s" : ""] implanted in [ M.p_their()] teeth.</span>\n"
//assess any suffocation damage
var/hypoxia_status = M.getOxyLoss() > 20
if(M == user)
if(hypoxia_status)
render_list += "<span class='danger ml-1'>Your lips appear blue!</span>\n"//you have suffocation damage
else
render_list += "<span class='notice ml-1'>Your lips appear healthy.</span>\n"//you're okay!
else
if(hypoxia_status)
render_list += "<span class='danger ml-1'>[M.p_Their()] lips appear blue!</span>\n"//they have suffocation damage
else
render_list += "<span class='notice ml-1'>[M.p_Their()] lips appear healthy.</span>\n"//they're okay!
//assess blood level
if(M == user)
render_list += span_info("You press a finger to your gums:\n")
else
render_list += span_info("You press a finger to [M.p_their()] gums:\n")
if(M.blood_volume <= BLOOD_VOLUME_SAFE && M.blood_volume > BLOOD_VOLUME_OKAY)
render_list += "<span class='danger ml-1'>Color returns slowly!</span>\n"//low blood
else if(M.blood_volume <= BLOOD_VOLUME_OKAY)
render_list += "<span class='danger ml-1'>Color does not return!</span>\n"//critical blood
else
render_list += "<span class='notice ml-1'>Color returns quickly.</span>\n"//they're okay :D
//display our packaged information in an examine block for easy reading
to_chat(user, examine_block(jointext(render_list, "")), type = MESSAGE_TYPE_INFO)
if(M.is_blind())
. += "<span class='notice ml-1'>You're not entirely certain what you were expecting...</span>\n"
else
. += "<span class='notice ml-1'>Trippy!</span>\n"
else
return ..()
user.visible_message(span_warning("[user] directs [src] to [M]'s eyes."), ignored_mobs = user)
. += span_info("You direct [src] to [M]'s eyes:\n")
if(M.stat == DEAD || M.is_blind() || M.get_eye_protection() > FLASH_PROTECTION_WELDER)
. += "<span class='danger ml-1'>[M.p_Their()] pupils don't react to the light!</span>\n"//mob is dead
else if(brain.damage > 20)
. += "<span class='danger ml-1'>[M.p_Their()] pupils contract unevenly!</span>\n"//mob has sustained damage to their brain
else
. += "<span class='notice ml-1'>[M.p_Their()] pupils narrow.</span>\n"//they're okay :D
if(M.dna && M.dna.check_mutation(/datum/mutation/human/xray))
. += "<span class='danger ml-1'>[M.p_Their()] pupils give an eerie glow!</span>\n"//mob has X-ray vision
return .
/obj/item/flashlight/proc/mouth_examine(mob/living/carbon/human/M, mob/living/user)
. = list()
if(M.is_mouth_covered())
to_chat(user, span_warning("You're going to need to remove that [(M.head && M.head.flags_cover & HEADCOVERSMOUTH) ? "helmet" : "mask"] first!"))
return
var/list/mouth_organs = list()
for(var/obj/item/organ/organ as anything in M.organs)
if(organ.zone == BODY_ZONE_PRECISE_MOUTH)
mouth_organs.Add(organ)
var/organ_list = ""
var/organ_count = LAZYLEN(mouth_organs)
if(organ_count)
for(var/I in 1 to organ_count)
if(I > 1)
if(I == mouth_organs.len)
organ_list += ", and "
else
organ_list += ", "
var/obj/item/organ/O = mouth_organs[I]
organ_list += (O.gender == "plural" ? O.name : "\an [O.name]")
var/pill_count = 0
for(var/datum/action/item_action/hands_free/activate_pill/AP in M.actions)
pill_count++
if(M == user)//if we're looking on our own mouth
var/can_use_mirror = FALSE
if(isturf(user.loc))
var/obj/structure/mirror/mirror = locate(/obj/structure/mirror, user.loc)
if(mirror)
switch(user.dir)
if(NORTH)
can_use_mirror = mirror.pixel_y > 0
if(SOUTH)
can_use_mirror = mirror.pixel_y < 0
if(EAST)
can_use_mirror = mirror.pixel_x > 0
if(WEST)
can_use_mirror = mirror.pixel_x < 0
M.visible_message(span_notice("[M] directs [src] to [ M.p_their()] mouth."), ignored_mobs = user)
. += span_info("You point [src] into your mouth:\n")
if(!can_use_mirror)
to_chat(user, span_notice("You can't see anything without a mirror."))
return
if(organ_count)
. += "<span class='notice ml-1'>Inside your mouth [organ_count > 1 ? "are" : "is"] [organ_list].</span>\n"
else
. += "<span class='notice ml-1'>There's nothing inside your mouth.</span>\n"
if(pill_count)
. += "<span class='notice ml-1'>You have [pill_count] implanted pill[pill_count > 1 ? "s" : ""].</span>\n"
else //if we're looking in someone elses mouth
user.visible_message(span_notice("[user] directs [src] to [M]'s mouth."), ignored_mobs = user)
. += span_info("You point [src] into [M]'s mouth:\n")
if(organ_count)
. += "<span class='notice ml-1'>Inside [ M.p_their()] mouth [organ_count > 1 ? "are" : "is"] [organ_list].</span>\n"
else
. += "<span class='notice ml-1'>[M] doesn't have any organs in [ M.p_their()] mouth.</span>\n"
if(pill_count)
. += "<span class='notice ml-1'>[M] has [pill_count] pill[pill_count > 1 ? "s" : ""] implanted in [ M.p_their()] teeth.</span>\n"
//assess any suffocation damage
var/hypoxia_status = M.getOxyLoss() > 20
if(M == user)
if(hypoxia_status)
. += "<span class='danger ml-1'>Your lips appear blue!</span>\n"//you have suffocation damage
else
. += "<span class='notice ml-1'>Your lips appear healthy.</span>\n"//you're okay!
else
if(hypoxia_status)
. += "<span class='danger ml-1'>[M.p_Their()] lips appear blue!</span>\n"//they have suffocation damage
else
. += "<span class='notice ml-1'>[M.p_Their()] lips appear healthy.</span>\n"//they're okay!
//assess blood level
if(M == user)
. += span_info("You press a finger to your gums:\n")
else
. += span_info("You press a finger to [M.p_their()] gums:\n")
if(M.blood_volume <= BLOOD_VOLUME_SAFE && M.blood_volume > BLOOD_VOLUME_OKAY)
. += "<span class='danger ml-1'>Color returns slowly!</span>\n"//low blood
else if(M.blood_volume <= BLOOD_VOLUME_OKAY)
. += "<span class='danger ml-1'>Color does not return!</span>\n"//critical blood
else
. += "<span class='notice ml-1'>Color returns quickly.</span>\n"//they're okay :D
/obj/item/flashlight/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!ishuman(interacting_with))
return NONE
if(!light_on)
return NONE
add_fingerprint(user)
if(user.combat_mode || (user.zone_selected != BODY_ZONE_PRECISE_EYES && user.zone_selected != BODY_ZONE_PRECISE_MOUTH))
return NONE
if((HAS_TRAIT(user, TRAIT_CLUMSY) || HAS_TRAIT(user, TRAIT_DUMB)) && prob(50)) //too dumb to use flashlight properly
return ITEM_INTERACT_SKIP_TO_ATTACK //just hit them in the head
. = ITEM_INTERACT_BLOCKING
if(!ISADVANCEDTOOLUSER(user))
to_chat(user, span_warning("You don't have the dexterity to do this!"))
return
var/mob/living/scanning = interacting_with
if(!scanning.get_bodypart(BODY_ZONE_HEAD))
to_chat(user, span_warning("[scanning] doesn't have a head!"))
return
if(light_power < 1)
to_chat(user, span_warning("[src] isn't bright enough to see anything!"))
return
var/list/render_list = list()
switch(user.zone_selected)
if(BODY_ZONE_PRECISE_EYES)
render_list += eye_examine(scanning, user)
if(BODY_ZONE_PRECISE_MOUTH)
render_list += mouth_examine(scanning, user)
if(length(render_list))
//display our packaged information in an examine block for easy reading
to_chat(user, examine_block(jointext(render_list, "")), type = MESSAGE_TYPE_INFO)
return ITEM_INTERACT_SUCCESS
return ITEM_INTERACT_BLOCKING
/// for directional sprites - so we get the same sprite in the inventory each time we pick one up
/obj/item/flashlight/equipped(mob/user, slot, initial)
@@ -299,24 +307,21 @@
light_color = "#CCFFFF"
COOLDOWN_DECLARE(holosign_cooldown)
/obj/item/flashlight/pen/afterattack(atom/target, mob/user, proximity_flag)
. = ..()
if(proximity_flag)
return
/obj/item/flashlight/pen/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!COOLDOWN_FINISHED(src, holosign_cooldown))
balloon_alert(user, "not ready!")
return
return ITEM_INTERACT_BLOCKING
var/target_turf = get_turf(target)
var/turf/target_turf = get_turf(interacting_with)
var/mob/living/living_target = locate(/mob/living) in target_turf
if(!living_target || (living_target == user))
return
return ITEM_INTERACT_BLOCKING
to_chat(living_target, span_boldnotice("[user] is offering medical assistance; please halt your actions."))
new /obj/effect/temp_visual/medical_holosign(target_turf, user) //produce a holographic glow
COOLDOWN_START(src, holosign_cooldown, 10 SECONDS)
return ITEM_INTERACT_SUCCESS
// see: [/datum/wound/burn/flesh/proc/uv()]
/obj/item/flashlight/pen/paramedic
@@ -731,26 +736,26 @@
..()
return
/obj/item/flashlight/emp/afterattack(atom/movable/A, mob/user, proximity)
/obj/item/flashlight/emp/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
. = ..()
if(!proximity)
if(. & ITEM_INTERACT_ANY_BLOCKER)
return
if(emp_cur_charges > 0)
emp_cur_charges -= 1
if(ismob(A))
var/mob/M = A
log_combat(user, M, "attacked", "EMP-light")
M.visible_message(span_danger("[user] blinks \the [src] at \the [A]."), \
if(ismob(interacting_with))
var/mob/empd = interacting_with
log_combat(user, empd, "attacked", "EMP-light")
empd.visible_message(span_danger("[user] blinks \the [src] at \the [empd]."), \
span_userdanger("[user] blinks \the [src] at you."))
else
A.visible_message(span_danger("[user] blinks \the [src] at \the [A]."))
interacting_with.visible_message(span_danger("[user] blinks \the [src] at \the [interacting_with]."))
to_chat(user, span_notice("\The [src] now has [emp_cur_charges] charge\s."))
A.emp_act(EMP_HEAVY)
interacting_with.emp_act(EMP_HEAVY)
else
to_chat(user, span_warning("\The [src] needs time to recharge!"))
return
return ITEM_INTERACT_SUCCESS
/obj/item/flashlight/emp/debug //for testing emp_act()
name = "debug EMP flashlight"
@@ -21,41 +21,42 @@
/// Checks to make sure the projector isn't busy with making another forcefield.
var/force_proj_busy = FALSE
/obj/item/forcefield_projector/afterattack(atom/target, mob/user, proximity_flag)
. = ..()
if(!check_allowed_items(target, not_inside = TRUE))
return
. |= AFTERATTACK_PROCESSED_ITEM
if(istype(target, /obj/structure/projected_forcefield))
var/obj/structure/projected_forcefield/F = target
/obj/item/forcefield_projector/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return interact_with_atom(interacting_with, user, modifiers)
/obj/item/forcefield_projector/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!check_allowed_items(interacting_with, not_inside = TRUE))
return NONE
if(istype(interacting_with, /obj/structure/projected_forcefield))
var/obj/structure/projected_forcefield/F = interacting_with
if(F.generator == src)
to_chat(user, span_notice("You deactivate [F]."))
qdel(F)
return
var/turf/T = get_turf(target)
return ITEM_INTERACT_BLOCKING
var/turf/T = get_turf(interacting_with)
var/obj/structure/projected_forcefield/found_field = locate() in T
if(found_field)
to_chat(user, span_warning("There is already a forcefield in that location!"))
return
return ITEM_INTERACT_BLOCKING
if(T.density)
return
return ITEM_INTERACT_BLOCKING
if(get_dist(T,src) > field_distance_limit)
return
if (get_turf(src) == T)
return ITEM_INTERACT_BLOCKING
if(get_turf(src) == T)
to_chat(user, span_warning("Target is too close, aborting!"))
return
return ITEM_INTERACT_BLOCKING
if(LAZYLEN(current_fields) >= max_fields)
to_chat(user, span_warning("[src] cannot sustain any more forcefields!"))
return
return ITEM_INTERACT_BLOCKING
if(force_proj_busy)
to_chat(user, span_notice("[src] is busy creating a forcefield."))
return
return ITEM_INTERACT_BLOCKING
playsound(loc, 'sound/machines/click.ogg', 20, TRUE)
if(creation_time)
force_proj_busy = TRUE
if(!do_after(user, creation_time, target = target))
if(!do_after(user, creation_time, target = interacting_with))
force_proj_busy = FALSE
return
return ITEM_INTERACT_BLOCKING
force_proj_busy = FALSE
playsound(src,'sound/weapons/resonator_fire.ogg',50,TRUE)
@@ -63,6 +64,7 @@
var/obj/structure/projected_forcefield/F = new(T, src)
current_fields += F
user.changeNext_move(CLICK_CD_MELEE)
return ITEM_INTERACT_SUCCESS
/obj/item/forcefield_projector/attack_self(mob/user)
if(LAZYLEN(current_fields))
@@ -67,18 +67,18 @@
update_appearance(UPDATE_ICON)
balloon_alert(user, "switch [scanning ? "on" : "off"]")
/obj/item/geiger_counter/afterattack(atom/target, mob/living/user, params)
. = ..()
. |= AFTERATTACK_PROCESSED_ITEM
/obj/item/geiger_counter/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return interact_with_atom(interacting_with, user, modifiers)
/obj/item/geiger_counter/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if (user.combat_mode)
return
return NONE
if (!CAN_IRRADIATE(interacting_with))
return NONE
if (!CAN_IRRADIATE(target))
return
user.visible_message(span_notice("[user] scans [target] with [src]."), span_notice("You scan [target]'s radiation levels with [src]..."))
addtimer(CALLBACK(src, PROC_REF(scan), target, user), 20, TIMER_UNIQUE) // Let's not have spamming GetAllContents
user.visible_message(span_notice("[user] scans [interacting_with] with [src]."), span_notice("You scan [interacting_with]'s radiation levels with [src]..."))
addtimer(CALLBACK(src, PROC_REF(scan), interacting_with, user), 20, TIMER_UNIQUE) // Let's not have spamming GetAllContents
return ITEM_INTERACT_SUCCESS
/obj/item/geiger_counter/equipped(mob/user, slot, initial)
. = ..()
@@ -182,13 +182,15 @@
. += "<i>\The [diode.name]'s size is much smaller compared to the previous generation lasers, \
and the wide margin between it and the focus lens could probably house <b>a crystal</b> of some sort.</i>"
/obj/item/laser_pointer/afterattack(atom/target, mob/living/user, flag, params)
. = ..()
. |= AFTERATTACK_PROCESSED_ITEM
laser_act(target, user, params)
/obj/item/laser_pointer/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return interact_with_atom(interacting_with, user, modifiers)
/obj/item/laser_pointer/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
laser_act(interacting_with, user, modifiers)
return ITEM_INTERACT_BLOCKING
///Handles shining the clicked atom,
/obj/item/laser_pointer/proc/laser_act(atom/target, mob/living/user, params)
/obj/item/laser_pointer/proc/laser_act(atom/target, mob/living/user, list/modifiers)
if(isnull(diode))
to_chat(user, span_notice("You point [src] at [target], but nothing happens!"))
return
@@ -286,7 +288,6 @@
//setup pointer blip
var/mutable_appearance/laser = mutable_appearance('icons/obj/weapons/guns/projectiles.dmi', pointer_icon_state)
var/list/modifiers = params2list(params)
if(modifiers)
if(LAZYACCESS(modifiers, ICON_X))
laser.pixel_x = (text2num(LAZYACCESS(modifiers, ICON_X)) - 16)
@@ -62,11 +62,23 @@
. = ..()
. += status_string()
/obj/item/lightreplacer/pre_attack(atom/target, mob/living/user, params)
. = ..()
if(.)
return
return do_action(target, user) //if we are attacking a valid target[light, floodlight or turf] stop here
/obj/item/lightreplacer/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return do_action(interacting_with, user) ? ITEM_INTERACT_SUCCESS : NONE
/obj/item/lightreplacer/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
// has no bluespace capabilities
if(!bluespace_toggle)
return NONE
// target not in range
if(interacting_with.z != user.z)
return NONE
// target not in view
if(!(interacting_with in view(7, get_turf(user))))
user.balloon_alert(user, "out of range!")
return ITEM_INTERACT_BLOCKING
//replace lights & stuff
return do_action(interacting_with, user) ? ITEM_INTERACT_SUCCESS : NONE
/obj/item/lightreplacer/attackby(obj/item/insert, mob/user, params)
. = ..()
@@ -239,23 +251,6 @@
return FALSE
/obj/item/lightreplacer/afterattack(atom/target, mob/user, proximity)
. = ..()
// has no bluespace capabilities
if(!bluespace_toggle)
return
// target not in range
if(target.z != user.z)
return
// target not in view
if(!(target in view(7, get_turf(user))))
user.balloon_alert(user, "out of range!")
return
//replace lights & stuff
do_action(target, user)
/obj/item/lightreplacer/proc/status_string()
return "It has [uses] light\s remaining (plus [bulb_shards]/[BULB_SHARDS_REQUIRED] fragment\s)."
+11 -11
View File
@@ -9,24 +9,24 @@
custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 2.5, /datum/material/glass = SHEET_MATERIAL_AMOUNT)
/obj/item/pipe_painter/afterattack(atom/target, mob/user, proximity_flag)
. = ..()
//Make sure we only paint adjacent items
if(!proximity_flag)
return
if(istype(target, /obj/machinery/atmospherics))
var/obj/machinery/atmospherics/target_pipe = target
/obj/item/pipe_painter/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(istype(interacting_with, /obj/machinery/atmospherics))
var/obj/machinery/atmospherics/target_pipe = interacting_with
target_pipe.paint(GLOB.pipe_paint_colors[paint_color])
playsound(src, 'sound/machines/click.ogg', 50, TRUE)
balloon_alert(user, "painted in [paint_color] color")
else if(istype(target, /obj/item/pipe))
var/obj/item/pipe/target_pipe = target
return ITEM_INTERACT_SUCCESS
if(istype(interacting_with, /obj/item/pipe))
var/obj/item/pipe/target_pipe = interacting_with
var/color = GLOB.pipe_paint_colors[paint_color]
target_pipe.pipe_color = color
target.add_atom_colour(color, FIXED_COLOUR_PRIORITY)
target_pipe.add_atom_colour(color, FIXED_COLOUR_PRIORITY)
playsound(src, 'sound/machines/click.ogg', 50, TRUE)
balloon_alert(user, "painted in [paint_color] color")
return ITEM_INTERACT_SUCCESS
return NONE
/obj/item/pipe_painter/attack_self(mob/user)
paint_color = tgui_input_list(user, "Which colour do you want to use?", "Pipe painter", GLOB.pipe_paint_colors)
@@ -145,12 +145,13 @@
ui_interact(user)
/obj/item/analyzer/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
if(!can_see(user, target, ranged_scan_distance))
return
. |= AFTERATTACK_PROCESSED_ITEM
atmos_scan(user, (target.return_analyzable_air() ? target : get_turf(target)))
/obj/item/analyzer/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return interact_with_atom(interacting_with, user, modifiers)
/obj/item/analyzer/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(can_see(user, interacting_with, ranged_scan_distance))
atmos_scan(user, (interacting_with.return_analyzable_air() ? interacting_with : get_turf(interacting_with)))
return NONE // Non-blocking
/// Called when our analyzer is used on something
/obj/item/analyzer/proc/on_analyze(datum/source, atom/target)
@@ -30,6 +30,15 @@
. += span_notice("It has the genetic makeup of \"[genetic_makeup_buffer["name"]]\" stored inside its buffer")
/obj/item/sequence_scanner/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(istype(interacting_with, /obj/machinery/computer/scan_consolenew))
var/obj/machinery/computer/scan_consolenew/console = interacting_with
if(console.stored_research)
to_chat(user, span_notice("[name] linked to central research database."))
discovered = console.stored_research.discovered_mutations
else
to_chat(user,span_warning("No database to update from."))
return ITEM_INTERACT_SUCCESS
if(!isliving(interacting_with))
return NONE
@@ -47,6 +56,12 @@
return ITEM_INTERACT_BLOCKING
/obj/item/sequence_scanner/interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
if(istype(interacting_with, /obj/machinery/computer/scan_consolenew))
var/obj/machinery/computer/scan_consolenew/console = interacting_with
var/buffer_index = tgui_input_number(user, "Slot:", "Which slot to export:", 1, LAZYLEN(console.genetic_makeup_buffer), 1)
console.genetic_makeup_buffer[buffer_index] = genetic_makeup_buffer
return ITEM_INTERACT_SUCCESS
if(!isliving(interacting_with))
return NONE
@@ -66,34 +81,12 @@
user.visible_message(span_notice("[user] fails to analyze [interacting_with]'s genetic makeup."), span_warning("[interacting_with] has no readable genetic makeup!"))
return ITEM_INTERACT_BLOCKING
/obj/item/sequence_scanner/afterattack_secondary(obj/object, mob/user, proximity)
. = ..()
if(!istype(object) || !proximity)
return
if(istype(object, /obj/machinery/computer/scan_consolenew))
var/obj/machinery/computer/scan_consolenew/console = object
var/buffer_index = tgui_input_number(user, "Slot:", "Which slot to export:", 1, LAZYLEN(console.genetic_makeup_buffer), 1)
console.genetic_makeup_buffer[buffer_index] = genetic_makeup_buffer
/obj/item/sequence_scanner/attack_self(mob/user)
display_sequence(user)
/obj/item/sequence_scanner/attack_self_tk(mob/user)
return
/obj/item/sequence_scanner/afterattack(obj/object, mob/user, proximity)
. = ..()
if(!istype(object) || !proximity)
return
if(istype(object, /obj/machinery/computer/scan_consolenew))
var/obj/machinery/computer/scan_consolenew/console = object
if(console.stored_research)
to_chat(user, span_notice("[name] linked to central research database."))
discovered = console.stored_research.discovered_mutations
else
to_chat(user,span_warning("No database to update from."))
///proc for scanning someone's mutations
/obj/item/sequence_scanner/proc/gene_scan(mob/living/carbon/target, mob/living/user)
if(!iscarbon(target) || !target.has_dna())
@@ -361,29 +361,41 @@ effective or pretty fucking useless.
new /obj/item/analyzer(src)
new /obj/item/wirecutters(src)
/obj/item/storage/toolbox/emergency/turret/attackby(obj/item/attacking_item, mob/living/user, params)
if(!istype(attacking_item, /obj/item/wrench/combat))
return ..()
/obj/item/storage/toolbox/emergency/turret/storage_insert_on_interacted_with(datum/storage, obj/item/inserted, mob/living/user)
if(!istype(inserted, /obj/item/wrench/combat))
return TRUE
if(!user.combat_mode)
return
if(!attacking_item.toolspeed)
return
return TRUE
if(!inserted.toolspeed)
return TRUE
return FALSE
/obj/item/storage/toolbox/emergency/turret/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
if(!istype(tool, /obj/item/wrench/combat))
return NONE
if(!user.combat_mode)
return NONE
if(!tool.toolspeed)
return ITEM_INTERACT_BLOCKING
balloon_alert(user, "constructing...")
if(!attacking_item.use_tool(src, user, 2 SECONDS, volume = 20))
return
if(!tool.use_tool(src, user, 2 SECONDS, volume = 20))
return ITEM_INTERACT_BLOCKING
balloon_alert(user, "constructed!")
user.visible_message(span_danger("[user] bashes [src] with [attacking_item]!"), \
span_danger("You bash [src] with [attacking_item]!"), null, COMBAT_MESSAGE_RANGE)
user.visible_message(
span_danger("[user] bashes [src] with [tool]!"),
span_danger("You bash [src] with [tool]!"),
null,
COMBAT_MESSAGE_RANGE,
)
playsound(src, "sound/items/drill_use.ogg", 80, TRUE, -1)
var/obj/machinery/porta_turret/syndicate/toolbox/turret = new(get_turf(loc))
set_faction(turret, user)
turret.toolbox = src
forceMove(turret)
return ITEM_INTERACT_SUCCESS
/obj/item/storage/toolbox/emergency/turret/proc/set_faction(obj/machinery/porta_turret/turret, mob/user)
turret.faction = list("[REF(user)]")
+5 -11
View File
@@ -30,18 +30,12 @@
///weak ref to the dna vault
var/datum/weakref/dna_vault_ref
/obj/item/dna_probe/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
if(!proximity_flag || !target)
return .
if (isitem(target))
. |= AFTERATTACK_PROCESSED_ITEM
if(istype(target, /obj/machinery/dna_vault) && !dna_vault_ref?.resolve())
try_linking_vault(target, user)
/obj/item/dna_probe/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(istype(interacting_with, /obj/machinery/dna_vault) && !dna_vault_ref?.resolve())
try_linking_vault(interacting_with, user)
else
scan_dna(target, user)
scan_dna(interacting_with, user)
return ITEM_INTERACT_BLOCKING
/obj/item/dna_probe/proc/try_linking_vault(atom/target, mob/user)
var/obj/machinery/dna_vault/our_vault = dna_vault_ref?.resolve()
+5 -9
View File
@@ -53,6 +53,9 @@
. = ..()
type_blacklist = list(typesof(/obj/machinery/door/airlock) + typesof(/obj/machinery/door/window/) + typesof(/obj/machinery/door/firedoor) - typesof(/obj/machinery/door/airlock/tram)) //list of all typepaths that require a specialized emag to hack.
/obj/item/card/emag/storage_insert_on_interaction(datum/storage, atom/storage_holder, mob/living/user)
return !user.combat_mode
/obj/item/card/emag/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!can_emag(interacting_with, user))
return ITEM_INTERACT_BLOCKING
@@ -60,15 +63,8 @@
interacting_with.emag_act(user, src)
return ITEM_INTERACT_SUCCESS
/obj/item/card/emag/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
// Proximity based emagging is handled by above
// This is only for ranged emagging
if(proximity_flag || prox_check)
return
. |= AFTERATTACK_PROCESSED_ITEM
interact_with_atom(target, user)
/obj/item/card/emag/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return prox_check ? NONE : interact_with_atom(interacting_with, user)
/obj/item/card/emag/proc/can_emag(atom/target, mob/user)
for (var/subtypelist in type_blacklist)
+46 -48
View File
@@ -133,7 +133,7 @@
/obj/item/extinguisher/suicide_act(mob/living/carbon/user)
if (!safety && (reagents.total_volume >= 1))
user.visible_message(span_suicide("[user] puts the nozzle to [user.p_their()] mouth. It looks like [user.p_theyre()] trying to extinguish the spark of life!"))
afterattack(user,user)
interact_with_atom(user, user)
return OXYLOSS
else if (safety && (reagents.total_volume >= 1))
user.visible_message(span_warning("[user] puts the nozzle to [user.p_their()] mouth... The safety's still on!"))
@@ -187,67 +187,65 @@
else
return FALSE
/obj/item/extinguisher/afterattack(atom/target, mob/user , flag)
. = ..()
// Make it so the extinguisher doesn't spray yourself when you click your inventory items
if (target.loc == user)
return
/obj/item/extinguisher/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return interact_with_atom(interacting_with, user, modifiers)
. |= AFTERATTACK_PROCESSED_ITEM
/obj/item/extinguisher/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if (interacting_with.loc == user)
return NONE
if(refilling)
refilling = FALSE
return NONE
if(safety)
return NONE
if (src.reagents.total_volume < 1)
balloon_alert(user, "it's empty!")
return .
if (!safety)
if (world.time < src.last_use + 12)
return .
if (src.reagents.total_volume < 1)
balloon_alert(user, "it's empty!")
return .
src.last_use = world.time
if (world.time < src.last_use + 12)
return .
playsound(src.loc, 'sound/effects/extinguish.ogg', 75, TRUE, -3)
src.last_use = world.time
var/direction = get_dir(src,interacting_with)
playsound(src.loc, 'sound/effects/extinguish.ogg', 75, TRUE, -3)
if(user.buckled && isobj(user.buckled) && !user.buckled.anchored)
var/obj/B = user.buckled
var/movementdirection = REVERSE_DIR(direction)
addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/item/extinguisher, move_chair), B, movementdirection), 0.1 SECONDS)
else
user.newtonian_move(REVERSE_DIR(direction))
var/direction = get_dir(src,target)
//Get all the turfs that can be shot at
var/turf/T = get_turf(interacting_with)
var/turf/T1 = get_step(T,turn(direction, 90))
var/turf/T2 = get_step(T,turn(direction, -90))
var/list/the_targets = list(T,T1,T2)
if(precision)
var/turf/T3 = get_step(T1, turn(direction, 90))
var/turf/T4 = get_step(T2,turn(direction, -90))
the_targets.Add(T3,T4)
if(user.buckled && isobj(user.buckled) && !user.buckled.anchored)
var/obj/B = user.buckled
var/movementdirection = REVERSE_DIR(direction)
addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/item/extinguisher, move_chair), B, movementdirection), 0.1 SECONDS)
else
user.newtonian_move(REVERSE_DIR(direction))
//Get all the turfs that can be shot at
var/turf/T = get_turf(target)
var/turf/T1 = get_step(T,turn(direction, 90))
var/turf/T2 = get_step(T,turn(direction, -90))
var/list/the_targets = list(T,T1,T2)
var/list/water_particles = list()
for(var/a in 1 to 5)
var/obj/effect/particle_effect/water/extinguisher/water = new /obj/effect/particle_effect/water/extinguisher(get_turf(src))
var/my_target = pick(the_targets)
water_particles[water] = my_target
// If precise, remove turf from targets so it won't be picked more than once
if(precision)
var/turf/T3 = get_step(T1, turn(direction, 90))
var/turf/T4 = get_step(T2,turn(direction, -90))
the_targets.Add(T3,T4)
the_targets -= my_target
var/datum/reagents/water_reagents = new /datum/reagents(5)
water.reagents = water_reagents
water_reagents.my_atom = water
reagents.trans_to(water, 1, transferred_by = user)
var/list/water_particles = list()
for(var/a in 1 to 5)
var/obj/effect/particle_effect/water/extinguisher/water = new /obj/effect/particle_effect/water/extinguisher(get_turf(src))
var/my_target = pick(the_targets)
water_particles[water] = my_target
// If precise, remove turf from targets so it won't be picked more than once
if(precision)
the_targets -= my_target
var/datum/reagents/water_reagents = new /datum/reagents(5)
water.reagents = water_reagents
water_reagents.my_atom = water
reagents.trans_to(water, 1, transferred_by = user)
//Make em move dat ass, hun
move_particles(water_particles)
return .
//Make em move dat ass, hun
move_particles(water_particles)
return ITEM_INTERACT_SKIP_TO_ATTACK // You can smack while spraying
//Particle movement loop
/obj/item/extinguisher/proc/move_particles(list/particles)
+6 -8
View File
@@ -51,15 +51,13 @@
user.visible_message(span_suicide("[user] axes [user.p_them()]self from head to toe! It looks like [user.p_theyre()] trying to commit suicide!"))
return BRUTELOSS
/obj/item/fireaxe/afterattack(atom/A, mob/user, proximity)
. = ..()
if(!proximity)
/obj/item/fireaxe/afterattack(atom/target, mob/user, click_parameters)
if(!HAS_TRAIT(src, TRAIT_WIELDED)) //destroys windows and grilles in one hit
return
if(HAS_TRAIT(src, TRAIT_WIELDED)) //destroys windows and grilles in one hit
if(istype(A, /obj/structure/window) || istype(A, /obj/structure/grille))
if(!(A.resistance_flags & INDESTRUCTIBLE))
var/obj/structure/W = A
W.atom_destruction("fireaxe")
if(target.resistance_flags & INDESTRUCTIBLE)
return
if(istype(target, /obj/structure/window) || istype(target, /obj/structure/grille))
target.atom_destruction("fireaxe")
/*
* Bone Axe
+9 -13
View File
@@ -79,21 +79,17 @@
if(lit)
. += "+lit"
/obj/item/flamethrower/afterattack(atom/target, mob/user, flag)
. = ..()
. |= AFTERATTACK_PROCESSED_ITEM
if(flag)
return // too close
/obj/item/flamethrower/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(HAS_TRAIT(user, TRAIT_PACIFISM))
to_chat(user, span_warning("You can't bring yourself to fire \the [src]! You don't want to risk harming anyone..."))
log_combat(user, target, "attempted to flamethrower", src, "with gas mixture: {[print_gas_mixture(ptank.return_analyzable_air())]}, flamethrower: \"[name]\" ([src]), igniter: \"[igniter.name]\", tank: \"[ptank.name]\" and tank distribution pressure: \"[siunit(1000 * ptank.distribute_pressure, unit = "Pa", maxdecimals = 9)]\"" + (lit ? " while lit" : "" + " but failed due to pacifism."))
return
if(user && user.get_active_held_item() == src) // Make sure our user is still holding us
var/turf/target_turf = get_turf(target)
if(target_turf)
var/turflist = get_line(user, target_turf)
log_combat(user, target, "flamethrowered", src, "with gas mixture: {[print_gas_mixture(ptank.return_analyzable_air())]}, flamethrower: \"[name]\", igniter: \"[igniter.name]\", tank: \"[ptank.name]\" and tank distribution pressure: \"[siunit(1000 * ptank.distribute_pressure, unit = "Pa", maxdecimals = 9)]\"" + (lit ? " while lit." : "."))
flame_turf(turflist)
log_combat(user, interacting_with, "attempted to flamethrower", src, "with gas mixture: {[print_gas_mixture(ptank.return_analyzable_air())]}, flamethrower: \"[name]\" ([src]), igniter: \"[igniter.name]\", tank: \"[ptank.name]\" and tank distribution pressure: \"[siunit(1000 * ptank.distribute_pressure, unit = "Pa", maxdecimals = 9)]\"" + (lit ? " while lit" : "" + " but failed due to pacifism."))
return ITEM_INTERACT_BLOCKING
var/turf/target_turf = get_turf(interacting_with)
if(target_turf)
var/turflist = get_line(user, target_turf)
log_combat(user, interacting_with, "flamethrowered", src, "with gas mixture: {[print_gas_mixture(ptank.return_analyzable_air())]}, flamethrower: \"[name]\", igniter: \"[igniter.name]\", tank: \"[ptank.name]\" and tank distribution pressure: \"[siunit(1000 * ptank.distribute_pressure, unit = "Pa", maxdecimals = 9)]\"" + (lit ? " while lit." : "."))
flame_turf(turflist)
return ITEM_INTERACT_SUCCESS
/obj/item/flamethrower/wrench_act(mob/living/user, obj/item/tool)
. = TRUE
+16 -15
View File
@@ -120,26 +120,27 @@ GLOBAL_VAR_INIT(chicks_from_eggs, 0)
else
..()
/obj/item/food/egg/afterattack_secondary(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
return
/obj/item/food/egg/interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
if(!istype(interacting_with, /obj/machinery/griddle))
return NONE
if(!istype(target, /obj/machinery/griddle))
return SECONDARY_ATTACK_CALL_NORMAL
var/obj/machinery/griddle/hit_griddle = interacting_with
if(length(hit_griddle.griddled_objects) >= hit_griddle.max_items)
interacting_with.balloon_alert(user, "no room!")
return ITEM_INTERACT_BLOCKING
var/atom/broken_egg = new /obj/item/food/rawegg(interacting_with.loc)
if(LAZYACCESS(modifiers, ICON_X))
broken_egg.pixel_x = clamp(text2num(LAZYACCESS(modifiers, ICON_X)) - 16, -(world.icon_size/2), world.icon_size/2)
if(LAZYACCESS(modifiers, ICON_Y))
broken_egg.pixel_y = clamp(text2num(LAZYACCESS(modifiers, ICON_Y)) - 16, -(world.icon_size/2), world.icon_size/2)
playsound(user, 'sound/items/sheath.ogg', 40, TRUE)
reagents.copy_to(broken_egg, reagents.total_volume)
var/atom/broken_egg = new /obj/item/food/rawegg(target.loc)
broken_egg.pixel_x = pixel_x
broken_egg.pixel_y = pixel_y
playsound(get_turf(user), 'sound/items/sheath.ogg', 40, TRUE)
reagents.copy_to(broken_egg,reagents.total_volume)
var/obj/machinery/griddle/hit_griddle = target
hit_griddle.AddToGrill(broken_egg, user)
target.balloon_alert(user, "cracks [src] open")
interacting_with.balloon_alert(user, "cracks [src] open")
qdel(src)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
return ITEM_INTERACT_BLOCKING
/obj/item/food/egg/blue
icon_state = "egg-blue"
+5 -7
View File
@@ -117,13 +117,11 @@
return ..()
apply_buff(user)
/obj/item/food/canned/envirochow/afterattack(atom/target, mob/user, proximity_flag)
. = ..()
if(!proximity_flag)
return
if(!check_buffability(target))
return
apply_buff(target, user)
/obj/item/food/canned/envirochow/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!check_buffability(interacting_with))
return NONE
apply_buff(interacting_with, user)
return ITEM_INTERACT_SUCCESS
///This proc checks if the mob is able to receive the buff.
/obj/item/food/canned/envirochow/proc/check_buffability(mob/living/hungry_pet)
+4 -4
View File
@@ -263,8 +263,8 @@
qdel(src)
return TRUE //It hit the grenade, not them
/obj/item/grenade/afterattack(atom/target, mob/user)
. = ..()
/obj/item/grenade/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(active)
user.throw_item(target)
return . | AFTERATTACK_PROCESSED_ITEM
user.throw_item(interacting_with)
return ITEM_INTERACT_SUCCESS
return NONE
+40 -42
View File
@@ -105,58 +105,56 @@
det_time = newtime
to_chat(user, "Timer set for [det_time] seconds.")
/obj/item/grenade/c4/afterattack(atom/movable/bomb_target, mob/user, flag)
. = ..()
aim_dir = get_dir(user, bomb_target)
if(isdead(bomb_target))
return
if(!flag)
return
. |= AFTERATTACK_PROCESSED_ITEM
/obj/item/grenade/c4/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
// Here lies C4 ghosts. We hardly knew ye
if(isdead(interacting_with))
return NONE
aim_dir = get_dir(user, interacting_with)
return plant_c4(interacting_with, user) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING
/obj/item/grenade/c4/proc/plant_c4(atom/bomb_target, mob/living/user)
if(bomb_target != user && HAS_TRAIT(user, TRAIT_PACIFISM) && isliving(bomb_target))
to_chat(user, span_warning("You don't want to harm other living beings!"))
return .
return FALSE
to_chat(user, span_notice("You start planting [src]. The timer is set to [det_time]..."))
if(do_after(user, 3 SECONDS, target = bomb_target))
if(!user.temporarilyRemoveItemFromInventory(src))
return .
target = bomb_target
active = TRUE
if(!do_after(user, 3 SECONDS, target = bomb_target))
return FALSE
if(!user.temporarilyRemoveItemFromInventory(src))
return FALSE
target = bomb_target
active = TRUE
message_admins("[ADMIN_LOOKUPFLW(user)] planted [name] on [target.name] at [ADMIN_VERBOSEJMP(target)] with [det_time] second fuse")
user.log_message("planted [name] on [target.name] with a [det_time] second fuse.", LOG_ATTACK)
var/icon/target_icon = icon(bomb_target.icon, bomb_target.icon_state)
target_icon.Blend(icon(icon, icon_state), ICON_OVERLAY)
var/mutable_appearance/bomb_target_image = mutable_appearance(target_icon)
notify_ghosts(
"[user] has planted \a [src] on [target] with a [det_time] second fuse!",
source = bomb_target,
header = "Explosive Planted",
alert_overlay = bomb_target_image,
notify_flags = NOTIFY_CATEGORY_NOFLASH,
)
message_admins("[ADMIN_LOOKUPFLW(user)] planted [name] on [target.name] at [ADMIN_VERBOSEJMP(target)] with [det_time] second fuse")
user.log_message("planted [name] on [target.name] with a [det_time] second fuse.", LOG_ATTACK)
var/icon/target_icon = icon(bomb_target.icon, bomb_target.icon_state)
target_icon.Blend(icon(icon, icon_state), ICON_OVERLAY)
var/mutable_appearance/bomb_target_image = mutable_appearance(target_icon)
notify_ghosts(
"[user] has planted \a [src] on [target] with a [det_time] second fuse!",
source = bomb_target,
header = "Explosive Planted",
alert_overlay = bomb_target_image,
notify_flags = NOTIFY_CATEGORY_NOFLASH,
)
moveToNullspace() //Yep
moveToNullspace() //Yep
if(isitem(bomb_target)) //your crappy throwing star can't fly so good with a giant brick of c4 on it.
var/obj/item/thrown_weapon = bomb_target
thrown_weapon.throw_speed = max(1, (thrown_weapon.throw_speed - 3))
thrown_weapon.throw_range = max(1, (thrown_weapon.throw_range - 3))
if(thrown_weapon.embedding)
thrown_weapon.embedding["embed_chance"] = 0
thrown_weapon.updateEmbedding()
else if(isliving(bomb_target))
plastic_overlay.layer = FLOAT_LAYER
if(isitem(bomb_target)) //your crappy throwing star can't fly so good with a giant brick of c4 on it.
var/obj/item/thrown_weapon = bomb_target
thrown_weapon.throw_speed = max(1, (thrown_weapon.throw_speed - 3))
thrown_weapon.throw_range = max(1, (thrown_weapon.throw_range - 3))
if(thrown_weapon.embedding)
thrown_weapon.embedding["embed_chance"] = 0
thrown_weapon.updateEmbedding()
else if(isliving(bomb_target))
plastic_overlay.layer = FLOAT_LAYER
target.add_overlay(plastic_overlay)
to_chat(user, span_notice("You plant the bomb. Timer counting down from [det_time]."))
addtimer(CALLBACK(src, PROC_REF(detonate)), det_time*10)
return .
target.add_overlay(plastic_overlay)
to_chat(user, span_notice("You plant the bomb. Timer counting down from [det_time]."))
addtimer(CALLBACK(src, PROC_REF(detonate)), det_time*10)
return TRUE
/obj/item/grenade/c4/proc/shout_syndicate_crap(mob/player)
if(!player)
+5 -3
View File
@@ -475,9 +475,10 @@
/// TRUE if the user was aiming anywhere but the mouth when they offer the kiss, if it's offered
var/cheek_kiss
/obj/item/hand_item/kisser/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
. |= AFTERATTACK_PROCESSED_ITEM
/obj/item/hand_item/kisser/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return ranged_interact_with_atom(interacting_with, user, modifiers)
/obj/item/hand_item/kisser/ranged_interact_with_atom(atom/target, mob/living/user, list/modifiers)
if(HAS_TRAIT(user, TRAIT_GARLIC_BREATH))
kiss_type = /obj/projectile/kiss/french
@@ -495,6 +496,7 @@
blown_kiss.preparePixelProjectile(target, user)
blown_kiss.fire()
qdel(src)
return ITEM_INTERACT_SUCCESS
/obj/item/hand_item/kisser/on_offered(mob/living/carbon/offerer, mob/living/carbon/offered)
if(!(locate(/mob/living/carbon) in orange(1, offerer)))
+18 -22
View File
@@ -26,8 +26,8 @@
AddElement(/datum/element/openspace_item_click_handler)
RegisterSignal(src, COMSIG_OBJ_PAINTED, TYPE_PROC_REF(/obj/item/holosign_creator, on_color_change))
/obj/item/holosign_creator/handle_openspace_click(turf/target, mob/user, proximity_flag, click_parameters)
afterattack(target, user, proximity_flag, click_parameters)
/obj/item/holosign_creator/handle_openspace_click(turf/target, mob/user, click_parameters)
interact_with_atom(target, user, click_parameters)
/obj/item/holosign_creator/examine(mob/user)
. = ..()
@@ -35,39 +35,35 @@
return
. += span_notice("It is currently maintaining <b>[signs.len]/[max_signs]</b> projections.")
/obj/item/holosign_creator/afterattack(atom/target, mob/user, proximity_flag)
. = ..()
if(!proximity_flag)
return
. |= AFTERATTACK_PROCESSED_ITEM
if(!check_allowed_items(target, not_inside = TRUE))
return .
var/turf/target_turf = get_turf(target)
/obj/item/holosign_creator/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!check_allowed_items(interacting_with, not_inside = TRUE))
return NONE
var/turf/target_turf = get_turf(interacting_with)
var/obj/structure/holosign/target_holosign = locate(holosign_type) in target_turf
if(target_holosign)
qdel(target_holosign)
return .
return ITEM_INTERACT_BLOCKING
if(target_turf.is_blocked_turf(TRUE)) //can't put holograms on a tile that has dense stuff
return .
return ITEM_INTERACT_BLOCKING
if(holocreator_busy)
to_chat(user, span_notice("[src] is busy creating a hologram."))
return .
balloon_alert(user, "busy making a hologram!")
return ITEM_INTERACT_BLOCKING
if(LAZYLEN(signs) >= max_signs)
balloon_alert(user, "max capacity!")
return .
playsound(loc, 'sound/machines/click.ogg', 20, TRUE)
return ITEM_INTERACT_BLOCKING
playsound(src, 'sound/machines/click.ogg', 20, TRUE)
if(creation_time)
holocreator_busy = TRUE
if(!do_after(user, creation_time, target = target))
if(!do_after(user, creation_time, target = interacting_with))
holocreator_busy = FALSE
return .
return ITEM_INTERACT_BLOCKING
holocreator_busy = FALSE
if(LAZYLEN(signs) >= max_signs)
return .
return ITEM_INTERACT_BLOCKING
if(target_turf.is_blocked_turf(TRUE)) //don't try to sneak dense stuff on our tile during the wait.
return .
target_holosign = create_holosign(target, user)
return .
return ITEM_INTERACT_BLOCKING
target_holosign = create_holosign(interacting_with, user)
return ITEM_INTERACT_SUCCESS
/obj/item/holosign_creator/attack(mob/living/carbon/human/M, mob/user)
return
+5 -4
View File
@@ -95,11 +95,12 @@
if(active)
to_chat(user, span_userdanger("You have a really bad feeling about [src]!"))
/obj/item/hot_potato/afterattack(atom/target, mob/user, adjacent, params)
/obj/item/hot_potato/attack(mob/living/target_mob, mob/living/user, params)
. = ..()
if(!adjacent || !ismob(target))
return
force_onto(target, user)
if(.)
return .
return force_onto(target_mob, user)
/obj/item/hot_potato/proc/force_onto(mob/living/victim, mob/user)
if(!istype(victim) || user != loc || victim == user)
@@ -97,7 +97,7 @@
/obj/item/implantcase/chem/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/reagent_containers/syringe) && imp)
W.afterattack(imp, user, TRUE, params)
W.interact_with_atom(imp, user, params)
return TRUE
else
return ..()
+2 -3
View File
@@ -77,9 +77,8 @@
/// Bleed stacks applied when an organic mob target is hit
var/bleed_stacks_per_hit = 3
/obj/item/knife/bloodletter/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
if(!isliving(target) || !proximity_flag)
/obj/item/knife/bloodletter/afterattack(atom/target, mob/user, click_parameters)
if(!isliving(target))
return
var/mob/living/M = target
if(!(M.mob_biotypes & MOB_ORGANIC))
+9 -6
View File
@@ -73,19 +73,22 @@
remove_old_machine()
return CLICK_ACTION_SUCCESS
/obj/item/machine_remote/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
/obj/item/machine_remote/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return interact_with_atom(interacting_with, user, modifiers)
/obj/item/machine_remote/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!COOLDOWN_FINISHED(src, timeout_time))
playsound(src, 'sound/machines/synth_no.ogg', 30 , TRUE)
say("Remote control disabled temporarily. Please try again soon.")
return FALSE
if(!ismachinery(target) && !isbot(target))
return
return ITEM_INTERACT_BLOCKING
if(!ismachinery(interacting_with) && !isbot(interacting_with))
return NONE
if(moving_bug) //we have a bug in transit already, so let's kill it.
QDEL_NULL(moving_bug)
var/turf/spawning_turf = (controlling_machine_or_bot ? get_turf(controlling_machine_or_bot) : get_turf(src))
moving_bug = new(spawning_turf, src, target)
moving_bug = new(spawning_turf, src, interacting_with)
remove_old_machine()
return ITEM_INTERACT_SUCCESS
///Sets a controlled machine to a new machine, if possible. Checks if AIs can even control it.
/obj/item/machine_remote/proc/set_controlled_machine(obj/machinery/new_machine)
+32 -29
View File
@@ -191,10 +191,7 @@
final_block_chance = 0 //Don't bring a sword to a gunfight, and also you aren't going to really block someone full body tackling you with a sword
return ..()
/obj/item/melee/beesword/afterattack(atom/target, mob/user, proximity)
. = ..()
if(!proximity)
return
/obj/item/melee/beesword/afterattack(atom/target, mob/user, click_parameters)
if(iscarbon(target))
var/mob/living/carbon/carbon_target = target
carbon_target.reagents.add_reagent(/datum/reagent/toxin, 4)
@@ -242,20 +239,24 @@
if(!isspaceturf(turf))
consume_turf(turf)
/obj/item/melee/supermatter_sword/afterattack(target, mob/user, proximity_flag)
/obj/item/melee/supermatter_sword/pre_attack(atom/A, mob/living/user, params)
. = ..()
if(user && target == user)
user.dropItemToGround(src)
if(proximity_flag)
consume_everything(target)
return . | AFTERATTACK_PROCESSED_ITEM
if(.)
return .
if(A == user)
user.dropItemToGround(src, TRUE)
else
user.do_attack_animation(A)
consume_everything(A)
return TRUE
/obj/item/melee/supermatter_sword/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
..()
if(ismob(hit_atom))
var/mob/mob = hit_atom
if(src.loc == mob)
mob.dropItemToGround(src)
mob.dropItemToGround(src, TRUE)
consume_everything(hit_atom)
/obj/item/melee/supermatter_sword/pickup(user)
@@ -330,10 +331,7 @@
attack_verb_simple = list("flog", "whip", "lash", "discipline")
hitsound = 'sound/weapons/whip.ogg'
/obj/item/melee/curator_whip/attack(mob/living/target, mob/living/user, params)
. = ..()
if(.)
return
/obj/item/melee/curator_whip/afterattack(atom/target, mob/user, click_parameters)
if(ishuman(target))
var/mob/living/carbon/human/human_target = target
human_target.drop_all_held_items()
@@ -429,22 +427,27 @@
held_sausage = null
update_appearance()
/obj/item/melee/roastingstick/afterattack(atom/target, mob/user, proximity)
. = ..()
/obj/item/melee/roastingstick/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if (!HAS_TRAIT(src, TRAIT_TRANSFORM_ACTIVE))
return
if (!is_type_in_typecache(target, ovens))
return
if (istype(target, /obj/singularity) && get_dist(user, target) < 10)
to_chat(user, span_notice("You send [held_sausage] towards [target]."))
return NONE
if (!is_type_in_typecache(interacting_with, ovens))
return NONE
if (istype(interacting_with, /obj/singularity) && get_dist(user, interacting_with) < 10)
to_chat(user, span_notice("You send [held_sausage] towards [interacting_with]."))
playsound(src, 'sound/items/rped.ogg', 50, TRUE)
beam = user.Beam(target, icon_state = "rped_upgrade", time = 10 SECONDS)
else if (user.Adjacent(target))
to_chat(user, span_notice("You extend [src] towards [target]."))
playsound(src.loc, 'sound/weapons/batonextend.ogg', 50, TRUE)
else
return
finish_roasting(user, target)
beam = user.Beam(interacting_with, icon_state = "rped_upgrade", time = 10 SECONDS)
return ITEM_INTERACT_SUCCESS
return NONE
/obj/item/melee/roastingstick/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if (!HAS_TRAIT(src, TRAIT_TRANSFORM_ACTIVE))
return NONE
if (!is_type_in_typecache(interacting_with, ovens))
return NONE
to_chat(user, span_notice("You extend [src] towards [interacting_with]."))
playsound(src, 'sound/weapons/batonextend.ogg', 50, TRUE)
finish_roasting(user, interacting_with)
return ITEM_INTERACT_SUCCESS
/obj/item/melee/roastingstick/proc/finish_roasting(user, atom/target)
if(do_after(user, 10 SECONDS, target = user))
+5 -3
View File
@@ -46,11 +46,13 @@
///Checks whether or not we should clean.
/obj/item/mop/proc/should_clean(datum/cleaning_source, atom/atom_to_clean, mob/living/cleaner)
if(clean_blacklist[atom_to_clean.type])
return DO_NOT_CLEAN
return CLEAN_BLOCKED|CLEAN_DONT_BLOCK_INTERACTION
if(reagents.total_volume < 0.1)
cleaner.balloon_alert(cleaner, "mop is dry!")
return DO_NOT_CLEAN
return reagents.has_reagent(amount = 1, chemical_flags = REAGENT_CLEANS)
return CLEAN_BLOCKED
if(reagents.has_reagent(amount = 1, chemical_flags = REAGENT_CLEANS))
return CLEAN_ALLOWED
return CLEAN_BLOCKED|CLEAN_NO_XP
/**
* Applies reagents to the cleaned floor and removes them from the mop.
+15 -18
View File
@@ -112,17 +112,16 @@
return FALSE
return TRUE
/obj/item/paint/afterattack(atom/target, mob/user, proximity)
. = ..()
if(!proximity)
return
/obj/item/paint/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!isturf(interacting_with) || isspaceturf(interacting_with))
return NONE
if(paintleft <= 0)
return NONE
paintleft--
interacting_with.add_atom_colour(paint_color, WASHABLE_COLOUR_PRIORITY)
if(paintleft <= 0)
icon_state = "paint_empty"
return
if(!isturf(target) || isspaceturf(target))
return
paintleft--
target.add_atom_colour(paint_color, WASHABLE_COLOUR_PRIORITY)
return ITEM_INTERACT_SUCCESS
/obj/item/paint/paint_remover
gender = PLURAL
@@ -130,12 +129,10 @@
desc = "Used to remove color from anything."
icon_state = "paint_neutral"
/obj/item/paint/paint_remover/afterattack(atom/target, mob/user, proximity)
. = ..()
if(!proximity)
return
if(!isturf(target) || !isobj(target))
return
. |= AFTERATTACK_PROCESSED_ITEM
if(target.color != initial(target.color))
target.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
/obj/item/paint/paint_remover/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!isturf(interacting_with) || !isobj(interacting_with))
return NONE
if(interacting_with.color != initial(interacting_with.color))
interacting_with.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
return ITEM_INTERACT_SUCCESS
return NONE
+9 -8
View File
@@ -161,14 +161,15 @@
loadedWeightClass++
return TRUE
/obj/item/pneumatic_cannon/afterattack(atom/target, mob/living/user, flag, params)
. = ..()
if(flag && user.combat_mode)//melee attack
return
if(!istype(user))
return
Fire(user, target)
return AFTERATTACK_PROCESSED_ITEM
/obj/item/pneumatic_cannon/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(user.combat_mode)
return ITEM_INTERACT_SKIP_TO_ATTACK
Fire(user, interacting_with)
return ITEM_INTERACT_SUCCESS
/obj/item/pneumatic_cannon/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
Fire(user, interacting_with)
return ITEM_INTERACT_SUCCESS
/obj/item/pneumatic_cannon/proc/Fire(mob/living/user, atom/target)
if(!istype(user) && !target)
+15 -17
View File
@@ -389,29 +389,27 @@
. = ..()
ui_interact(user)
/obj/item/construction/rcd/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
//proximity check for normal rcd & range check for arcd
if((!proximity_flag && !ranged) || (ranged && !range_check(target, user)))
return FALSE
//do the work
/obj/item/construction/rcd/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
mode = construction_mode
rcd_create(target, user)
rcd_create(interacting_with, user)
return ITEM_INTERACT_SUCCESS
return . | AFTERATTACK_PROCESSED_ITEM
/obj/item/construction/rcd/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!ranged || !range_check(interacting_with, user))
return ITEM_INTERACT_BLOCKING
/obj/item/construction/rcd/afterattack_secondary(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
//proximity check for normal rcd & range check for arcd
if((!proximity_flag && !ranged) || (ranged && !range_check(target, user)))
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
return interact_with_atom(interacting_with, user, modifiers)
//do the work
/obj/item/construction/rcd/interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
mode = RCD_DECONSTRUCT
rcd_create(target, user)
rcd_create(interacting_with, user)
return ITEM_INTERACT_SUCCESS
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
/obj/item/construction/rcd/ranged_interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
if(!ranged || !range_check(interacting_with, user))
return ITEM_INTERACT_BLOCKING
return interact_with_atom_secondary(interacting_with, user, modifiers)
/obj/item/construction/rcd/proc/detonate_pulse()
audible_message("<span class='danger'><b>[src] begins to vibrate and \
+40 -47
View File
@@ -88,61 +88,56 @@
else
toggle_silo(user)
/obj/item/construction/rld/afterattack(atom/A, mob/user)
. = ..()
if(!range_check(A,user))
return
/obj/item/construction/rld/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!range_check(interacting_with, user))
return NONE
return interact_with_atom(interacting_with, user, modifiers)
/obj/item/construction/rld/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
var/turf/start = get_turf(src)
switch(mode)
if(REMOVE_MODE)
if(!istype(A, /obj/machinery/light/))
return FALSE
if(!istype(interacting_with, /obj/machinery/light))
return NONE
//resource sanity checks before & after delay
if(!checkResource(DECONSTRUCT_COST, user))
return FALSE
var/beam = user.Beam(A,icon_state="light_beam", time = 15)
playsound(loc, 'sound/machines/click.ogg', 50, TRUE)
if(!do_after(user, REMOVE_DELAY, target = A))
return ITEM_INTERACT_BLOCKING
var/beam = user.Beam(interacting_with, icon_state="light_beam", time = 15)
playsound(src, 'sound/machines/click.ogg', 50, TRUE)
if(!do_after(user, REMOVE_DELAY, target = interacting_with))
qdel(beam)
return FALSE
return ITEM_INTERACT_BLOCKING
if(!checkResource(DECONSTRUCT_COST, user))
return FALSE
return ITEM_INTERACT_BLOCKING
if(!useResource(DECONSTRUCT_COST, user))
return FALSE
return ITEM_INTERACT_BLOCKING
activate()
qdel(A)
return TRUE
qdel(interacting_with)
return ITEM_INTERACT_SUCCESS
if(LIGHT_MODE)
//resource sanity checks before & after delay
var/cost = iswallturf(A) ? LIGHT_TUBE_COST : FLOOR_LIGHT_COST
var/cost = iswallturf(interacting_with) ? LIGHT_TUBE_COST : FLOOR_LIGHT_COST
if(!checkResource(cost, user))
return FALSE
var/beam = user.Beam(A,icon_state="light_beam", time = BUILD_DELAY)
return ITEM_INTERACT_BLOCKING
var/beam = user.Beam(interacting_with, icon_state="light_beam", time = BUILD_DELAY)
playsound(loc, 'sound/machines/click.ogg', 50, TRUE)
playsound(loc, 'sound/effects/light_flicker.ogg', 50, FALSE)
if(!do_after(user, BUILD_DELAY, target = A))
if(!do_after(user, BUILD_DELAY, target = interacting_with))
qdel(beam)
return FALSE
return ITEM_INTERACT_BLOCKING
if(!checkResource(cost, user))
return FALSE
return ITEM_INTERACT_BLOCKING
if(iswallturf(A))
if(iswallturf(interacting_with))
var/turf/open/winner = null
var/winning_dist = null
var/skip = FALSE
for(var/direction in GLOB.cardinals)
var/turf/C = get_step(A, direction)
var/turf/C = get_step(interacting_with, direction)
//turf already has a light
skip = FALSE
for(var/obj/machinery/light/dupe in C)
if(istype(dupe, /obj/machinery/light))
skip = TRUE
break
if(skip)
if(locate(/obj/machinery/light) in C)
continue
//can't put a light here
if(!(isspaceturf(C) || TURF_SHARES(C)))
@@ -159,43 +154,41 @@
winning_dist = contender
if(!winner)
balloon_alert(user, "no valid target!")
return FALSE
return ITEM_INTERACT_BLOCKING
if(!useResource(cost, user))
return FALSE
return ITEM_INTERACT_BLOCKING
activate()
var/obj/machinery/light/L = new /obj/machinery/light(get_turf(winner))
L.setDir(get_dir(winner, A))
L.setDir(get_dir(winner, interacting_with))
L.color = color_choice
L.set_light_color(color_choice)
return TRUE
if(isfloorturf(A))
var/turf/target = get_turf(A)
for(var/obj/machinery/light/floor/dupe in target)
if(istype(dupe))
return FALSE
return ITEM_INTERACT_SUCCESS
if(isfloorturf(interacting_with))
var/turf/target = get_turf(interacting_with)
if(locate(/obj/machinery/light/floor) in target)
return ITEM_INTERACT_BLOCKING
if(!useResource(cost, user))
return FALSE
return ITEM_INTERACT_BLOCKING
activate()
var/obj/machinery/light/floor/FL = new /obj/machinery/light/floor(target)
FL.color = color_choice
FL.set_light_color(color_choice)
return TRUE
return ITEM_INTERACT_SUCCESS
if(GLOW_MODE)
if(!useResource(GLOW_STICK_COST, user))
return FALSE
return ITEM_INTERACT_BLOCKING
activate()
var/obj/item/flashlight/glowstick/new_stick = new /obj/item/flashlight/glowstick(start)
new_stick.color = color_choice
new_stick.set_light_color(new_stick.color)
new_stick.throw_at(A, 9, 3, user)
new_stick.throw_at(interacting_with, 9, 3, user)
new_stick.turn_on()
new_stick.update_brightness()
return ITEM_INTERACT_SUCCESS
return TRUE
return NONE
/obj/item/construction/rld/mini
name = "mini-rapid-light-device"
+11 -10
View File
@@ -240,31 +240,32 @@
if(duct_machine.duct_layer & layer_id)
return FALSE
/obj/item/construction/plumbing/interact_with_atom(atom/target, mob/living/user, list/modifiers)
. = NONE
/obj/item/construction/plumbing/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
for(var/category_name in plumbing_design_types)
var/list/designs = plumbing_design_types[category_name]
for(var/obj/machinery/recipe as anything in designs)
if(target.type != recipe)
if(interacting_with.type != recipe)
continue
var/obj/machinery/machine_target = target
var/obj/machinery/machine_target = interacting_with
if(machine_target.anchored)
balloon_alert(user, "unanchor first!")
return ITEM_INTERACT_BLOCKING
if(do_after(user, 2 SECONDS, target = target))
if(do_after(user, 2 SECONDS, target = interacting_with))
machine_target.deconstruct() //Let's not substract matter
playsound(get_turf(src), 'sound/machines/click.ogg', 50, TRUE) //this is just such a great sound effect
playsound(src, 'sound/machines/click.ogg', 50, TRUE) //this is just such a great sound effect
return ITEM_INTERACT_SUCCESS
if(create_machine(target, user))
if(!isopenturf(interacting_with))
return NONE
if(create_machine(interacting_with, user))
return ITEM_INTERACT_SUCCESS
return ITEM_INTERACT_BLOCKING
/obj/item/construction/plumbing/interact_with_atom_secondary(atom/target, mob/living/user, list/modifiers)
. = NONE
if(!istype(target, /obj/machinery/duct))
return ITEM_INTERACT_BLOCKING
return NONE
var/obj/machinery/duct/duct = target
if(duct.duct_layer && duct.duct_color)
@@ -272,6 +273,7 @@
current_layer = GLOB.plumbing_layer_names["[duct.duct_layer]"]
balloon_alert(user, "using [current_color], layer [current_layer]")
return ITEM_INTERACT_SUCCESS
return ITEM_INTERACT_BLOCKING
/obj/item/construction/plumbing/click_alt(mob/user)
ui_interact(user)
@@ -374,4 +376,3 @@
plumbing_design_types = service_design_types
. = ..()
+8 -14
View File
@@ -125,21 +125,18 @@ RSF
return FALSE
return TRUE
/obj/item/rsf/afterattack(atom/A, mob/user, proximity)
/obj/item/rsf/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(cooldown > world.time)
return
. = ..()
if(!proximity)
return .
. |= AFTERATTACK_PROCESSED_ITEM
if (!is_allowed(A))
return .
return NONE
if (!is_allowed(interacting_with))
return NONE
if(use_matter(dispense_cost, user))//If we can charge that amount of charge, we do so and return true
playsound(loc, 'sound/machines/click.ogg', 10, TRUE)
var/atom/meme = new to_dispense(get_turf(A))
var/atom/meme = new to_dispense(get_turf(interacting_with))
to_chat(user, span_notice("[action_type] [meme.name]..."))
cooldown = world.time + cooldowndelay
return .
return ITEM_INTERACT_SUCCESS
return ITEM_INTERACT_BLOCKING
///A helper proc. checks to see if we can afford the amount of charge that is passed, and if we can docs the charge from our base, and returns TRUE. If we can't we return FALSE
/obj/item/rsf/proc/use_matter(charge, mob/user)
@@ -163,10 +160,7 @@ RSF
///Helper proc that iterates through all the things we are allowed to spawn on, and sees if the passed atom is one of them
/obj/item/rsf/proc/is_allowed(atom/to_check)
for(var/sort in allowed_surfaces)
if(istype(to_check, sort))
return TRUE
return FALSE
return is_type_in_list(to_check, allowed_surfaces)
/obj/item/rsf/cookiesynth
name = "Cookie Synthesizer"
+34 -23
View File
@@ -227,10 +227,16 @@
return TRUE
/obj/item/construction/rtd/afterattack(turf/open/floor/floor, mob/user)
. = ..()
if(!istype(floor) || !range_check(floor,user))
return TRUE
/obj/item/construction/rtd/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!range_check(interacting_with, user))
return NONE
return interact_with_atom(interacting_with, user, modifiers)
/obj/item/construction/rtd/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
var/turf/open/floor/floor = interacting_with
if(!istype(floor))
return NONE
var/floor_designs = GLOB.floor_designs
if(!istype(floor, /turf/open/floor/plating)) //we infer what floor type it is if its not the usual plating
@@ -259,11 +265,11 @@
selected_design.set_direction(floor.dir)
balloon_alert(user, "tile changed to [selected_design.name]")
return TRUE
return ITEM_INTERACT_SUCCESS
//can't infer floor type!
balloon_alert(user, "design not supported!")
return TRUE
return ITEM_INTERACT_BLOCKING
var/delay = CONSTRUCTION_TIME(selected_design.cost)
var/obj/effect/constructing_effect/rcd_effect = new(floor, delay, RCD_TURF)
@@ -271,27 +277,27 @@
//resource sanity check before & after delay along with special effects
if(!checkResource(selected_design.cost, user))
qdel(rcd_effect)
return TRUE
return ITEM_INTERACT_BLOCKING
var/beam = user.Beam(floor, icon_state = "light_beam", time = delay)
playsound(loc, 'sound/effects/light_flicker.ogg', 50, FALSE)
if(!do_after(user, delay, target = floor))
qdel(beam)
qdel(rcd_effect)
return TRUE
return ITEM_INTERACT_BLOCKING
if(!checkResource(selected_design.cost, user))
qdel(rcd_effect)
return TRUE
return ITEM_INTERACT_BLOCKING
if(!useResource(selected_design.cost, user))
qdel(rcd_effect)
return TRUE
return ITEM_INTERACT_BLOCKING
activate()
//step 1 create tile
var/obj/item/stack/tile/final_tile = selected_design.new_tile(user.drop_location())
if(QDELETED(final_tile)) //if you were standing on a stack of tiles this newly spawned tile could get merged with it cause its spawned on your location
qdel(rcd_effect)
balloon_alert(user, "tile got merged with the stack beneath you!")
return TRUE
return ITEM_INTERACT_SUCCESS
//step 2 lay tile
var/turf/open/new_turf = final_tile.place_tile(floor, user)
if(new_turf) //apply infered overlays
@@ -299,16 +305,21 @@
info.add_decal(new_turf)
rcd_effect.end_animation()
return TRUE
return ITEM_INTERACT_SUCCESS
/obj/item/construction/rtd/afterattack_secondary(turf/open/floor/floor, mob/user, proximity_flag, click_parameters)
..()
if(!istype(floor) || !range_check(floor,user))
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
/obj/item/construction/rtd/ranged_interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
if(!range_check(interacting_with, user))
return NONE
return interact_with_atom_secondary(interacting_with, user, modifiers)
/obj/item/construction/rtd/interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers)
var/turf/open/floor/floor = interacting_with
if(!istype(floor))
return NONE
if(istype(floor, /turf/open/floor/plating)) //cant deconstruct normal plating thats the RCD's job
balloon_alert(user, "nothing to deconstruct!")
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
return ITEM_INTERACT_BLOCKING
var/floor_designs = GLOB.floor_designs
@@ -327,7 +338,7 @@
break
if(!cost)
balloon_alert(user, "can't deconstruct this type!")
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
return ITEM_INTERACT_BLOCKING
var/delay = DECONSTRUCTION_TIME(cost)
var/obj/effect/constructing_effect/rcd_effect = new(floor, delay, RCD_DECONSTRUCT)
@@ -335,21 +346,21 @@
//resource sanity check before & after delay along with beam effects
if(!checkResource(cost * 0.7, user)) //no ballon alert for checkResource as it already spans an alert to chat
qdel(rcd_effect)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
return ITEM_INTERACT_BLOCKING
var/beam = user.Beam(floor, icon_state = "light_beam", time = delay)
playsound(loc, 'sound/effects/light_flicker.ogg', 50, FALSE)
if(!do_after(user, delay, target = floor))
qdel(beam)
qdel(rcd_effect)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
return ITEM_INTERACT_BLOCKING
if(!checkResource(cost * 0.7, user))
qdel(rcd_effect)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
return ITEM_INTERACT_BLOCKING
//do the tiling
if(!useResource(cost * 0.7, user))
qdel(rcd_effect)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
return ITEM_INTERACT_BLOCKING
activate()
//find & collect all decals
var/list/all_decals = list()
@@ -365,7 +376,7 @@
floor.ScrapeAway(flags = CHANGETURF_INHERIT_AIR)
rcd_effect.end_animation()
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
return ITEM_INTERACT_SUCCESS
/obj/item/construction/rtd/loaded
matter = 350
+9 -6
View File
@@ -343,15 +343,18 @@
var/staffcooldown = 0
var/staffwait = 30
/obj/item/godstaff/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
/obj/item/godstaff/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return interact_with_atom(interacting_with, user, modifiers)
/obj/item/godstaff/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(staffcooldown + staffwait > world.time)
return
. |= AFTERATTACK_PROCESSED_ITEM
return ITEM_INTERACT_BLOCKING
user.visible_message(span_notice("[user] chants deeply and waves [user.p_their()] staff!"))
if(do_after(user, 2 SECONDS, src))
target.add_atom_colour(conversion_color, WASHABLE_COLOUR_PRIORITY) //wololo
if(do_after(user, 2 SECONDS, interacting_with))
interacting_with.add_atom_colour(conversion_color, WASHABLE_COLOUR_PRIORITY) //wololo
staffcooldown = world.time
return ITEM_INTERACT_SUCCESS
/obj/item/godstaff/red
icon_state = "godstaff-red"
+27 -11
View File
@@ -117,23 +117,39 @@
user.visible_message(span_warning("[user] shoots a high-velocity gumball at [target]!"))
check_amount()
/obj/item/borg/lollipop/afterattack(atom/target, mob/living/user, proximity, click_params)
/obj/item/borg/lollipop/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
check_amount()
if(iscyborg(user))
var/mob/living/silicon/robot/robot_user = user
if(!robot_user.cell.use(0.012 * STANDARD_CELL_CHARGE))
if(!robot_user.cell?.use(0.012 * STANDARD_CELL_CHARGE))
to_chat(user, span_warning("Not enough power."))
return AFTERATTACK_PROCESSED_ITEM
return ITEM_INTERACT_BLOCKING
switch(mode)
if(THROW_LOLLIPOP_MODE)
shootL(interacting_with, user, list2params(modifiers))
return ITEM_INTERACT_SUCCESS
if(THROW_GUMBALL_MODE)
shootG(interacting_with, user, list2params(modifiers))
return ITEM_INTERACT_SUCCESS
return NONE
/obj/item/borg/lollipop/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
check_amount()
if(iscyborg(user))
var/mob/living/silicon/robot/robot_user = user
if(!robot_user.cell?.use(0.012 * STANDARD_CELL_CHARGE))
to_chat(user, span_warning("Not enough power."))
return ITEM_INTERACT_BLOCKING
switch(mode)
if(DISPENSE_LOLLIPOP_MODE, DISPENSE_ICECREAM_MODE)
if(!proximity)
return AFTERATTACK_PROCESSED_ITEM
dispense(target, user)
if(THROW_LOLLIPOP_MODE)
shootL(target, user, click_params)
if(THROW_GUMBALL_MODE)
shootG(target, user, click_params)
return ..() | AFTERATTACK_PROCESSED_ITEM
dispense(interacting_with, user)
return ITEM_INTERACT_SUCCESS
return NONE
/obj/item/borg/lollipop/attack_self(mob/living/user)
switch(mode)
@@ -234,11 +234,11 @@
to_chat(user, span_notice("You toggle [src] to \"[mode]\" mode."))
update_appearance()
/obj/item/borg/charger/afterattack(obj/item/target, mob/living/silicon/robot/user, proximity_flag)
. = ..()
if(!proximity_flag || !iscyborg(user))
return
. |= AFTERATTACK_PROCESSED_ITEM
/obj/item/borg/charger/interact_with_atom(atom/target, mob/living/silicon/robot/user, list/modifiers)
if(!iscyborg(user))
return NONE
. = ITEM_INTERACT_BLOCKING
if(mode == "draw")
if(is_type_in_list(target, charge_machines))
var/obj/machinery/target_machine = target
+29 -35
View File
@@ -358,31 +358,29 @@
/obj/item/reagent_containers/borghypo/borgshaker/attack(mob/M, mob/user)
return //Can't inject stuff with a shaker, can we? //not with that attitude
/obj/item/reagent_containers/borghypo/borgshaker/afterattack(obj/target, mob/user, proximity)
. = ..()
if(!proximity)
return .
/obj/item/reagent_containers/borghypo/borgshaker/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!interacting_with.is_refillable())
return NONE
if(!selected_reagent)
balloon_alert(user, "no reagent selected!")
return .
. |= AFTERATTACK_PROCESSED_ITEM
if(target.is_refillable())
if(!stored_reagents.has_reagent(selected_reagent.type, amount_per_transfer_from_this))
balloon_alert(user, "not enough [selected_reagent.name]!")
return .
if(target.reagents.total_volume >= target.reagents.maximum_volume)
balloon_alert(user, "[target] is full!")
return .
return ITEM_INTERACT_BLOCKING
if(!stored_reagents.has_reagent(selected_reagent.type, amount_per_transfer_from_this))
balloon_alert(user, "not enough [selected_reagent.name]!")
return ITEM_INTERACT_BLOCKING
if(interacting_with.reagents.total_volume >= interacting_with.reagents.maximum_volume)
balloon_alert(user, "it's full!")
return ITEM_INTERACT_BLOCKING
// This is the in-between where we're storing the reagent we're going to pour into the container
// because we cannot specify a singular reagent to transfer in trans_to
var/datum/reagents/shaker = new()
stored_reagents.remove_reagent(selected_reagent.type, amount_per_transfer_from_this)
shaker.add_reagent(selected_reagent.type, amount_per_transfer_from_this, reagtemp = dispensed_temperature, no_react = TRUE)
// This is the in-between where we're storing the reagent we're going to pour into the container
// because we cannot specify a singular reagent to transfer in trans_to
var/datum/reagents/shaker = new()
stored_reagents.remove_reagent(selected_reagent.type, amount_per_transfer_from_this)
shaker.add_reagent(selected_reagent.type, amount_per_transfer_from_this, reagtemp = dispensed_temperature, no_react = TRUE)
shaker.trans_to(interacting_with, amount_per_transfer_from_this, transferred_by = user)
balloon_alert(user, "[amount_per_transfer_from_this] unit\s poured")
return ITEM_INTERACT_SUCCESS
shaker.trans_to(target, amount_per_transfer_from_this, transferred_by = user)
balloon_alert(user, "[amount_per_transfer_from_this] unit\s poured")
return .
/obj/item/reagent_containers/borghypo/condiment_synthesizer // Solids! Condiments! The borger uprising!
name = "Condiment Synthesizer"
@@ -423,30 +421,26 @@
/obj/item/reagent_containers/borghypo/condiment_synthesizer/attack(mob/M, mob/user)
return
/obj/item/reagent_containers/borghypo/condiment_synthesizer/afterattack(obj/target, mob/user, proximity)
. = ..()
if(!proximity)
return .
/obj/item/reagent_containers/borghypo/condiment_synthesizer/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(!interacting_with.is_refillable())
return NONE
if(!selected_reagent)
balloon_alert(user, "no reagent selected!")
return .
. |= AFTERATTACK_PROCESSED_ITEM
if(!target.is_refillable())
return .
return ITEM_INTERACT_BLOCKING
if(!stored_reagents.has_reagent(selected_reagent.type, amount_per_transfer_from_this))
balloon_alert(user, "not enough [selected_reagent.name]!")
return .
if(target.reagents.total_volume >= target.reagents.maximum_volume)
balloon_alert(user, "[target] is full!")
return .
return ITEM_INTERACT_BLOCKING
if(interacting_with.reagents.total_volume >= interacting_with.reagents.maximum_volume)
balloon_alert(user, "it's full!")
return ITEM_INTERACT_BLOCKING
// This is the in-between where we're storing the reagent we're going to pour into the container
// because we cannot specify a singular reagent to transfer in trans_to
var/datum/reagents/shaker = new()
stored_reagents.remove_reagent(selected_reagent.type, amount_per_transfer_from_this)
shaker.add_reagent(selected_reagent.type, amount_per_transfer_from_this, reagtemp = dispensed_temperature, no_react = TRUE)
shaker.trans_to(target, amount_per_transfer_from_this, transferred_by = user)
shaker.trans_to(interacting_with, amount_per_transfer_from_this, transferred_by = user)
balloon_alert(user, "[amount_per_transfer_from_this] unit\s poured")
return ITEM_INTERACT_SUCCESS
/obj/item/reagent_containers/borghypo/borgshaker/hacked
name = "cyborg shaker"
+8 -7
View File
@@ -26,13 +26,14 @@
user.visible_message(span_notice("[user] collects [src]."), balloon_alert(user, "you collect the [src]."))
return TRUE
/obj/item/rolling_table_dock/afterattack(obj/target, mob/user , proximity)
. = ..()
var/turf/target_turf = get_turf(target)
if(!proximity || target_turf.is_blocked_turf(TRUE) || locate(/mob/living) in target_turf)
return
if(isopenturf(target))
deploy_rolling_table(user, target)
/obj/item/rolling_table_dock/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
var/turf/target_turf = get_turf(interacting_with)
if(target_turf.is_blocked_turf(TRUE) || (locate(/mob/living) in target_turf))
return NONE
if(isopenturf(interacting_with))
deploy_rolling_table(user, interacting_with)
return ITEM_INTERACT_SUCCESS
return NONE
/obj/item/rolling_table_dock/proc/deploy_rolling_table(mob/user, atom/location)
var/obj/structure/table/rolling/rable = new /obj/structure/table/rolling(location)
+21 -26
View File
@@ -167,30 +167,27 @@
return CLICK_ACTION_SUCCESS
/obj/item/spear/explosive/afterattack(atom/movable/AM, mob/user, proximity)
. = ..()
if(!proximity || !HAS_TRAIT(src, TRAIT_WIELDED) || !istype(AM))
/obj/item/spear/explosive/afterattack(atom/movable/target, mob/user, click_parameters)
if(!HAS_TRAIT(src, TRAIT_WIELDED) || !istype(target))
return
. |= AFTERATTACK_PROCESSED_ITEM
if(AM.resistance_flags & INDESTRUCTIBLE) //due to the lich incident of 2021, embedding grenades inside of indestructible structures is forbidden
return .
if(ismob(AM))
var/mob/mob_target = AM
if(target.resistance_flags & INDESTRUCTIBLE) //due to the lich incident of 2021, embedding grenades inside of indestructible structures is forbidden
return
if(ismob(target))
var/mob/mob_target = target
if(mob_target.status_flags & GODMODE) //no embedding grenade phylacteries inside of ghost poly either
return .
if(iseffect(AM)) //and no accidentally wasting your moment of glory on graffiti
return .
return
if(iseffect(target)) //and no accidentally wasting your moment of glory on graffiti
return
user.say("[war_cry]", forced="spear warcry")
if(isliving(user))
var/mob/living/living_user = user
living_user.set_resting(new_resting = TRUE, silent = TRUE, instant = TRUE)
living_user.Move(get_turf(AM))
living_user.Move(get_turf(target))
explosive.forceMove(get_turf(living_user))
explosive.detonate(lanced_by=user)
if(!QDELETED(living_user))
living_user.set_resting(new_resting = FALSE, silent = TRUE, instant = TRUE)
qdel(src)
return .
//GREY TIDE
/obj/item/spear/grey_tide
@@ -201,20 +198,18 @@
force_unwielded = 15
force_wielded = 25
/obj/item/spear/grey_tide/afterattack(atom/movable/AM, mob/living/user, proximity)
. = ..()
if(!proximity)
return
/obj/item/spear/grey_tide/afterattack(atom/movable/target, mob/living/user, click_parameters)
user.faction |= "greytide([REF(user)])"
if(isliving(AM))
var/mob/living/L = AM
if(istype (L, /mob/living/simple_animal/hostile/illusion))
return
if(!L.stat && prob(50))
var/mob/living/simple_animal/hostile/illusion/M = new(user.loc)
M.faction = user.faction.Copy()
M.Copy_Parent(user, 100, user.health/2.5, 12, 30)
M.GiveTarget(L)
if(!isliving(target))
return
var/mob/living/stabbed = target
if(istype(stabbed, /mob/living/simple_animal/hostile/illusion))
return
if(stabbed.stat == CONSCIOUS && prob(50))
var/mob/living/simple_animal/hostile/illusion/fake_clone = new(user.loc)
fake_clone.faction = user.faction.Copy()
fake_clone.Copy_Parent(user, 100, user.health/2.5, 12, 30)
fake_clone.GiveTarget(stabbed)
//MILITARY
/obj/item/spear/military
@@ -26,20 +26,23 @@
held_gibtonite.forceMove(src)
addtimer(CALLBACK(src, PROC_REF(release_gibtonite)), GIBTONITE_GOLEM_HOLD_TIME, TIMER_DELETE_ME)
/obj/item/gibtonite_hand/afterattack(atom/target, mob/living/user, flag, params)
. = ..()
/obj/item/gibtonite_hand/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return ranged_interact_with_atom(interacting_with, user, modifiers)
/obj/item/gibtonite_hand/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if (!held_gibtonite)
to_chat(user, span_warning("[src] fizzles, it was a dud!"))
qdel(src)
return TRUE | AFTERATTACK_PROCESSED_ITEM
return ITEM_INTERACT_BLOCKING
playsound(src, 'sound/weapons/sonic_jackhammer.ogg', 50, TRUE)
held_gibtonite.forceMove(get_turf(src))
held_gibtonite.det_time = 2 SECONDS
held_gibtonite.GibtoniteReaction(user, "A [src] has targeted [target] with a thrown and primed")
held_gibtonite.throw_at(target, range = 10, speed = 3, thrower = user)
held_gibtonite.GibtoniteReaction(user, "A [src] has targeted [interacting_with] with a thrown and primed")
held_gibtonite.throw_at(interacting_with, range = 10, speed = 3, thrower = user)
held_gibtonite = null
qdel(src)
return TRUE | AFTERATTACK_PROCESSED_ITEM
return ITEM_INTERACT_SUCCESS
/// Called when you can't hold it in any longer and just drop it on the ground
/obj/item/gibtonite_hand/proc/release_gibtonite()
@@ -69,15 +72,17 @@
/// How accurate are you?
var/teleport_vary = 2
/obj/item/bluespace_finger/afterattack(atom/target, mob/living/user, flag, params)
. = ..()
var/turf/target_turf = get_turf(target)
/obj/item/bluespace_finger/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
return ranged_interact_with_atom(interacting_with, user, modifiers)
/obj/item/bluespace_finger/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
var/turf/target_turf = get_turf(interacting_with)
if (get_dist(target_turf, get_turf(src)) > teleport_range)
balloon_alert(user, "too far!")
return TRUE | AFTERATTACK_PROCESSED_ITEM
return ITEM_INTERACT_BLOCKING
if (target_turf.is_blocked_turf(exclude_mobs = TRUE))
balloon_alert(user, "no room!")
return TRUE | AFTERATTACK_PROCESSED_ITEM
return ITEM_INTERACT_BLOCKING
var/obj/effect/temp_visual/teleport_golem/landing_indicator = new(target_turf)
user.add_filter(BLUESPACE_GLOW_FILTER, 2, list("type" = "outline", "color" = COLOR_BRIGHT_BLUE, "alpha" = 0, "size" = 1))
@@ -89,7 +94,7 @@
qdel(landing_indicator)
user.remove_filter(BLUESPACE_GLOW_FILTER)
if (!did_teleport)
return
return ITEM_INTERACT_BLOCKING
var/list/valid_landing_tiles = list(target_turf)
for (var/turf/potential_landing in oview(teleport_vary, target_turf))
@@ -101,6 +106,7 @@
telefrag.Knockdown(2 SECONDS)
do_teleport(user, final_destination, asoundin = 'sound/effects/phasein.ogg', no_effects = TRUE)
qdel(src)
return ITEM_INTERACT_SUCCESS
#undef GIBTONITE_GOLEM_HOLD_TIME
#undef BLUESPACE_GLOW_FILTER
+2 -3
View File
@@ -63,9 +63,8 @@ GLOBAL_LIST_INIT(rod_recipes, list ( \
slapcraft_recipes = slapcraft_recipe_list,\
)
/obj/item/stack/rods/handle_openspace_click(turf/target, mob/user, proximity_flag, click_parameters)
if(proximity_flag)
target.attackby(src, user, click_parameters)
/obj/item/stack/rods/handle_openspace_click(turf/target, mob/user, click_parameters)
target.attackby(src, user, click_parameters)
/obj/item/stack/rods/get_main_recipes()
. = ..()
+8 -12
View File
@@ -341,20 +341,16 @@ GLOBAL_LIST_INIT(plastitaniumglass_recipes, list(
if(T && is_station_level(T.z))
SSblackbox.record_feedback("tally", "station_mess_destroyed", 1, name)
/obj/item/shard/afterattack(atom/A as mob|obj, mob/user, proximity)
. = ..()
if(!proximity || !(src in user))
/obj/item/shard/afterattack(atom/target, mob/user, click_parameters)
if(!iscarbon(user) || !user.is_holding(src))
return
if(isturf(A))
var/mob/living/carbon/jab = user
if(jab.get_all_covered_flags() & HANDS)
return
if(istype(A, /obj/item/storage))
return
var/hit_hand = ((user.active_hand_index % 2 == 0) ? "r_" : "l_") + "arm"
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(!H.gloves && !HAS_TRAIT(H, TRAIT_PIERCEIMMUNE)) // golems, etc
to_chat(H, span_warning("[src] cuts into your hand!"))
H.apply_damage(force*0.5, BRUTE, hit_hand, attacking_item = src)
to_chat(user, span_warning("[src] cuts into your hand!"))
jab.apply_damage(force * 0.5, BRUTE, user.get_active_hand(), attacking_item = src)
/obj/item/shard/attackby(obj/item/item, mob/user, params)
if(istype(item, /obj/item/lightreplacer))

Some files were not shown because too many files have changed in this diff Show More