mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-20 12:35:33 +01:00
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)  - 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:  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:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
))
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
. = ..()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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...")
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
. = ..()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)."
|
||||
|
||||
|
||||
@@ -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)]")
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ..()
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
. = ..()
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
. = ..()
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user