From 8486f2f7e28fecd131c2377abd04ec276980ff95 Mon Sep 17 00:00:00 2001
From: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
Date: Thu, 12 Sep 2024 16:48:19 -0500
Subject: [PATCH] Storage / table interactions at the bottom of the interaction
chain (#85512)
Because the wings were in fact made of wax
## About The Pull Request
Storage goes to the very bottom of the interaction chain, hardcoded in
on `/atom`.
This is not preferred, obviously, but it ends up being a lot less
snowflaking overall.
Tables also go at the very bottom by extending `base_item_interaction`.
Fixes #83742
Fixes #84434
Fixes #83982
Fixes #85516
Fixes #84990
Fixes #84890
Closes #85036
Closes #84025 (RMB places it on the table.)
Closes #86616
Other changes:
Refactored pod storage to be less jank. Patches some exploits around it.
## Why It's Good For The Game
Should make a lot more interactions a lot more reliable... hopefully
## Changelog
:cl: Melbert
refactor: Storage and Tables are now a lower priority action, meaning
some uses of items on storage should work... better, now. Here's hoping
at least, report any oddities.
refactor: Note: For an overwhelming majority of items, **combat mode**
will attempt to attack/insert into the target, while **non-combat-mode**
will attempt to use on a target. This means screwdrivering or emagging a
MODsuit must be done on non-combat-mode, as combat mode will simply put
the screwdriver or emag into its storage. Same applies to tables, though
when in doubt, RMB may help (for things which are also weapons, like
mops).
refactor: Refactored escape pod storage, now they actually properly show
as unlocked on red alert and above.
/:cl:
---
.../signals_atom/signals_atom_x_act.dm | 5 --
code/__DEFINES/tools.dm | 6 ++
code/__DEFINES/traits/declarations.dm | 13 +++
code/_globalvars/traits/_traits.dm | 11 +--
code/datums/components/cleaner.dm | 3 +
code/datums/components/lockable_storage.dm | 1 -
code/datums/storage/storage.dm | 33 ++------
code/game/atom/atom_tool_acts.dm | 38 +++------
code/game/objects/items/climbingrope.dm | 2 +
code/game/objects/items/clown_items.dm | 3 -
code/game/objects/items/control_wand.dm | 8 +-
code/game/objects/items/crayons.dm | 12 ++-
code/game/objects/items/devices/aicard.dm | 16 ++--
.../objects/items/devices/chameleonproj.dm | 47 ++++++-----
.../items/devices/forcefieldprojector.dm | 6 +-
.../objects/items/devices/geiger_counter.dm | 10 +--
.../objects/items/devices/laserpointer.dm | 8 +-
.../objects/items/devices/traitordevices.dm | 9 ---
code/game/objects/items/emags.dm | 8 +-
code/game/objects/items/extinguisher.dm | 10 ++-
code/game/objects/items/machine_wand.dm | 8 +-
code/game/objects/items/rcd/RCD.dm | 23 +++---
code/game/objects/items/religion.dm | 8 +-
code/game/objects/items/stacks/wrap.dm | 9 +--
code/game/objects/items/storage/bags.dm | 10 +--
code/game/objects/items/taster.dm | 2 +-
.../structures/crates_lockers/closets.dm | 2 +-
.../objects/structures/deployable_turret.dm | 6 +-
code/game/objects/structures/tables_racks.dm | 38 ++++-----
.../game/objects/structures/tank_dispenser.dm | 2 +-
.../structures/water_structures/sink.dm | 2 +-
.../water_structures/water_source.dm | 2 +-
.../abductor/equipment/gear/abductor_items.dm | 24 +++---
.../heretic/items/labyrinth_handbook.dm | 8 +-
code/modules/antagonists/spy/spy_bounty.dm | 8 ++
code/modules/antagonists/spy/spy_uplink.dm | 12 +--
.../antagonists/traitor/objectives/steal.dm | 8 +-
.../antagonists/wizard/equipment/artefact.dm | 6 +-
.../antagonists/wizard/equipment/soulstone.dm | 15 ++--
.../clothing/chameleon/chameleon_scanner.dm | 10 ++-
code/modules/detectivework/evidence.dm | 29 ++++---
code/modules/detectivework/scanner.dm | 5 +-
code/modules/fishing/fishing_rod.dm | 2 +-
.../food_and_drinks/machinery/microwave.dm | 24 +++---
.../food_and_drinks/machinery/smartfridge.dm | 2 +-
.../hydroponics/beekeeping/bee_smoker.dm | 15 +++-
code/modules/library/bibles.dm | 3 -
.../equipment/monster_organs/monster_organ.dm | 3 +
.../modules/mining/lavaland/megafauna_loot.dm | 8 +-
.../basic/minebots/minebot_remote_control.dm | 2 +
code/modules/mod/mod_control.dm | 12 +--
code/modules/mod/mod_core.dm | 21 +----
code/modules/paperwork/filingcabinet.dm | 2 +-
code/modules/paperwork/handlabeler.dm | 3 -
code/modules/photography/camera/camera.dm | 4 +
code/modules/power/singularity/emitter.dm | 2 +
.../machinery/portable_chem_mixer.dm | 18 ++---
.../reagents/reagent_containers/cups/_cup.dm | 4 +-
.../reagents/reagent_containers/spray.dm | 3 +
code/modules/recycling/conveyor.dm | 2 +-
code/modules/recycling/disposal/bin.dm | 3 +-
.../research/xenobiology/xenobiology.dm | 11 +--
code/modules/shuttle/emergency.dm | 79 +++++++++++++------
code/modules/shuttle/on_move.dm | 13 +--
code/modules/unit_tests/storage.dm | 21 +++++
65 files changed, 386 insertions(+), 357 deletions(-)
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")