diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_x_act.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_x_act.dm index a33c4951384..46e179ee567 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_x_act.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_x_act.dm @@ -89,11 +89,6 @@ /// 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) - /// from /obj/projectile/energy/fisher/on_hit() or /obj/item/gun/energy/recharge/fisher when striking a target #define COMSIG_ATOM_SABOTEUR_ACT "hit_by_saboteur" #define COMSIG_SABOTEUR_SUCCESS 1 diff --git a/code/__DEFINES/tools.dm b/code/__DEFINES/tools.dm index 2348bd49f19..b0812746cb8 100644 --- a/code/__DEFINES/tools.dm +++ b/code/__DEFINES/tools.dm @@ -39,3 +39,9 @@ /// Combination flag for any item interaction that blocks the rest of the attack chain #define ITEM_INTERACT_ANY_BLOCKER (ITEM_INTERACT_SUCCESS | ITEM_INTERACT_BLOCKING) + +/** + * A helper for checking if an item interaction should be skipped. + * This is only used explicitly because some interactions may not want to ever be skipped. + */ +#define SHOULD_SKIP_INTERACTION(target, item, user) (HAS_TRAIT(target, TRAIT_COMBAT_MODE_SKIP_INTERACTION) && user.combat_mode) diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 39547eac6ac..7cc8085888b 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -1278,6 +1278,19 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai ///Trait which allows mobs to parry mining mob projectiles #define TRAIT_MINING_PARRYING "mining_parrying" +/** + * + * This trait is used in some interactions very high in the interaction chain to allow + * certain atoms to be skipped by said interactions if the user is in combat mode. + * + * Its primarily use case is for stuff like storage and tables, to allow things like emags to be bagged + * (because in some contexts you might want to be emagging a bag, and in others you might want to be storing it.) + * + * This is only checked by certain items explicitly so you can't just add the trait and expect it to work. + * (This may be changed later but I chose to do it this way to avoid messing up interactions which require combat mode) + */ +#define TRAIT_COMBAT_MODE_SKIP_INTERACTION "combat_mode_skip_interaction" + ///A "fake" effect that should not be subject to normal effect removal methods (like the effect remover component) #define TRAIT_ILLUSORY_EFFECT "illusory_effect" diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index ba3491dc44b..1a0fc110722 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -37,6 +37,8 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_BLOCKING_EXPLOSIVES" = TRAIT_BLOCKING_EXPLOSIVES, "TRAIT_BOULDER_BREAKER" = TRAIT_BOULDER_BREAKER, "TRAIT_CASTABLE_LOC" = TRAIT_CASTABLE_LOC, + "TRAIT_CHASM_STOPPER" = TRAIT_CHASM_STOPPER, + "TRAIT_COMBAT_MODE_SKIP_INTERACTION" = TRAIT_COMBAT_MODE_SKIP_INTERACTION, "TRAIT_DEL_ON_SPACE_DUMP" = TRAIT_DEL_ON_SPACE_DUMP, "TRAIT_FISH_CASE_COMPATIBILE" = TRAIT_FISH_CASE_COMPATIBILE, "TRAIT_FROZEN" = TRAIT_FROZEN, @@ -50,27 +52,26 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_MOVE_FLYING" = TRAIT_MOVE_FLYING, "TRAIT_MOVE_GROUND" = TRAIT_MOVE_GROUND, "TRAIT_MOVE_PHASING" = TRAIT_MOVE_PHASING, - "TRAIT_MOVE_VENTCRAWLING" = TRAIT_MOVE_VENTCRAWLING, "TRAIT_MOVE_UPSIDE_DOWN" = TRAIT_MOVE_UPSIDE_DOWN, + "TRAIT_MOVE_VENTCRAWLING" = TRAIT_MOVE_VENTCRAWLING, + "TRAIT_NOT_ENGRAVABLE" = TRAIT_NOT_ENGRAVABLE, "TRAIT_NO_FLOATING_ANIM" = TRAIT_NO_FLOATING_ANIM, "TRAIT_NO_MANIFEST_CONTENTS_ERROR" = TRAIT_NO_MANIFEST_CONTENTS_ERROR, "TRAIT_NO_MISSING_ITEM_ERROR" = TRAIT_NO_MISSING_ITEM_ERROR, "TRAIT_NO_THROW_HITPUSH" = TRAIT_NO_THROW_HITPUSH, - "TRAIT_NOT_ENGRAVABLE" = TRAIT_NOT_ENGRAVABLE, - "TRAIT_SPELLS_TRANSFER_TO_LOC" = TRAIT_SPELLS_TRANSFER_TO_LOC, "TRAIT_ODD_CUSTOMIZABLE_FOOD_INGREDIENT" = TRAIT_ODD_CUSTOMIZABLE_FOOD_INGREDIENT, "TRAIT_ON_HIT_EFFECT" = TRAIT_ON_HIT_EFFECT, "TRAIT_RUNECHAT_HIDDEN" = TRAIT_RUNECHAT_HIDDEN, "TRAIT_SCARY_FISHERMAN" = TRAIT_SCARY_FISHERMAN, "TRAIT_SECLUDED_LOCATION" = TRAIT_SECLUDED_LOCATION, "TRAIT_SNOWSTORM_IMMUNE" = TRAIT_SNOWSTORM_IMMUNE, + "TRAIT_SPELLS_TRANSFER_TO_LOC" = TRAIT_SPELLS_TRANSFER_TO_LOC, "TRAIT_TELEKINESIS_CONTROLLED" = TRAIT_TELEKINESIS_CONTROLLED, "TRAIT_UNDERFLOOR" = TRAIT_UNDERFLOOR, "TRAIT_UNIQUE_IMMERSE" = TRAIT_UNIQUE_IMMERSE, - "TRAIT_WAS_RENAMED" = TRAIT_WAS_RENAMED, "TRAIT_WADDLING" = TRAIT_WADDLING, + "TRAIT_WAS_RENAMED" = TRAIT_WAS_RENAMED, "TRAIT_WEATHER_IMMUNE" = TRAIT_WEATHER_IMMUNE, - "TRAIT_CHASM_STOPPER" = TRAIT_CHASM_STOPPER, ), /datum/controller/subsystem/economy = list( "TRAIT_MARKET_CRASHING" = TRAIT_MARKET_CRASHING, diff --git a/code/datums/components/cleaner.dm b/code/datums/components/cleaner.dm index 3001fde9837..75319a7133f 100644 --- a/code/datums/components/cleaner.dm +++ b/code/datums/components/cleaner.dm @@ -62,6 +62,9 @@ /datum/component/cleaner/proc/on_interaction(datum/source, mob/living/user, atom/target, list/modifiers) SIGNAL_HANDLER + if(isitem(source) && SHOULD_SKIP_INTERACTION(target, source, user)) + return NONE + // By default, give XP var/give_xp = TRUE if(pre_clean_callback) diff --git a/code/datums/components/lockable_storage.dm b/code/datums/components/lockable_storage.dm index 482cb134159..ca058cb3fbf 100644 --- a/code/datums/components/lockable_storage.dm +++ b/code/datums/components/lockable_storage.dm @@ -62,7 +62,6 @@ 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, diff --git a/code/datums/storage/storage.dm b/code/datums/storage/storage.dm index 8bdfa3f3de2..aedb28a74e9 100644 --- a/code/datums/storage/storage.dm +++ b/code/datums/storage/storage.dm @@ -189,20 +189,19 @@ /// Set the passed atom as the parent /datum/storage/proc/set_parent(atom/new_parent) - PRIVATE_PROC(TRUE) + PROTECTED_PROC(TRUE) ASSERT(isnull(parent)) parent = new_parent + ADD_TRAIT(parent, TRAIT_COMBAT_MODE_SKIP_INTERACTION, REF(src)) // a few of theses should probably be on the real_location rather than the parent - 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_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)) @@ -834,19 +833,9 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) attempt_insert(dropping, user) return COMPONENT_CANCEL_MOUSEDROPPED_ONTO -/// Signal handler for whenever we're attacked by an object. -/datum/storage/proc/on_item_interact(datum/source, mob/user, obj/item/thing, params) - SIGNAL_HANDLER - - 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 - +/// Called directly from the attack chain if [insert_on_attack] is TRUE. +/// Handles inserting an item into the storage when clicked. +/datum/storage/proc/item_interact_insert(mob/living/user, obj/item/thing) if(iscyborg(user)) return ITEM_INTERACT_BLOCKING @@ -897,18 +886,6 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) return toreturn -/// Signal handler for when we get attacked with secondary click by an item. -/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) - - 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) SIGNAL_HANDLER diff --git a/code/game/atom/atom_tool_acts.dm b/code/game/atom/atom_tool_acts.dm index 6fe1ffefc5d..efb43fc16e5 100644 --- a/code/game/atom/atom_tool_acts.dm +++ b/code/game/atom/atom_tool_acts.dm @@ -14,7 +14,7 @@ if(tool_return) return tool_return - var/is_right_clicking = LAZYACCESS(modifiers, RIGHT_CLICK) + var/is_right_clicking = text2num(LAZYACCESS(modifiers, RIGHT_CLICK)) var/is_left_clicking = !is_right_clicking var/early_sig_return = NONE if(is_left_clicking) @@ -22,10 +22,8 @@ * 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 + * This puts priority on the atom's signals, then the tool's signals, then the user's signals, + * so we can avoid doing two interactions at once */ early_sig_return = SEND_SIGNAL(src, COMSIG_ATOM_ITEM_INTERACTION, user, tool, modifiers) \ || SEND_SIGNAL(tool, COMSIG_ITEM_INTERACTING_WITH_ATOM, user, src, modifiers) \ @@ -50,6 +48,16 @@ if(interact_return) return interact_return + // We have to manually handle storage in item_interaction because storage is blocking in 99% of interactions, which stifles a lot + // Yeah it sucks not being able to signalize this, but the other option is to have a second signal here just for storage which is also not great + if(atom_storage) + if(is_left_clicking) + if(atom_storage.insert_on_attack) + return atom_storage.item_interact_insert(user, tool) + else + if(atom_storage.open_storage(user) && atom_storage.display_contents) + return ITEM_INTERACT_SUCCESS + return NONE /** @@ -315,23 +323,3 @@ /// Called on an object when a tool with analyzer capabilities is used to right click an object /atom/proc/analyzer_act_secondary(mob/living/user, obj/item/tool) return - -/** - * 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 - -/** - * 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 diff --git a/code/game/objects/items/climbingrope.dm b/code/game/objects/items/climbingrope.dm index e68e5087712..552b5d58850 100644 --- a/code/game/objects/items/climbingrope.dm +++ b/code/game/objects/items/climbingrope.dm @@ -27,6 +27,8 @@ . += span_notice("The rope looks like you could use it [uses] times before it falls apart.") /obj/item/climbing_hook/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + if(HAS_TRAIT(interacting_with, TRAIT_COMBAT_MODE_SKIP_INTERACTION)) + return NONE 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) diff --git a/code/game/objects/items/clown_items.dm b/code/game/objects/items/clown_items.dm index 6565bcae44f..58f2cb49a13 100644 --- a/code/game/objects/items/clown_items.dm +++ b/code/game/objects/items/clown_items.dm @@ -161,9 +161,6 @@ return CLEAN_BLOCKED return ..() -/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 */ diff --git a/code/game/objects/items/control_wand.dm b/code/game/objects/items/control_wand.dm index abad07f96d8..9734661e88f 100644 --- a/code/game/objects/items/control_wand.dm +++ b/code/game/objects/items/control_wand.dm @@ -35,10 +35,12 @@ update_icon_state() balloon_alert(user, "mode: [desc[mode]]") -/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) + if(!istype(interacting_with, /obj/machinery/door) && !isturf(interacting_with)) + return NONE + return ranged_interact_with_atom(interacting_with, user, modifiers) + +/obj/item/door_remote/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) var/obj/machinery/door/door if (istype(interacting_with, /obj/machinery/door)) diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm index 3b2d9d196a1..484cb54b0e3 100644 --- a/code/game/objects/items/crayons.dm +++ b/code/game/objects/items/crayons.dm @@ -865,7 +865,10 @@ /obj/item/toy/crayon/spraycan/can_use_on(atom/target, mob/user, list/modifiers) if(iscarbon(target)) return TRUE - if(ismob(target) && (HAS_TRAIT(target, TRAIT_SPRAY_PAINTABLE))) + if(is_capped && HAS_TRAIT(target, TRAIT_COMBAT_MODE_SKIP_INTERACTION)) + // specifically don't try to use a capped spraycan on stuff like bags and tables, just place it + return FALSE + if(ismob(target) && HAS_TRAIT(target, TRAIT_SPRAY_PAINTABLE)) return TRUE if(isobj(target) && !(target.flags_1 & UNPAINTABLE_1)) return TRUE @@ -967,6 +970,10 @@ /obj/item/toy/crayon/spraycan/interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers) if(is_capped) + if(!interacting_with.color) + // let's be generous and assume if they're trying to match something with no color, while capped, + // we shouldn't be blocking further interactions + return NONE balloon_alert(user, "take the cap off first!") return ITEM_INTERACT_BLOCKING if(check_empty(user)) @@ -1003,9 +1010,6 @@ update_appearance() return CLICK_ACTION_SUCCESS -/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() icon_state = is_capped ? icon_capped : icon_uncapped return ..() diff --git a/code/game/objects/items/devices/aicard.dm b/code/game/objects/items/devices/aicard.dm index c619f7d7018..77eefa8a150 100644 --- a/code/game/objects/items/devices/aicard.dm +++ b/code/game/objects/items/devices/aicard.dm @@ -43,17 +43,15 @@ user.visible_message(span_suicide("[user] is trying to upload [user.p_them()]self into [src]! That's not going to work out well!")) return BRUTELOSS -/obj/item/aicard/pre_attack(atom/target, mob/living/user, params) - . = ..() - if(.) - return - +/obj/item/aicard/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(AI) - if(upload_ai(target, user)) - return TRUE + if(upload_ai(interacting_with, user)) + return ITEM_INTERACT_SUCCESS else - if(capture_ai(target, user)) - return TRUE + if(capture_ai(interacting_with, user)) + return ITEM_INTERACT_SUCCESS + + return NONE /// Tries to get an AI from the atom clicked /obj/item/aicard/proc/capture_ai(atom/from_what, mob/living/user) diff --git a/code/game/objects/items/devices/chameleonproj.dm b/code/game/objects/items/devices/chameleonproj.dm index 1920e47f97f..f0a934fc198 100644 --- a/code/game/objects/items/devices/chameleonproj.dm +++ b/code/game/objects/items/devices/chameleonproj.dm @@ -36,26 +36,37 @@ else to_chat(user, span_warning("You can't use [src] while inside something!")) -/obj/item/chameleon/interact_with_atom(atom/target, mob/living/user, list/modifiers) - if(!check_sprite(target)) - return ITEM_INTERACT_BLOCKING - if(active_dummy)//I now present you the blackli(f)st - return ITEM_INTERACT_BLOCKING - if(isturf(target)) - return ITEM_INTERACT_BLOCKING - if(ismob(target)) - return ITEM_INTERACT_BLOCKING - if(istype(target, /obj/structure/falsewall)) - return ITEM_INTERACT_BLOCKING - if(target.alpha != 255) - return ITEM_INTERACT_BLOCKING - if(target.invisibility != 0) - return ITEM_INTERACT_BLOCKING - if(iseffect(target) && !istype(target, /obj/effect/decal)) //be a footprint - return ITEM_INTERACT_BLOCKING - make_copy(target, user) +/obj/item/chameleon/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + if(!can_copy(interacting_with) || SHOULD_SKIP_INTERACTION(interacting_with, src, user)) + return NONE + make_copy(interacting_with, user) return ITEM_INTERACT_SUCCESS +/obj/item/chameleon/interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers) + if(!can_copy(interacting_with)) // RMB scan works on storage items, LMB scan does not + return NONE + make_copy(interacting_with, user) + return ITEM_INTERACT_SUCCESS + +/obj/item/chameleon/proc/can_copy(atom/target) + if(!check_sprite(target)) + return FALSE + if(active_dummy)//I now present you the blackli(f)st + return FALSE + if(isturf(target)) + return FALSE + if(ismob(target)) + return FALSE + if(istype(target, /obj/structure/falsewall)) + return FALSE + if(target.alpha != 255) + return FALSE + if(target.invisibility != 0) + return FALSE + if(iseffect(target) && !istype(target, /obj/effect/decal)) //be a footprint + return FALSE + return TRUE + /obj/item/chameleon/proc/make_copy(atom/target, mob/user) playsound(get_turf(src), 'sound/weapons/flash.ogg', 100, TRUE, -6) to_chat(user, span_notice("Scanned [target].")) diff --git a/code/game/objects/items/devices/forcefieldprojector.dm b/code/game/objects/items/devices/forcefieldprojector.dm index 5d40d40a4d9..91bd3040832 100644 --- a/code/game/objects/items/devices/forcefieldprojector.dm +++ b/code/game/objects/items/devices/forcefieldprojector.dm @@ -21,10 +21,10 @@ /// Checks to make sure the projector isn't busy with making another forcefield. var/force_proj_busy = FALSE -/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) + return ranged_interact_with_atom(interacting_with, user, modifiers) + +/obj/item/forcefield_projector/ranged_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)) diff --git a/code/game/objects/items/devices/geiger_counter.dm b/code/game/objects/items/devices/geiger_counter.dm index 1d5ef17a90c..25bae430609 100644 --- a/code/game/objects/items/devices/geiger_counter.dm +++ b/code/game/objects/items/devices/geiger_counter.dm @@ -67,13 +67,13 @@ update_appearance(UPDATE_ICON) balloon_alert(user, "switch [scanning ? "on" : "off"]") -/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) + if(SHOULD_SKIP_INTERACTION(interacting_with, src, user)) return NONE - if (!CAN_IRRADIATE(interacting_with)) + return ranged_interact_with_atom(interacting_with, user, modifiers) + +/obj/item/geiger_counter/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + if(!CAN_IRRADIATE(interacting_with)) return NONE user.visible_message(span_notice("[user] scans [interacting_with] with [src]."), span_notice("You scan [interacting_with]'s radiation levels with [src]...")) diff --git a/code/game/objects/items/devices/laserpointer.dm b/code/game/objects/items/devices/laserpointer.dm index 3fe16fdb3fd..8dd03736a65 100644 --- a/code/game/objects/items/devices/laserpointer.dm +++ b/code/game/objects/items/devices/laserpointer.dm @@ -183,12 +183,14 @@ and the wide margin between it and the focus lens could probably house a crystal of some sort." /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 +/obj/item/laser_pointer/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + if(HAS_TRAIT(interacting_with, TRAIT_COMBAT_MODE_SKIP_INTERACTION)) + return NONE + return ranged_interact_with_atom(interacting_with, user, modifiers) + ///Handles shining the clicked atom, /obj/item/laser_pointer/proc/laser_act(atom/target, mob/living/user, list/modifiers) if(isnull(diode)) diff --git a/code/game/objects/items/devices/traitordevices.dm b/code/game/objects/items/devices/traitordevices.dm index 8327e185ea6..ee4a61b9351 100644 --- a/code/game/objects/items/devices/traitordevices.dm +++ b/code/game/objects/items/devices/traitordevices.dm @@ -361,15 +361,6 @@ effective or pretty fucking useless. new /obj/item/analyzer(src) new /obj/item/wirecutters(src) -/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 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 diff --git a/code/game/objects/items/emags.dm b/code/game/objects/items/emags.dm index ccb52b71bc3..f854ba1b90a 100644 --- a/code/game/objects/items/emags.dm +++ b/code/game/objects/items/emags.dm @@ -137,16 +137,16 @@ . = ..() 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(SHOULD_SKIP_INTERACTION(interacting_with, src, user)) + return NONE // lets us put things in bags without trying to emag them if(!can_emag(interacting_with, user)) return ITEM_INTERACT_BLOCKING log_combat(user, interacting_with, "attempted to emag") if(interacting_with.emag_act(user, src)) SSblackbox.record_feedback("tally", "atom_emagged", 1, interacting_with.type) - return ITEM_INTERACT_SUCCESS + return ITEM_INTERACT_SUCCESS + return NONE // In a perfect world this would be blocking, but this is not a perfect world /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) diff --git a/code/game/objects/items/extinguisher.dm b/code/game/objects/items/extinguisher.dm index 764e2fc6173..c542048b49d 100644 --- a/code/game/objects/items/extinguisher.dm +++ b/code/game/objects/items/extinguisher.dm @@ -207,13 +207,15 @@ else return FALSE -/obj/item/extinguisher/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) - return interact_with_atom(interacting_with, user, modifiers) - /obj/item/extinguisher/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) - if (interacting_with.loc == user) + if(interacting_with.loc == user) return NONE + // Always skip interaction if it's a bag or table (that's not on fire) + if(!(interacting_with.resistance_flags & ON_FIRE) && HAS_TRAIT(interacting_with, TRAIT_COMBAT_MODE_SKIP_INTERACTION)) + return NONE + return ranged_interact_with_atom(interacting_with, user, modifiers) +/obj/item/extinguisher/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(refilling) refilling = FALSE return NONE diff --git a/code/game/objects/items/machine_wand.dm b/code/game/objects/items/machine_wand.dm index 75c765730f7..7d8b4a0697d 100644 --- a/code/game/objects/items/machine_wand.dm +++ b/code/game/objects/items/machine_wand.dm @@ -85,10 +85,12 @@ remove_old_machine() return CLICK_ACTION_SUCCESS -/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(HAS_TRAIT(interacting_with, TRAIT_COMBAT_MODE_SKIP_INTERACTION) || (!ismachinery(interacting_with) && !isbot(interacting_with))) + return NONE + return ranged_interact_with_atom(interacting_with, user, modifiers) + +/obj/item/machine_remote/ranged_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.") diff --git a/code/game/objects/items/rcd/RCD.dm b/code/game/objects/items/rcd/RCD.dm index 0a9ff79d1ac..279bc91d622 100644 --- a/code/game/objects/items/rcd/RCD.dm +++ b/code/game/objects/items/rcd/RCD.dm @@ -207,15 +207,15 @@ * * [mob][user]- the user building this structure */ /obj/item/construction/rcd/proc/rcd_create(atom/target, mob/user) + var/list/rcd_results = target.rcd_vals(user, src) // does this atom allow for rcd actions? + if(!rcd_results) // nope + return NONE + //straight up can't touch this if(mode == RCD_DECONSTRUCT && (target.resistance_flags & INDESTRUCTIBLE)) balloon_alert(user, "too durable!") - return + return ITEM_INTERACT_BLOCKING - //does this atom allow for rcd actions? - var/list/rcd_results = target.rcd_vals(user, src) - if(!rcd_results) - return FALSE rcd_results["[RCD_DESIGN_MODE]"] = mode rcd_results["[RCD_DESIGN_PATH]"] = rcd_design_path @@ -237,6 +237,7 @@ log_tool("[key_name(user)] used [src] to [rcd_results["[RCD_DESIGN_MODE]"] != RCD_DECONSTRUCT ? "construct [initial(design_path.name)]([design_path])" : "deconstruct [target_name]([target_path])"] at [location]") current_active_effects -= 1 + return ITEM_INTERACT_SUCCESS /** * Internal proc which creates the rcd effects & creates the structure @@ -401,29 +402,25 @@ return . mode = construction_mode - rcd_create(interacting_with, user) - return ITEM_INTERACT_SUCCESS + return rcd_create(interacting_with, user) /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 mode = construction_mode - rcd_create(interacting_with, user) - return ITEM_INTERACT_SUCCESS + return rcd_create(interacting_with, user) /obj/item/construction/rcd/interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers) mode = RCD_DECONSTRUCT - rcd_create(interacting_with, user) - return ITEM_INTERACT_SUCCESS + return rcd_create(interacting_with, user) /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 mode = RCD_DECONSTRUCT - rcd_create(interacting_with, user) - return ITEM_INTERACT_SUCCESS + return rcd_create(interacting_with, user) /obj/item/construction/rcd/handle_openspace_click(turf/target, mob/user, list/modifiers) interact_with_atom(target, user, modifiers) diff --git a/code/game/objects/items/religion.dm b/code/game/objects/items/religion.dm index 232de4c4619..77b087b8ac5 100644 --- a/code/game/objects/items/religion.dm +++ b/code/game/objects/items/religion.dm @@ -343,10 +343,12 @@ var/staffcooldown = 0 var/staffwait = 30 -/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(SHOULD_SKIP_INTERACTION(interacting_with, src, user)) + return NONE + return ranged_interact_with_atom(interacting_with, user, modifiers) + +/obj/item/godstaff/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(staffcooldown + staffwait > world.time) return ITEM_INTERACT_BLOCKING diff --git a/code/game/objects/items/stacks/wrap.dm b/code/game/objects/items/stacks/wrap.dm index d7fcd17f295..d1cbb7f1ce8 100644 --- a/code/game/objects/items/stacks/wrap.dm +++ b/code/game/objects/items/stacks/wrap.dm @@ -102,13 +102,6 @@ /obj/item/delivery/can_be_package_wrapped() return FALSE -/obj/item/stack/package_wrap/storage_insert_on_interaction(datum/storage, atom/storage_holder, mob/user) - if(isitem(storage_holder)) - // Don't insert if the target can be wrapped - var/obj/item/item = storage_holder - return !item.can_be_package_wrapped() - return TRUE - /obj/item/stack/package_wrap/interact_with_atom(obj/interacting_with, mob/living/user, list/modifiers) if(!isobj(interacting_with)) return NONE @@ -118,6 +111,8 @@ if(isitem(interacting_with)) var/obj/item/item = interacting_with if(!item.can_be_package_wrapped()) + if(SHOULD_SKIP_INTERACTION(interacting_with, src, user)) + return NONE // put it in the bag instead of yelling balloon_alert(user, "can't be wrapped!") return ITEM_INTERACT_BLOCKING if(user.is_holding(item)) diff --git a/code/game/objects/items/storage/bags.dm b/code/game/objects/items/storage/bags.dm index 269a6699d3e..2a2affef2cb 100644 --- a/code/game/objects/items/storage/bags.dm +++ b/code/game/objects/items/storage/bags.dm @@ -155,13 +155,13 @@ UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED) listeningTo = null -/obj/item/storage/bag/ore/storage_insert_on_interacted_with(datum/storage, obj/item/inserted, mob/living/user) - if(istype(inserted, /obj/item/boulder)) - to_chat(user, span_warning("You can't fit [inserted] into [src]. \ +/obj/item/storage/bag/ore/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + if(istype(tool, /obj/item/boulder)) + to_chat(user, span_warning("You can't fit [tool] into [src]. \ Perhaps you should break it down first, or find an ore box.")) - return FALSE + return ITEM_INTERACT_BLOCKING - return TRUE + return NONE /obj/item/storage/bag/ore/proc/pickup_ores(mob/living/user) SIGNAL_HANDLER diff --git a/code/game/objects/items/taster.dm b/code/game/objects/items/taster.dm index 599b78971db..cdd67ceae56 100644 --- a/code/game/objects/items/taster.dm +++ b/code/game/objects/items/taster.dm @@ -16,4 +16,4 @@ else var/message = interacting_with.reagents.generate_taste_message(user, taste_sensitivity) to_chat(user, span_notice("[src] tastes [message] in [interacting_with].")) - return ITEM_INTERACT_SUCCESS + return user.combat_mode ? NONE : ITEM_INTERACT_SUCCESS diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index ea2bd7e97e7..3bfac213ba5 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -888,7 +888,7 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets) user.log_message("[welded ? "welded":"unwelded"] closet [src] with [weapon]", LOG_GAME) update_appearance() - else if(!user.combat_mode) + else if(!user.combat_mode || (weapon.item_flags & NOBLUDGEON)) var/item_is_id = weapon.GetID() if(!item_is_id) return FALSE diff --git a/code/game/objects/structures/deployable_turret.dm b/code/game/objects/structures/deployable_turret.dm index 908d2348db4..6abb14294de 100644 --- a/code/game/objects/structures/deployable_turret.dm +++ b/code/game/objects/structures/deployable_turret.dm @@ -259,11 +259,11 @@ M.attacked_by(src, user) add_fingerprint(user) -/obj/item/gun_control/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) +/obj/item/gun_control/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) var/obj/machinery/deployable_turret/E = user.buckled E.calculated_projectile_vars = calculate_projectile_angle_and_pixel_offsets(user, interacting_with, modifiers) E.direction_track(user, interacting_with) E.checkfire(interacting_with, user) -/obj/item/gun_control/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) - return interact_with_atom(interacting_with, user, modifiers) +/obj/item/gun_control/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + return ranged_interact_with_atom(interacting_with, user, modifiers) diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 8dc8d82ff5f..32e76bb2c83 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -55,6 +55,8 @@ AddElement(/datum/element/give_turf_traits, give_turf_traits) register_context() + ADD_TRAIT(src, TRAIT_COMBAT_MODE_SKIP_INTERACTION, INNATE_TRAIT) + ///Adds the element used to make the object climbable, and also the one that shift the mob buckled to it up. /obj/structure/table/proc/make_climbable() AddElement(/datum/element/climbable) @@ -224,36 +226,24 @@ deconstruct(TRUE) return ITEM_INTERACT_SUCCESS -/obj/structure/table/item_interaction_secondary(mob/living/user, obj/item/tool, list/modifiers) - if(istype(tool, /obj/item/construction/rcd)) - return NONE +// This extends base item interaction because tables default to blocking 99% of interactions +/obj/structure/table/base_item_interaction(mob/living/user, obj/item/tool, list/modifiers) + . = ..() + if(.) + return . - var/deck_act_value = NONE if(istype(tool, /obj/item/toy/cards/deck)) - deck_act_value = deck_act(user, tool, modifiers, TRUE) - // Continue to placing if we don't do anything else - if(deck_act_value != NONE) - return deck_act_value - - if(!user.combat_mode) - return table_place_act(user, tool, modifiers) - - return NONE - -/obj/structure/table/item_interaction(mob/living/user, obj/item/tool, list/modifiers) - . = NONE + . = deck_act(user, tool, modifiers, !!LAZYACCESS(modifiers, RIGHT_CLICK)) if(istype(tool, /obj/item/storage/bag/tray)) . = tray_act(user, tool) - else if(istype(tool, /obj/item/toy/cards/deck)) - . = deck_act(user, tool, modifiers, FALSE) else if(istype(tool, /obj/item/riding_offhand)) . = riding_offhand_act(user, tool) // Continue to placing if we don't do anything else - if(. != NONE) + if(.) return . - if(!user.combat_mode) + if(!user.combat_mode || (tool.item_flags & NOBLUDGEON)) return table_place_act(user, tool, modifiers) return NONE @@ -865,6 +855,7 @@ AddElement(/datum/element/climbable) AddElement(/datum/element/elevation, pixel_shift = 12) register_context() + ADD_TRAIT(src, TRAIT_COMBAT_MODE_SKIP_INTERACTION, INNATE_TRAIT) /obj/structure/rack/add_context(atom/source, list/context, obj/item/held_item, mob/living/user) if(isnull(held_item)) @@ -892,8 +883,11 @@ deconstruct(TRUE) return ITEM_INTERACT_SUCCESS -/obj/structure/rack/item_interaction(mob/living/user, obj/item/tool, list/modifiers) - if((tool.item_flags & ABSTRACT) || user.combat_mode) +/obj/structure/rack/base_item_interaction(mob/living/user, obj/item/tool, list/modifiers) + . = ..() + if(.) + return . + if((tool.item_flags & ABSTRACT) || (user.combat_mode && !(tool.item_flags & NOBLUDGEON))) return NONE if(user.transferItemToLoc(tool, drop_location(), silent = FALSE)) return ITEM_INTERACT_SUCCESS diff --git a/code/game/objects/structures/tank_dispenser.dm b/code/game/objects/structures/tank_dispenser.dm index 2d16ea30a69..46c18d85b40 100644 --- a/code/game/objects/structures/tank_dispenser.dm +++ b/code/game/objects/structures/tank_dispenser.dm @@ -71,7 +71,7 @@ oxygentanks++ else full = TRUE - else if(!user.combat_mode) + else if(!user.combat_mode || (I.item_flags & NOBLUDGEON)) balloon_alert(user, "can't insert!") return else diff --git a/code/game/objects/structures/water_structures/sink.dm b/code/game/objects/structures/water_structures/sink.dm index 878dab578a5..1cd3f7d7aaa 100644 --- a/code/game/objects/structures/water_structures/sink.dm +++ b/code/game/objects/structures/water_structures/sink.dm @@ -204,7 +204,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/sink, (-14)) if(O.item_flags & ABSTRACT) //Abstract items like grabs won't wash. No-drop items will though because it's still technically an item in your hand. return - if(!user.combat_mode) + if(!user.combat_mode || (O.item_flags & NOBLUDGEON)) to_chat(user, span_notice("You start washing [O]...")) busy = TRUE if(!do_after(user, 4 SECONDS, target = src)) diff --git a/code/game/objects/structures/water_structures/water_source.dm b/code/game/objects/structures/water_structures/water_source.dm index 9420156d918..a59051f92dd 100644 --- a/code/game/objects/structures/water_structures/water_source.dm +++ b/code/game/objects/structures/water_structures/water_source.dm @@ -114,7 +114,7 @@ attacking_item.use(1) return - if(!user.combat_mode) + if(!user.combat_mode || (attacking_item.item_flags & NOBLUDGEON)) to_chat(user, span_notice("You start washing [attacking_item]...")) busy = TRUE if(!do_after(user, 4 SECONDS, target = src)) diff --git a/code/modules/antagonists/abductor/equipment/gear/abductor_items.dm b/code/modules/antagonists/abductor/equipment/gear/abductor_items.dm index 25bbea66577..5a8f699832e 100644 --- a/code/modules/antagonists/abductor/equipment/gear/abductor_items.dm +++ b/code/modules/antagonists/abductor/equipment/gear/abductor_items.dm @@ -48,7 +48,7 @@ icon_state = "gizmo_scan" to_chat(user, span_notice("You switch the device to [mode == GIZMO_SCAN? "SCAN": "MARK"] MODE")) -/obj/item/abductor/gizmo/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) +/obj/item/abductor/gizmo/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(!ScientistCheck(user)) return ITEM_INTERACT_SKIP_TO_ATTACK // So you slap them with it if(!console) @@ -63,8 +63,10 @@ return ITEM_INTERACT_SUCCESS -/obj/item/abductor/gizmo/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) - return interact_with_atom(interacting_with, user, modifiers) +/obj/item/abductor/gizmo/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + if(!ismob(interacting_with)) + return NONE + return ranged_interact_with_atom(interacting_with, user, modifiers) /obj/item/abductor/gizmo/proc/scan(atom/target, mob/living/user) if(ishuman(target)) @@ -104,15 +106,17 @@ icon_state = "silencer" inhand_icon_state = "gizmo" -/obj/item/abductor/silencer/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) +/obj/item/abductor/silencer/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(!AbductorCheck(user)) return ITEM_INTERACT_SKIP_TO_ATTACK // So you slap them with it radio_off(interacting_with, user) return ITEM_INTERACT_SUCCESS -/obj/item/abductor/silencer/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) - return interact_with_atom(interacting_with, user, modifiers) +/obj/item/abductor/silencer/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + if(!ismob(interacting_with)) + return NONE + return ranged_interact_with_atom(interacting_with, user, modifiers) /obj/item/abductor/silencer/proc/radio_off(atom/target, mob/living/user) if( !(user in (viewers(7,target))) ) @@ -155,10 +159,12 @@ icon_state = "mind_device_message" to_chat(user, span_notice("You switch the device to [mode == MIND_DEVICE_MESSAGE? "TRANSMISSION": "COMMAND"] MODE")) -/obj/item/abductor/mind_device/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) - return interact_with_atom(interacting_with, user, modifiers) - /obj/item/abductor/mind_device/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + if(!ismob(interacting_with)) + return NONE + return ranged_interact_with_atom(interacting_with, user, modifiers) + +/obj/item/abductor/mind_device/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(!ScientistCheck(user)) return ITEM_INTERACT_BLOCKING diff --git a/code/modules/antagonists/heretic/items/labyrinth_handbook.dm b/code/modules/antagonists/heretic/items/labyrinth_handbook.dm index 8555b60f0c3..e4f333260a8 100644 --- a/code/modules/antagonists/heretic/items/labyrinth_handbook.dm +++ b/code/modules/antagonists/heretic/items/labyrinth_handbook.dm @@ -41,10 +41,12 @@ . += span_hypnophrase("Materializes a barrier upon any tile in sight, which only you can pass through. Lasts 8 seconds.") . += span_hypnophrase("It has [uses] uses left.") -/obj/item/heretic_labyrinth_handbook/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) - return interact_with_atom(interacting_with, user, modifiers) - /obj/item/heretic_labyrinth_handbook/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + if(HAS_TRAIT(interacting_with, TRAIT_COMBAT_MODE_SKIP_INTERACTION)) + return NONE + return ranged_interact_with_atom(interacting_with, user, modifiers) + +/obj/item/heretic_labyrinth_handbook/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(!IS_HERETIC(user)) if(ishuman(user)) var/mob/living/carbon/human/human_user = user diff --git a/code/modules/antagonists/spy/spy_bounty.dm b/code/modules/antagonists/spy/spy_bounty.dm index 42ab0203e5c..ccab7952a9c 100644 --- a/code/modules/antagonists/spy/spy_bounty.dm +++ b/code/modules/antagonists/spy/spy_bounty.dm @@ -132,6 +132,14 @@ /datum/spy_bounty/proc/clean_up_stolen_item(atom/movable/stealing, mob/living/spy) do_sparks(3, FALSE, stealing) + if(isitem(stealing) && stealing.loc == spy) + // get it out of our inventory before we mess with it to prevent any weirdness. + // bypasses nodrop - if you want, add a bespoke check for that higher up the chain + spy.temporarilyRemoveItemFromInventory(stealing, force = TRUE) + // also check for DROPDEL + if(QDELETED(stealing)) + return + // Don't mess with it while it's going away var/had_attack_hand_interaction = stealing.interaction_flags_atom & INTERACT_ATOM_ATTACK_HAND stealing.interaction_flags_atom &= ~INTERACT_ATOM_ATTACK_HAND diff --git a/code/modules/antagonists/spy/spy_uplink.dm b/code/modules/antagonists/spy/spy_uplink.dm index 5de66271fe2..920076f21b4 100644 --- a/code/modules/antagonists/spy/spy_uplink.dm +++ b/code/modules/antagonists/spy/spy_uplink.dm @@ -23,7 +23,7 @@ /datum/component/spy_uplink/RegisterWithParent() RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) RegisterSignal(parent, COMSIG_ITEM_ATTACK_SELF, PROC_REF(on_attack_self)) - RegisterSignal(parent, COMSIG_ITEM_PRE_ATTACK_SECONDARY, PROC_REF(on_pre_attack_secondary)) + RegisterSignal(parent, COMSIG_ITEM_INTERACTING_WITH_ATOM, PROC_REF(on_item_atom_interaction)) RegisterSignal(parent, COMSIG_TABLET_CHECK_DETONATE, PROC_REF(block_pda_bombs)) /datum/component/spy_uplink/UnregisterFromParent() @@ -60,13 +60,15 @@ INVOKE_ASYNC(src, TYPE_PROC_REF(/datum, ui_interact), user) return NONE -/datum/component/spy_uplink/proc/on_pre_attack_secondary(obj/item/source, atom/target, mob/living/user, params) +/datum/component/spy_uplink/proc/on_item_atom_interaction(obj/item/source, mob/living/user, atom/target, list/modifiers) SIGNAL_HANDLER if(!ismovable(target)) return NONE if(!IS_SPY(user)) return NONE + if(SHOULD_SKIP_INTERACTION(target, source, user)) + return NONE if(!try_steal(target, user)) return NONE return COMPONENT_CANCEL_ATTACK_CHAIN @@ -94,7 +96,7 @@ /// Wraps the stealing process in a scanning effect. /datum/component/spy_uplink/proc/start_stealing(atom/movable/stealing, mob/living/spy, datum/spy_bounty/bounty) if(!isturf(stealing.loc) && stealing.loc != spy) - to_chat(spy, span_warning("Your uplinks blinks red: [stealing] cannot be extracted from there.")) + to_chat(spy, span_warning("Your uplink blinks red: [stealing] cannot be extracted from there.")) return FALSE log_combat(spy, stealing, "started stealing", parent, "(spy bounty)") @@ -139,10 +141,10 @@ if(!do_after(spy, bounty.theft_time, stealing, interaction_key = REF(src), hidden = TRUE)) return FALSE if(bounty.claimed) - to_chat(spy, span_warning("Your uplinks blinks red: The bounty for [stealing] has been claimed by another spy!")) + to_chat(spy, span_warning("Your uplink blinks red: The bounty for [stealing] has been claimed by another spy!")) return FALSE if(spy.is_holding(stealing) && !spy.dropItemToGround(stealing)) - to_chat(spy, span_warning("Your uplinks blinks red: [stealing] seems stuck to your hand!")) + to_chat(spy, span_warning("Your uplink blinks red: [stealing] seems stuck to your hand!")) return FALSE var/bounty_key = bounty.get_dupe_protection_key(stealing) diff --git a/code/modules/antagonists/traitor/objectives/steal.dm b/code/modules/antagonists/traitor/objectives/steal.dm index fdcd693fed8..4c697d66d57 100644 --- a/code/modules/antagonists/traitor/objectives/steal.dm +++ b/code/modules/antagonists/traitor/objectives/steal.dm @@ -255,7 +255,7 @@ GLOBAL_DATUM_INIT(steal_item_handler, /datum/objective_item_handler, new()) /obj/item/traitor_bug name = "suspicious device" desc = "It looks dangerous." - item_flags = EXAMINE_SKIP + item_flags = EXAMINE_SKIP|NOBLUDGEON icon = 'icons/obj/antags/syndicate_tools.dmi' icon_state = "bug" @@ -280,7 +280,8 @@ GLOBAL_DATUM_INIT(steal_item_handler, /datum/objective_item_handler, new()) /obj/item/traitor_bug/interact_with_atom(atom/movable/target, mob/living/user, list/modifiers) if(!target_object_type || !ismovable(target)) return NONE - + if(SHOULD_SKIP_INTERACTION(target, src, user)) + return NONE var/result = SEND_SIGNAL(src, COMSIG_TRAITOR_BUG_PRE_PLANTED_OBJECT, target) if(!(result & COMPONENT_FORCE_PLACEMENT)) if(result & COMPONENT_FORCE_FAIL_PLACEMENT || !istype(target, target_object_type)) @@ -315,6 +316,3 @@ GLOBAL_DATUM_INIT(steal_item_handler, /datum/objective_item_handler, new()) anchored = FALSE UnregisterSignal(planted_on, COMSIG_QDELETING) planted_on = null - -/obj/item/traitor_bug/storage_insert_on_interaction(datum/storage, atom/storage_holder, mob/user) - return !istype(storage_holder, target_object_type) diff --git a/code/modules/antagonists/wizard/equipment/artefact.dm b/code/modules/antagonists/wizard/equipment/artefact.dm index 9176558c7a1..bf04c535a56 100644 --- a/code/modules/antagonists/wizard/equipment/artefact.dm +++ b/code/modules/antagonists/wizard/equipment/artefact.dm @@ -431,10 +431,10 @@ COMSIG_ITEM_MAGICALLY_CHARGED = PROC_REF(on_magic_charge), ) -/obj/item/runic_vendor_scepter/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) - return interact_with_atom(interacting_with, user, modifiers) - /obj/item/runic_vendor_scepter/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + return ranged_interact_with_atom(interacting_with, user, modifiers) + +/obj/item/runic_vendor_scepter/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(scepter_is_busy_recharging) user.balloon_alert(user, "busy!") return ITEM_INTERACT_BLOCKING diff --git a/code/modules/antagonists/wizard/equipment/soulstone.dm b/code/modules/antagonists/wizard/equipment/soulstone.dm index f8f5cf22350..eb4df6b6239 100644 --- a/code/modules/antagonists/wizard/equipment/soulstone.dm +++ b/code/modules/antagonists/wizard/equipment/soulstone.dm @@ -224,19 +224,19 @@ shade_datum.release_time = world.time on_release_spirits() -/obj/item/soulstone/pre_attack(atom/A, mob/living/user, params) - var/mob/living/basic/shade/occupant = (locate() in src) - var/obj/item/storage/toolbox/mechanical/target_toolbox = A - if(!occupant || !istype(target_toolbox) || target_toolbox.has_soul) - return ..() +/obj/item/soulstone/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + var/mob/living/basic/shade/occupant = locate() in src + var/obj/item/storage/toolbox/mechanical/target_toolbox = interacting_with + if(isnull(occupant) || !istype(target_toolbox) || target_toolbox.has_soul) + return NONE if(theme == THEME_HOLY && IS_CULTIST(user)) hot_potato(user) - return + return ITEM_INTERACT_BLOCKING if(!role_check(user)) user.Unconscious(10 SECONDS) to_chat(user, span_userdanger("Your body is wracked with debilitating pain!")) - return + return ITEM_INTERACT_BLOCKING user.visible_message("[user] holds [src] above [user.p_their()] head and forces it into [target_toolbox] with a flash of light!", \ span_notice("You hold [src] above your head briefly, then force it into [target_toolbox], transferring the [occupant]'s soul!"), ignored_mobs = occupant) @@ -253,6 +253,7 @@ target_toolbox.icon_state = "toolbox_blue_old" target_toolbox.has_soul = TRUE target_toolbox.has_latches = FALSE + return ITEM_INTERACT_SUCCESS ///////////////////////////Transferring to constructs///////////////////////////////////////////////////// /obj/structure/constructshell diff --git a/code/modules/clothing/chameleon/chameleon_scanner.dm b/code/modules/clothing/chameleon/chameleon_scanner.dm index 2ea0958a0cc..8b213e3f816 100644 --- a/code/modules/clothing/chameleon/chameleon_scanner.dm +++ b/code/modules/clothing/chameleon/chameleon_scanner.dm @@ -46,10 +46,14 @@ /obj/item/chameleon_scanner/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) return scan_target(interacting_with, user) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING -/obj/item/chameleon_scanner/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) - return interact_with_atom(interacting_with, user, modifiers) +/obj/item/chameleon_scanner/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + if(SHOULD_SKIP_INTERACTION(interacting_with, src, user)) + return NONE + return ranged_interact_with_atom(interacting_with, user, modifiers) -/obj/item/chameleon_scanner/interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers) +/obj/item/chameleon_scanner/ranged_interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers) + if(!isliving(interacting_with) && !isturf(interacting_with)) + return NONE var/list/scanned_outfit = scan_target(interacting_with, user) if(length(scanned_outfit)) var/datum/outfit/empty_outfit = new() diff --git a/code/modules/detectivework/evidence.dm b/code/modules/detectivework/evidence.dm index 4f8d8c74cb1..7110e368dce 100644 --- a/code/modules/detectivework/evidence.dm +++ b/code/modules/detectivework/evidence.dm @@ -7,16 +7,19 @@ icon_state = "evidenceobj" inhand_icon_state = "" w_class = WEIGHT_CLASS_TINY + item_flags = NOBLUDGEON /obj/item/evidencebag/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) - if(interacting_with == loc) + if(interacting_with == loc || !isitem(interacting_with) || HAS_TRAIT(interacting_with, TRAIT_COMBAT_MODE_SKIP_INTERACTION)) return NONE - evidencebagEquip(interacting_with, user) - return ITEM_INTERACT_SUCCESS + if(evidencebagEquip(interacting_with, user)) + return ITEM_INTERACT_SUCCESS + return NONE -/obj/item/evidencebag/attackby(obj/item/I, mob/user, params) - if(evidencebagEquip(I, user)) - return 1 +/obj/item/evidencebag/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + if(evidencebagEquip(tool, user)) + return ITEM_INTERACT_SUCCESS + return NONE /obj/item/evidencebag/Exited(atom/movable/gone, direction) . = ..() @@ -27,7 +30,7 @@ /obj/item/evidencebag/proc/evidencebagEquip(obj/item/I, mob/user) if(!istype(I) || I.anchored) - return + return FALSE if(loc.atom_storage && I.atom_storage) to_chat(user, span_warning("No matter what way you try, you can't get [I] to fit inside [src].")) @@ -43,24 +46,24 @@ if(loc in I.get_all_contents()) // fixes tg #39452, evidence bags could store their own location, causing I to be stored in the bag while being present inworld still, and able to be teleported when removed. to_chat(user, span_warning("You find putting [I] in [src] while it's still inside it quite difficult!")) - return + return TRUE if(I.w_class > WEIGHT_CLASS_NORMAL) to_chat(user, span_warning("[I] won't fit in [src]!")) - return + return TRUE if(contents.len) to_chat(user, span_warning("[src] already has something inside it!")) - return + return TRUE if(!isturf(I.loc)) //If it isn't on the floor. Do some checks to see if it's in our hands or a box. Otherwise give up. if(I.loc.atom_storage) //in a container. I.loc.atom_storage.remove_single(user, I, src) if(!user.is_holding(I) || HAS_TRAIT(I, TRAIT_NODROP)) - return + return TRUE if(QDELETED(I)) - return + return TRUE user.visible_message(span_notice("[user] puts [I] into [src]."), span_notice("You put [I] inside [src]."),\ span_hear("You hear a rustle as someone puts something into a plastic bag.")) @@ -78,7 +81,7 @@ desc = "An evidence bag containing [I]. [I.desc]" I.forceMove(src) update_weight_class(I.w_class) - return 1 + return TRUE /obj/item/evidencebag/attack_self(mob/user) if(contents.len) diff --git a/code/modules/detectivework/scanner.dm b/code/modules/detectivework/scanner.dm index 57987eda621..002647f7a08 100644 --- a/code/modules/detectivework/scanner.dm +++ b/code/modules/detectivework/scanner.dm @@ -74,10 +74,9 @@ // Clear the logs log = list() -/obj/item/detective_scanner/storage_insert_on_interaction(datum/storage, atom/storage_holder, mob/living/user) - return !user.combat_mode - /obj/item/detective_scanner/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + if(SHOULD_SKIP_INTERACTION(interacting_with, src, user)) + return NONE // lets us put our scanner away without trying to scan the bag safe_scan(user, interacting_with) return ITEM_INTERACT_SUCCESS diff --git a/code/modules/fishing/fishing_rod.dm b/code/modules/fishing/fishing_rod.dm index 86fe5178a6c..122378e99e6 100644 --- a/code/modules/fishing/fishing_rod.dm +++ b/code/modules/fishing/fishing_rod.dm @@ -221,7 +221,7 @@ /obj/item/fishing_rod/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) //this prevent trying to use telekinesis to fish (which would be broken anyway) - if(!user.contains(src)) + if(!user.contains(src) || (user.combat_mode && !isturf(interacting_with)) ||HAS_TRAIT(interacting_with, TRAIT_COMBAT_MODE_SKIP_INTERACTION)) return ..() return ranged_interact_with_atom(interacting_with, user, modifiers) diff --git a/code/modules/food_and_drinks/machinery/microwave.dm b/code/modules/food_and_drinks/machinery/microwave.dm index 4fa586401ff..92687aee8d0 100644 --- a/code/modules/food_and_drinks/machinery/microwave.dm +++ b/code/modules/food_and_drinks/machinery/microwave.dm @@ -381,12 +381,20 @@ if(operating) return NONE - if (item.item_flags & ABSTRACT) + if(item.item_flags & ABSTRACT) + return NONE + + if(dirty >= MAX_MICROWAVE_DIRTINESS) // The microwave is all dirty so can't be used! + if(IS_EDIBLE(item)) + balloon_alert(user, "it's too dirty!") + return ITEM_INTERACT_BLOCKING return NONE if(broken > NOT_BROKEN) - balloon_alert(user, "it's broken!") - return ITEM_INTERACT_BLOCKING + if(IS_EDIBLE(item)) + balloon_alert(user, "it's broken!") + return ITEM_INTERACT_BLOCKING + return NONE if(istype(item, /obj/item/stock_parts/power_store/cell) && cell_powered) var/swapped = FALSE @@ -405,12 +413,10 @@ return ITEM_INTERACT_SUCCESS if(!anchored) - balloon_alert(user, "not secured!") - return ITEM_INTERACT_BLOCKING - - if(dirty >= MAX_MICROWAVE_DIRTINESS) // The microwave is all dirty so can't be used! - balloon_alert(user, "it's too dirty!") - return ITEM_INTERACT_BLOCKING + if(IS_EDIBLE(item)) + balloon_alert(user, "not secured!") + return ITEM_INTERACT_BLOCKING + return NONE if(vampire_charging_capable && istype(item, /obj/item/modular_computer) && ingredients.len > 0) balloon_alert(user, "max 1 device!") diff --git a/code/modules/food_and_drinks/machinery/smartfridge.dm b/code/modules/food_and_drinks/machinery/smartfridge.dm index 1dca29b9504..b80a37a0ce6 100644 --- a/code/modules/food_and_drinks/machinery/smartfridge.dm +++ b/code/modules/food_and_drinks/machinery/smartfridge.dm @@ -313,7 +313,7 @@ to_chat(user, span_warning("\The [src]'s magnetic door won't open without power!")) return FALSE - if(!user.combat_mode) + if(!user.combat_mode || (weapon.item_flags & NOBLUDGEON)) to_chat(user, span_warning("\The [src] smartly refuses [weapon].")) return FALSE diff --git a/code/modules/hydroponics/beekeeping/bee_smoker.dm b/code/modules/hydroponics/beekeeping/bee_smoker.dm index 91195dacc84..f3eae4dc41c 100644 --- a/code/modules/hydroponics/beekeeping/bee_smoker.dm +++ b/code/modules/hydroponics/beekeeping/bee_smoker.dm @@ -37,13 +37,17 @@ return TRUE /obj/item/bee_smoker/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + if(!istype(interacting_with, /obj/structure/beebox) && !isturf(interacting_with) && !istype(interacting_with, /mob/living/basic/bee)) + return NONE + + . = ITEM_INTERACT_BLOCKING if(!activated) user.balloon_alert(user, "not activated!") - return ITEM_INTERACT_BLOCKING + return . if(current_herb_fuel < single_use_cost) user.balloon_alert(user, "not enough fuel!") - return ITEM_INTERACT_BLOCKING + return . current_herb_fuel -= single_use_cost playsound(src, 'sound/effects/spray2.ogg', 100, TRUE) @@ -53,16 +57,19 @@ if(friend.flags_1 & HOLOGRAM_1) continue friend.befriend(user) + . = ITEM_INTERACT_SUCCESS if(!istype(interacting_with, /obj/structure/beebox)) - return ITEM_INTERACT_BLOCKING + return . var/obj/structure/beebox/hive = interacting_with for(var/mob/living/bee as anything in hive.bees) if(bee.flags_1 & HOLOGRAM_1) continue bee.befriend(user) - return ITEM_INTERACT_SUCCESS + . = ITEM_INTERACT_SUCCESS + + return . /obj/item/bee_smoker/attackby(obj/item/herb, mob/living/carbon/human/user, list/modifiers) . = ..() diff --git a/code/modules/library/bibles.dm b/code/modules/library/bibles.dm index 0c6a1aad71d..4b9b4ae61d1 100644 --- a/code/modules/library/bibles.dm +++ b/code/modules/library/bibles.dm @@ -269,9 +269,6 @@ GLOBAL_LIST_INIT(bibleitemstates, list( playsound(target_mob, SFX_PUNCH, 25, TRUE, -1) log_combat(user, target_mob, "attacked", src) -/obj/item/book/bible/storage_insert_on_interaction(datum/storage, atom/storage_holder, mob/user) - return !istype(storage_holder, /obj/item/book/bible) - /obj/item/book/bible/interact_with_atom(atom/bible_smacked, mob/living/user, list/modifiers) if(SEND_SIGNAL(bible_smacked, COMSIG_BIBLE_SMACKED, user) & COMSIG_END_BIBLE_CHAIN) return ITEM_INTERACT_SUCCESS diff --git a/code/modules/mining/equipment/monster_organs/monster_organ.dm b/code/modules/mining/equipment/monster_organs/monster_organ.dm index 9b6330f3467..cf6131fa922 100644 --- a/code/modules/mining/equipment/monster_organs/monster_organ.dm +++ b/code/modules/mining/equipment/monster_organs/monster_organ.dm @@ -132,6 +132,9 @@ return ..() /obj/item/organ/internal/monster_core/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + if(!isliving(interacting_with)) + return NONE + try_apply(interacting_with, user) return ITEM_INTERACT_SUCCESS diff --git a/code/modules/mining/lavaland/megafauna_loot.dm b/code/modules/mining/lavaland/megafauna_loot.dm index f0270b66d37..94837a4ae48 100644 --- a/code/modules/mining/lavaland/megafauna_loot.dm +++ b/code/modules/mining/lavaland/megafauna_loot.dm @@ -805,10 +805,12 @@ var/timer = 0 var/static/list/banned_turfs = typecacheof(list(/turf/open/space, /turf/closed)) -/obj/item/lava_staff/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) - return interact_with_atom(interacting_with, user, modifiers) - /obj/item/lava_staff/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + if(interacting_with.atom_storage || SHOULD_SKIP_INTERACTION(interacting_with, src, user)) + return NONE + return ranged_interact_with_atom(interacting_with, user, modifiers) + +/obj/item/lava_staff/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(timer > world.time) return NONE if(is_type_in_typecache(interacting_with, banned_turfs)) diff --git a/code/modules/mob/living/basic/minebots/minebot_remote_control.dm b/code/modules/mob/living/basic/minebots/minebot_remote_control.dm index 36019409123..adb6d79e541 100644 --- a/code/modules/mob/living/basic/minebots/minebot_remote_control.dm +++ b/code/modules/mob/living/basic/minebots/minebot_remote_control.dm @@ -44,6 +44,8 @@ user.update_mouse_pointer() /obj/item/minebot_remote_control/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + if(HAS_TRAIT(interacting_with, TRAIT_COMBAT_MODE_SKIP_INTERACTION)) + return NONE return ranged_interact_with_atom(interacting_with, user, modifiers) /obj/item/minebot_remote_control/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) diff --git a/code/modules/mod/mod_control.dm b/code/modules/mod/mod_control.dm index cbd299e8b58..1faadafe0ec 100644 --- a/code/modules/mod/mod_control.dm +++ b/code/modules/mod/mod_control.dm @@ -303,22 +303,12 @@ playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) return ITEM_INTERACT_BLOCKING -/obj/item/mod/control/storage_insert_on_interacted_with(datum/storage, obj/item/inserted, mob/living/user) - // Hack. revisit later - if(istype(inserted, /obj/item/aicard)) - var/obj/item/aicard/ai_card = inserted - if(ai_card.AI) - return FALSE // we want to get an AI assistant, try uploading instead of insertion - if(ai_assistant) - return FALSE // we already have an AI assistant, try withdrawing instead of insertion - return TRUE - // Makes use of tool act to prevent shoving stuff into our internal storage /obj/item/mod/control/tool_act(mob/living/user, obj/item/tool, list/modifiers) if(istype(tool, /obj/item/pai_card)) if(!open) balloon_alert(user, "open the cover first!") - return ITEM_INTERACT_BLOCKING + return NONE // shoves the card in the storage anyways insert_pai(user, tool) return ITEM_INTERACT_SUCCESS if(istype(tool, /obj/item/mod/paint)) diff --git a/code/modules/mod/mod_core.dm b/code/modules/mod/mod_core.dm index 5f93427f532..2c9845afe4c 100644 --- a/code/modules/mod/mod_core.dm +++ b/code/modules/mod/mod_core.dm @@ -97,7 +97,6 @@ install_cell(cell) RegisterSignal(mod, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) RegisterSignal(mod, COMSIG_ATOM_ATTACK_HAND, PROC_REF(on_attack_hand)) - RegisterSignal(mod, COMSIG_ATOM_STORAGE_ITEM_INTERACT_INSERT, PROC_REF(on_mod_storage_insert)) RegisterSignal(mod, COMSIG_ATOM_ITEM_INTERACTION, PROC_REF(on_mod_interaction)) RegisterSignal(mod, COMSIG_MOD_WEARER_SET, PROC_REF(on_wearer_set)) if(mod.wearer) @@ -109,7 +108,6 @@ UnregisterSignal(mod, list( COMSIG_ATOM_EXAMINE, COMSIG_ATOM_ATTACK_HAND, - COMSIG_ATOM_STORAGE_ITEM_INTERACT_INSERT, COMSIG_ATOM_ITEM_INTERACTION, COMSIG_MOD_WEARER_SET, )) @@ -212,17 +210,9 @@ cell_to_move.forceMove(drop_location()) user.put_in_hands(cell_to_move) -/obj/item/mod/core/standard/proc/on_mod_storage_insert(datum/source, obj/item/thing, mob/living/user) - SIGNAL_HANDLER - - return replace_cell(thing, user) ? BLOCK_STORAGE_INSERT : NONE - /obj/item/mod/core/standard/proc/on_mod_interaction(datum/source, mob/living/user, obj/item/thing) SIGNAL_HANDLER - if(mod.atom_storage) // handled by the storage signal - return NONE - return item_interaction(user, thing) /obj/item/mod/core/standard/item_interaction(mob/living/user, obj/item/tool, list/modifiers) @@ -323,11 +313,10 @@ /obj/item/mod/core/plasma/install(obj/item/mod/control/mod_unit) . = ..() - RegisterSignal(mod, COMSIG_ATOM_STORAGE_ITEM_INTERACT_INSERT, PROC_REF(on_mod_storage_insert)) RegisterSignal(mod, COMSIG_ATOM_ITEM_INTERACTION, PROC_REF(on_mod_interaction)) /obj/item/mod/core/plasma/uninstall() - UnregisterSignal(mod, list(COMSIG_ATOM_STORAGE_ITEM_INTERACT_INSERT, COMSIG_ATOM_ITEM_INTERACTION)) + UnregisterSignal(mod, COMSIG_ATOM_ITEM_INTERACTION) return ..() /obj/item/mod/core/plasma/charge_source() @@ -366,17 +355,9 @@ return "empty" -/obj/item/mod/core/plasma/proc/on_mod_storage_insert(datum/source, obj/item/thing, mob/living/user) - SIGNAL_HANDLER - - return charge_plasma(thing, user) ? BLOCK_STORAGE_INSERT : NONE - /obj/item/mod/core/plasma/proc/on_mod_interaction(datum/source, mob/living/user, obj/item/thing) SIGNAL_HANDLER - if(mod.atom_storage) // handled by the storage signal - return NONE - return item_interaction(thing, user) /obj/item/mod/core/plasma/item_interaction(mob/living/user, obj/item/tool, list/modifiers) diff --git a/code/modules/paperwork/filingcabinet.dm b/code/modules/paperwork/filingcabinet.dm index 41d9aabb54a..f297d76b9e0 100644 --- a/code/modules/paperwork/filingcabinet.dm +++ b/code/modules/paperwork/filingcabinet.dm @@ -56,7 +56,7 @@ icon_state = "[initial(icon_state)]-open" sleep(0.5 SECONDS) icon_state = initial(icon_state) - else if(!user.combat_mode) + else if(!user.combat_mode || (P.item_flags & NOBLUDGEON)) to_chat(user, span_warning("You can't put [P] in [src]!")) else return ..() diff --git a/code/modules/paperwork/handlabeler.dm b/code/modules/paperwork/handlabeler.dm index 98f6662f8c5..5d6b10c0568 100644 --- a/code/modules/paperwork/handlabeler.dm +++ b/code/modules/paperwork/handlabeler.dm @@ -116,9 +116,6 @@ labels_left = initial(labels_left) //Yes, it's capped at its initial value return ITEM_INTERACT_SUCCESS -/obj/item/hand_labeler/storage_insert_on_interaction(datum/storage, atom/storage_holder, mob/user) - return !mode - /obj/item/hand_labeler/borg name = "cyborg-hand labeler" diff --git a/code/modules/photography/camera/camera.dm b/code/modules/photography/camera/camera.dm index 5814750dab1..eb29ca4b8b5 100644 --- a/code/modules/photography/camera/camera.dm +++ b/code/modules/photography/camera/camera.dm @@ -129,6 +129,10 @@ return TRUE /obj/item/camera/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + // Always skip on storage and tables + if(HAS_TRAIT(interacting_with, TRAIT_COMBAT_MODE_SKIP_INTERACTION)) + return NONE + return ranged_interact_with_atom(interacting_with, user, modifiers) /obj/item/camera/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm index b288fd6aa87..90aed008763 100644 --- a/code/modules/power/singularity/emitter.dm +++ b/code/modules/power/singularity/emitter.dm @@ -504,6 +504,8 @@ ADD_TRAIT(src, TRAIT_NODROP, ABSTRACT_ITEM_TRAIT) /obj/item/turret_control/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + if(HAS_TRAIT(interacting_with, TRAIT_COMBAT_MODE_SKIP_INTERACTION)) + return NONE return ranged_interact_with_atom(interacting_with, user, modifiers) /obj/item/turret_control/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) diff --git a/code/modules/reagents/chemistry/machinery/portable_chem_mixer.dm b/code/modules/reagents/chemistry/machinery/portable_chem_mixer.dm index 21f23a209b6..8071887f852 100644 --- a/code/modules/reagents/chemistry/machinery/portable_chem_mixer.dm +++ b/code/modules/reagents/chemistry/machinery/portable_chem_mixer.dm @@ -100,18 +100,18 @@ /obj/item/storage/portable_chem_mixer/ex_act(severity, target) return severity > EXPLODE_LIGHT ? ..() : FALSE -/obj/item/storage/portable_chem_mixer/storage_insert_on_interacted_with(datum/storage, obj/item/weapon, mob/living/user) +/obj/item/storage/portable_chem_mixer/item_interaction(mob/living/user, obj/item/tool, list/modifiers) if (!atom_storage.locked || \ - (weapon.item_flags & ABSTRACT) || \ - (weapon.flags_1 & HOLOGRAM_1) || \ - !is_reagent_container(weapon) || \ - !weapon.is_open_container() \ + (tool.item_flags & ABSTRACT) || \ + (tool.flags_1 & HOLOGRAM_1) || \ + !is_reagent_container(tool) || \ + !tool.is_open_container() \ ) - return TRUE //continue with regular insertion + return NONE // continue with regular storage handling - replace_beaker(user, weapon) + replace_beaker(user, tool) update_appearance() - return FALSE //block insertion cause we handled it ourselves + return ITEM_INTERACT_SUCCESS /** * Replaces the beaker of the portable chemical mixer with another beaker, or simply adds the new beaker if none is in currently @@ -128,7 +128,7 @@ user.put_in_hands(beaker) if(!QDELETED(new_beaker)) - if(!user.transferItemToLoc(new_beaker, src)) + if(!user.transferItemToLoc(new_beaker, src, silent = FALSE)) return beaker = new_beaker diff --git a/code/modules/reagents/reagent_containers/cups/_cup.dm b/code/modules/reagents/reagent_containers/cups/_cup.dm index 5590be84f43..431e1d66c69 100644 --- a/code/modules/reagents/reagent_containers/cups/_cup.dm +++ b/code/modules/reagents/reagent_containers/cups/_cup.dm @@ -142,11 +142,11 @@ /obj/item/reagent_containers/cup/interact_with_atom_secondary(atom/target, mob/living/user, list/modifiers) if(user.combat_mode) - return ITEM_INTERACT_SKIP_TO_ATTACK + return NONE if(!check_allowed_items(target, target_self = TRUE)) return NONE if(!spillable) - return ITEM_INTERACT_BLOCKING + return NONE if(target.is_drainable()) //A dispenser. Transfer FROM it TO us. if(!target.reagents.total_volume) diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm index 4b6ee9c8c78..2149b2fd4c4 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -35,6 +35,9 @@ // (because the desired effect will just work out of the box) if(istype(interacting_with, /obj/structure/sink) || istype(interacting_with, /obj/structure/mop_bucket/janitorialcart) || istype(interacting_with, /obj/machinery/hydroponics)) return NONE + // Always skip on storage and tables + if(HAS_TRAIT(interacting_with, TRAIT_COMBAT_MODE_SKIP_INTERACTION)) + return NONE return try_spray(interacting_with, user) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING diff --git a/code/modules/recycling/conveyor.dm b/code/modules/recycling/conveyor.dm index 0d207ed7e11..82ac4646e05 100644 --- a/code/modules/recycling/conveyor.dm +++ b/code/modules/recycling/conveyor.dm @@ -309,7 +309,7 @@ GLOBAL_LIST_EMPTY(conveyors_by_id) belt_item.use(1) new /obj/machinery/conveyor(target_turf, forwards, id) - else if(!user.combat_mode) + else if(!user.combat_mode || (attacking_item.item_flags & NOBLUDGEON)) user.transferItemToLoc(attacking_item, drop_location()) else return ..() diff --git a/code/modules/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm index 46d023dbfaf..dbcabfab196 100644 --- a/code/modules/recycling/disposal/bin.dm +++ b/code/modules/recycling/disposal/bin.dm @@ -66,6 +66,7 @@ COMSIG_TURF_RECEIVE_SWEEPED_ITEMS = PROC_REF(ready_for_trash), ) AddElement(/datum/element/connect_loc, loc_connections) + ADD_TRAIT(src, TRAIT_COMBAT_MODE_SKIP_INTERACTION, INNATE_TRAIT) return INITIALIZE_HINT_LATELOAD //we need turfs to have air /// Checks if there a connecting trunk diposal pipe under the disposal @@ -128,7 +129,7 @@ deconstruct() return - if(!user.combat_mode) + if(!user.combat_mode || (I.item_flags & NOBLUDGEON)) if((I.item_flags & ABSTRACT) || !user.temporarilyRemoveItemFromInventory(I)) return place_item_in_disposal(I, user) diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm index 6ec7fca37e3..9a416372a28 100644 --- a/code/modules/research/xenobiology/xenobiology.dm +++ b/code/modules/research/xenobiology/xenobiology.dm @@ -910,6 +910,8 @@ if(isitem(interacting_with)) var/obj/item/apply_to = interacting_with if(apply_to.slowdown <= 0 || (apply_to.item_flags & IMMUTABLE_SLOW)) + if(interacting_with.atom_storage) + return NONE // lets us put the potion in the bag to_chat(user, span_warning("The [apply_to] can't be made any faster!")) return ITEM_INTERACT_BLOCKING apply_to.slowdown = 0 @@ -920,15 +922,6 @@ qdel(src) return ITEM_INTERACT_SUCCESS -/obj/item/slimepotion/speed/storage_insert_on_interaction(datum/storage, atom/storage_holder, mob/user) - if(!isitem(storage_holder)) - return TRUE - if(istype(storage_holder, /obj/item/mod/control)) - var/obj/item/mod/control/mod = storage_holder - return mod.slowdown_inactive <= 0 - var/obj/item/storage_item = storage_holder - return storage_item.slowdown <= 0 - /obj/item/slimepotion/fireproof name = "slime chill potion" desc = "A potent chemical mix that will fireproof any article of clothing. Has three uses." diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm index 6586539b1d0..5d2242a6144 100644 --- a/code/modules/shuttle/emergency.dm +++ b/code/modules/shuttle/emergency.dm @@ -767,6 +767,57 @@ name = "emergency disembarkation tool" desc = "For extracting yourself from rough landings." +/datum/storage/pod + max_slots = 14 + max_total_storage = WEIGHT_CLASS_BULKY * 14 + /// If TRUE, we unlock regardless of security level + var/always_unlocked = FALSE + +/datum/storage/pod/open_storage(mob/to_show) + if(isliving(to_show) && SSsecurity_level.get_current_level_as_number() < SEC_LEVEL_RED) + to_chat(to_show, span_warning("The storage unit will only unlock during a Red or Delta security alert.")) + return FALSE + return ..() + +/datum/storage/pod/New(atom/parent, max_slots, max_specific_storage, max_total_storage) + . = ..() + // all of these are a type below what actually spawn with + // (IE all space suits instead of just the emergency ones) + // because an enterprising traitor might be able to hide things, + // like their syndicate toolbox or softsuit. may be fun? + var/static/list/exception_cache = typecacheof(list( + /obj/item/clothing/suit/space, + /obj/item/pickaxe, + /obj/item/storage/toolbox, + )) + src.exception_hold = exception_cache + RegisterSignal(SSsecurity_level, COMSIG_SECURITY_LEVEL_CHANGED, PROC_REF(update_lock)) + update_lock(new_level = SSsecurity_level.get_current_level_as_number()) + +/datum/storage/pod/set_parent(atom/new_parent) + . = ..() + RegisterSignal(parent, COMSIG_ATOM_AFTER_SHUTTLE_MOVE, PROC_REF(pod_launch)) + +/datum/storage/pod/proc/update_lock(datum/source, new_level) + SIGNAL_HANDLER + if(always_unlocked) + return + + locked = (new_level < SEC_LEVEL_RED) ? STORAGE_FULLY_LOCKED : STORAGE_NOT_LOCKED + parent.update_appearance(UPDATE_ICON_STATE) + if(locked) // future todo : make `locked` a setter so this behavior can be built in (avoids exploits) + close_all() + +/datum/storage/pod/proc/pod_launch(datum/source, turf/old_turf) + SIGNAL_HANDLER + // This check is to ignore the movement of the shuttle from the transit level to the station as it is loaded in. + if(old_turf && is_reserved_level(old_turf.z)) + return + // If the pod was launched, the storage will always open. + always_unlocked = TRUE + locked = STORAGE_NOT_LOCKED + parent.update_appearance(UPDATE_ICON_STATE) + /obj/item/storage/pod name = "emergency space suits" desc = "A wall mounted safe containing space suits. Will only open in emergencies." @@ -774,11 +825,11 @@ density = FALSE icon = 'icons/obj/storage/storage.dmi' icon_state = "wall_safe_locked" - var/unlocked = FALSE + storage_type = /datum/storage/pod /obj/item/storage/pod/update_icon_state() . = ..() - icon_state = "wall_safe[unlocked ? "" : "_locked"]" + icon_state = "wall_safe[atom_storage?.locked ? "_locked" : ""]" MAPPING_DIRECTIONAL_HELPERS(/obj/item/storage/pod, 32) @@ -798,30 +849,6 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/item/storage/pod, 32) new /obj/item/bodybag/environmental(src) new /obj/item/bodybag/environmental(src) -/obj/item/storage/pod/storage_insert_on_interacted_with(datum/storage, obj/item/inserted, mob/living/user) - return can_interact(user) - -/obj/item/storage/pod/attack_hand(mob/user, list/modifiers) - if (can_interact(user)) - atom_storage?.show_contents(user) - return TRUE - -/obj/item/storage/pod/attack_hand_secondary(mob/user, list/modifiers) - if(!can_interact(user)) - return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN - return ..() - -/obj/item/storage/pod/click_alt(mob/user) - return CLICK_ACTION_SUCCESS - -/obj/item/storage/pod/can_interact(mob/user) - if(!..()) - return FALSE - if(SSsecurity_level.get_current_level_as_number() >= SEC_LEVEL_RED || unlocked) - return TRUE - to_chat(user, "The storage unit will only unlock during a Red or Delta security alert.") - return FALSE - /obj/docking_port/mobile/emergency/backup name = "backup shuttle" shuttle_id = "backup" diff --git a/code/modules/shuttle/on_move.dm b/code/modules/shuttle/on_move.dm index 4c73b7bd263..5203d7d20e8 100644 --- a/code/modules/shuttle/on_move.dm +++ b/code/modules/shuttle/on_move.dm @@ -109,7 +109,7 @@ All ShuttleMove procs go here // Called on atoms after everything has been moved /atom/movable/proc/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation) - SEND_SIGNAL(src, COMSIG_ATOM_AFTER_SHUTTLE_MOVE) + SEND_SIGNAL(src, COMSIG_ATOM_AFTER_SHUTTLE_MOVE, oldT) if(light) update_light() if(rotation) @@ -250,17 +250,6 @@ All ShuttleMove procs go here GLOB.deliverybeacons += src GLOB.deliverybeacontags += location -/************************************Item move procs************************************/ - -/obj/item/storage/pod/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation) - . = ..() - // If the pod was launched, the storage will always open. The reserved_level check - // ignores the movement of the shuttle from the transit level to - // the station as it is loaded in. - if (oldT && !is_reserved_level(oldT.z)) - unlocked = TRUE - update_appearance() - /************************************Mob move procs************************************/ /mob/onShuttleMove(turf/newT, turf/oldT, list/movement_force, move_dir, obj/docking_port/stationary/old_dock, obj/docking_port/mobile/moving_dock) diff --git a/code/modules/unit_tests/storage.dm b/code/modules/unit_tests/storage.dm index 82ac035ed7e..cadf2261682 100644 --- a/code/modules/unit_tests/storage.dm +++ b/code/modules/unit_tests/storage.dm @@ -20,3 +20,24 @@ small_thing.update_weight_class(WEIGHT_CLASS_BULKY) TEST_ASSERT_NOTEQUAL(small_thing.loc, storage_item, "A small item changed back into bulky size should have ejected from the backpack") + +/datum/unit_test/common_item_inserting + +/datum/unit_test/common_item_inserting/Run() + var/obj/item/storage/backpack/bag = allocate(__IMPLIED_TYPE__, run_loc_floor_bottom_left) + var/mob/living/carbon/human/consistent/dummy = allocate(__IMPLIED_TYPE__, run_loc_floor_bottom_left) + bag.atom_storage.max_slots = INFINITY + bag.atom_storage.max_total_storage = INFINITY + + var/list/common_noncombat_insertion_items = list( + /obj/item/reagent_containers/cup/rag, + /obj/item/soap, + /obj/item/card/emag, + /obj/item/detective_scanner, + ) + + dummy.set_combat_mode(TRUE) + for(var/item_type in common_noncombat_insertion_items) + var/obj/item/item = allocate(item_type, run_loc_floor_bottom_left) + item.melee_attack_chain(dummy, bag) + TEST_ASSERT_EQUAL(item.loc, bag, "[item_type] was unable to be inserted into a backpack on click while off combat mode")