Machines can now be pried open multiple times and maintain their initial densities (#74163)

## About The Pull Request
These changes fix how machines are pried open with crowbars. Currently,
most machines can be pried open, but many of them have no method for
being closed again. This means they can be pried once, and then never
again (as their internal logic has them stuck in an "open" state).

Additionally, the densities of these machines is also inconsistent, as
density is tied to the procs for opening/closing machines (open =
non-dense, closed = dense). Thus, these new changes allow desired
densities to be passed to `open_machine()` and `close_machine()`, as
well as `default_pry_open()`, meaning that atypical machine densities
can be maintained (e.g. machines that should remain dense when open, or
non-dense when closed).

I've also added a `close_after_pry` boolean parameter to the
`default_pry_open()` proc, which determines whether to immediately close
a machine after opening it. This is useful for machines that don't
really have a use case for remaining open, often lacking a sprite to
represent this state as well.
* Note: Opening and immediately closing machines with this boolean will
still drop their contents onto the floor, but will now immediately
"close" in their logic, allowing for further prying attempts in the
future.

It's worth noting that this implements default density values for these
procs, which match the existing behavior for machines, so as to
(hopefully) not disrupt existing or expected machine behavior.

Two caveats to these changes currently exist:
1. On machines that immediately close after prying, the prying action
can now be spammed to the chat with repeated clicking. I'm uncertain if
this needs some sort of spam protection or if it's fine as is.
2. I've only been able to manually test this code. I'd love to write
unit tests for it, as it affects a lot of different machines, but don't
know where to begin with DM Unit Testing (or which files would be good
examples to reference in the code base).
* Note: I did manually test each and every machine that calls
`default_pry_open()` and they all seem to be working correctly. (Except
for `obj/machinery/plumbing/sender`, but that doesn't seem to need
prying, as it has no contents to drop, only reagents.)

As always, let me know if any improvements/changes should be made.

This closes #26833.

## Why It's Good For The Game
These changes allow crowbar prying to correctly occur multiple times on
any machine, which is intended behavior. It prevents player confusion
that could occur when a machine couldn't be pried open a second time
during a shift, even though it had previously been pried before, forcing
players to question themselves. (Are they missing something? Did they
perform the action a different way last time? Is the machine actually
still powered on instead of off? Etc.)

These changes also maintain the correct density for machines after
prying, preventing scenarios where a machine might behave differently
once it had been pried open. (An example of this was being able to walk
through a smartfridge after prying it open.) Additionally, players are
no longer required to know/use workarounds (such as machine disassembly)
to retrieve a powered-off machine's contents.

Overall, these changes improve consistency around machines, creating
more scenarios where they behave as players would expect.

## Changelog
🆑
fix: machines can now be pried open more than once.
fix: machines now have the correct density when pried open.
/🆑

---------

Co-authored-by: san7890 <the@san7890.com>
This commit is contained in:
Antonio Tosti
2023-03-23 15:19:53 -07:00
committed by GitHub
parent f6a88e8cb3
commit 0e1cedd354
20 changed files with 44 additions and 41 deletions
+9 -6
View File
@@ -326,10 +326,11 @@
* Will update the machine icon and any user interfaces currently open.
* Arguments:
* * drop - Boolean. Whether to drop any stored items in the machine. Does not include components.
* * density - Boolean. Whether to make the object dense when it's open.
*/
/obj/machinery/proc/open_machine(drop = TRUE)
/obj/machinery/proc/open_machine(drop = TRUE, density_to_set = FALSE)
state_open = TRUE
set_density(FALSE)
set_density(density_to_set)
if(drop)
dump_inventory_contents()
update_appearance()
@@ -394,9 +395,9 @@
/obj/machinery/proc/can_be_occupant(atom/movable/occupant_atom)
return occupant_typecache ? is_type_in_typecache(occupant_atom, occupant_typecache) : isliving(occupant_atom)
/obj/machinery/proc/close_machine(atom/movable/target)
/obj/machinery/proc/close_machine(atom/movable/target, density_to_set = TRUE)
state_open = FALSE
set_density(TRUE)
set_density(density_to_set)
if(!target)
for(var/atom in loc)
if (!(can_be_occupant(atom)))
@@ -780,13 +781,15 @@
active_power_usage = initial(active_power_usage) * (1 + parts_energy_rating)
update_current_power_usage()
/obj/machinery/proc/default_pry_open(obj/item/crowbar)
/obj/machinery/proc/default_pry_open(obj/item/crowbar, close_after_pry = FALSE, open_density = FALSE, closed_density = TRUE)
. = !(state_open || panel_open || is_operational || (flags_1 & NODECONSTRUCT_1)) && crowbar.tool_behaviour == TOOL_CROWBAR
if(!.)
return
crowbar.play_tool_sound(src, 50)
visible_message(span_notice("[usr] pries open \the [src]."), span_notice("You pry open \the [src]."))
open_machine()
open_machine(density_to_set = open_density)
if (close_after_pry) //Should it immediately close after prying? (If not, it must be closed elsewhere)
close_machine(density_to_set = closed_density)
/obj/machinery/proc/default_deconstruction_crowbar(obj/item/crowbar, ignore_panel = 0, custom_deconstruct = FALSE)
. = (panel_open || ignore_panel) && !(flags_1 & NODECONSTRUCT_1) && crowbar.tool_behaviour == TOOL_CROWBAR
+3 -3
View File
@@ -91,7 +91,7 @@
return C
return null
/obj/machinery/dna_scannernew/close_machine(mob/living/carbon/user)
/obj/machinery/dna_scannernew/close_machine(mob/living/carbon/user, density_to_set = TRUE)
if(!state_open)
return FALSE
@@ -104,7 +104,7 @@
return TRUE
/obj/machinery/dna_scannernew/open_machine()
/obj/machinery/dna_scannernew/open_machine(density_to_set = FALSE)
if(state_open)
return FALSE
@@ -129,7 +129,7 @@
update_appearance()//..since we're updating the icon here, since the scanner can be unpowered when opened/closed
return
if(default_pry_open(I))
if(default_pry_open(I, close_after_pry = FALSE, open_density = FALSE, closed_density = TRUE))
return
if(default_deconstruction_crowbar(I))
+2 -2
View File
@@ -50,7 +50,7 @@
[span_notice("Removing [bite_size] nutritional units per operation.")]
[span_notice("Requires [nutrient_to_meat] nutritional units per meat slab.")]"}
/obj/machinery/fat_sucker/close_machine(mob/user)
/obj/machinery/fat_sucker/close_machine(mob/user, density_to_set = TRUE)
if(panel_open)
to_chat(user, span_warning("You need to close the maintenance hatch first!"))
return
@@ -65,7 +65,7 @@
addtimer(CALLBACK(src, PROC_REF(start_extracting)), 20, TIMER_OVERRIDE|TIMER_UNIQUE)
update_appearance()
/obj/machinery/fat_sucker/open_machine(mob/user)
/obj/machinery/fat_sucker/open_machine(mob/user, density_to_set = FALSE)
make_meat()
playsound(src, 'sound/machines/click.ogg', 50)
if(processing)
+1 -1
View File
@@ -42,7 +42,7 @@
icon_state = base_icon_state
return ..()
/obj/machinery/harvester/open_machine(drop = TRUE)
/obj/machinery/harvester/open_machine(drop = TRUE, density_to_set = FALSE)
if(panel_open)
return
. = ..()
+1 -1
View File
@@ -245,7 +245,7 @@ Possible to do for anyone motivated enough:
if(default_deconstruction_screwdriver(user, "holopad_open", "holopad0", P))
return
if(default_pry_open(P))
if(default_pry_open(P, close_after_pry = TRUE, closed_density = FALSE))
return
if(default_deconstruction_crowbar(P))
+4 -4
View File
@@ -80,7 +80,7 @@
if(default_deconstruction_screwdriver(user, "borgdecon2", "borgcharger0", P))
return
if(default_pry_open(P))
if(default_pry_open(P, close_after_pry = FALSE, open_density = FALSE, closed_density = TRUE))
return
if(default_deconstruction_crowbar(P))
@@ -93,15 +93,15 @@
/obj/machinery/recharge_station/proc/toggle_open()
if(state_open)
close_machine()
close_machine(density_to_set = TRUE)
else
open_machine()
/obj/machinery/recharge_station/open_machine()
/obj/machinery/recharge_station/open_machine(drop = TRUE, density_to_set = FALSE)
. = ..()
update_use_power(IDLE_POWER_USE)
/obj/machinery/recharge_station/close_machine()
/obj/machinery/recharge_station/close_machine(density_to_set = TRUE)
. = ..()
if(occupant)
update_use_power(ACTIVE_POWER_USE) //It always tries to charge, even if it can't.
+1 -1
View File
@@ -76,7 +76,7 @@
if(default_deconstruction_screwdriver(user, "grinder-oOpen", "grinder-o0", I))
return
if(default_pry_open(I))
if(default_pry_open(I, close_after_pry = TRUE))
return
if(default_deconstruction_crowbar(I))
+2 -2
View File
@@ -94,12 +94,12 @@
if (!state_open)
container_resist_act(user)
/obj/machinery/sleeper/open_machine()
/obj/machinery/sleeper/open_machine(density_to_set = FALSE)
if(!state_open && !panel_open)
flick("[initial(icon_state)]-anim", src)
return ..()
/obj/machinery/sleeper/close_machine(mob/user)
/obj/machinery/sleeper/close_machine(mob/user, density_to_set = TRUE)
if((isnull(user) || istype(user)) && state_open && !panel_open)
flick("[initial(icon_state)]-anim", src)
..()
+2 -2
View File
@@ -416,7 +416,7 @@ GLOBAL_LIST_INIT(dye_registry, list(
new /obj/item/stack/sheet/iron(drop_location(), 2)
qdel(src)
/obj/machinery/washing_machine/open_machine(drop = 1)
..()
/obj/machinery/washing_machine/open_machine(drop = TRUE, density_to_set = FALSE)
. = ..()
set_density(TRUE) //because machinery/open_machine() sets it to FALSE
color_source = null
@@ -153,7 +153,7 @@
close_machine(target)
/obj/machinery/implantchair/close_machine(mob/living/user)
/obj/machinery/implantchair/close_machine(mob/living/user, density_to_set = TRUE)
if((isnull(user) || istype(user)) && state_open)
..(user)
if(auto_inject && ready && ready_implants > 0)
@@ -28,11 +28,11 @@
return
close_machine(target)
/obj/machinery/abductor/experiment/open_machine()
/obj/machinery/abductor/experiment/open_machine(density_to_set = FALSE)
if(!state_open && !panel_open)
..()
/obj/machinery/abductor/experiment/close_machine(mob/target)
/obj/machinery/abductor/experiment/close_machine(mob/target, density_to_set = TRUE)
for(var/A in loc)
if(isabductor(A))
return
@@ -356,16 +356,16 @@
message_cooldown = world.time + 50
to_chat(user, span_warning("[src]'s door won't budge!"))
/obj/machinery/atmospherics/components/unary/cryo_cell/open_machine(drop = FALSE)
/obj/machinery/atmospherics/components/unary/cryo_cell/open_machine(drop = FALSE, density_to_set = FALSE)
if(!state_open && !panel_open)
set_on(FALSE)
for(var/mob/M in contents) //only drop mobs
M.forceMove(get_turf(src))
set_occupant(null)
flick("pod-open-anim", src)
..()
return ..()
/obj/machinery/atmospherics/components/unary/cryo_cell/close_machine(mob/living/carbon/user)
/obj/machinery/atmospherics/components/unary/cryo_cell/close_machine(mob/living/carbon/user, density_to_set = TRUE)
treating_wounds = FALSE
if((isnull(user) || istype(user)) && state_open && !panel_open)
flick("pod-close-anim", src)
@@ -417,7 +417,7 @@
return TOOL_ACT_TOOLTYPE_SUCCESS
/obj/machinery/atmospherics/components/unary/cryo_cell/crowbar_act(mob/living/user, obj/item/tool)
if(on || occupant || state_open)
if(on || state_open)
return FALSE
if(default_pry_open(tool) || default_deconstruction_crowbar(tool))
return TOOL_ACT_TOOLTYPE_SUCCESS
@@ -117,7 +117,7 @@
if(default_deconstruction_screwdriver(user, "grinder_open", "grinder", P))
return
else if(default_pry_open(P))
else if(default_pry_open(P, close_after_pry = TRUE))
return
else if(default_deconstruction_crowbar(P))
@@ -48,7 +48,7 @@ GLOBAL_LIST_EMPTY(monkey_recyclers)
if(default_deconstruction_screwdriver(user, "grinder_open", "grinder", O))
return
if(default_pry_open(O))
if(default_pry_open(O, close_after_pry = TRUE))
return
if(default_deconstruction_crowbar(O))
@@ -87,7 +87,7 @@
if(processing)
to_chat(user, span_warning("[src] is in the process of processing!"))
return TRUE
if(default_deconstruction_screwdriver(user, "processor", "processor1", attacking_item) || default_pry_open(attacking_item) || default_deconstruction_crowbar(attacking_item))
if(default_deconstruction_screwdriver(user, "processor", "processor1", attacking_item) || default_pry_open(attacking_item, close_after_pry = TRUE) || default_deconstruction_crowbar(attacking_item))
return
if(istype(attacking_item, /obj/item/storage/bag/tray))
@@ -88,7 +88,7 @@
SStgui.update_uis(src)
return
if(default_pry_open(O))
if(default_pry_open(O, close_after_pry = TRUE))
return
if(default_deconstruction_crowbar(O))
+1 -1
View File
@@ -100,7 +100,7 @@
if(default_deconstruction_screwdriver(user, "sextractor_open", "sextractor", attacking_item))
return TRUE
if(default_pry_open(attacking_item))
if(default_pry_open(attacking_item, close_after_pry = TRUE))
return TRUE
if(default_deconstruction_crowbar(attacking_item))
@@ -48,7 +48,7 @@
/obj/machinery/skill_station/relaymove(mob/living/user, direction)
open_machine()
/obj/machinery/skill_station/open_machine()
/obj/machinery/skill_station/open_machine(density_to_set = FALSE)
. = ..()
interrupt_operation()
@@ -63,7 +63,7 @@
if(working)
interrupt_operation()
/obj/machinery/skill_station/close_machine(atom/movable/target)
/obj/machinery/skill_station/close_machine(atom/movable/target, density_to_set = TRUE)
. = ..()
if(occupant)
ui_interact(occupant)
@@ -173,13 +173,13 @@
mod_unit = null
open_machine()
/obj/machinery/mod_installer/open_machine()
/obj/machinery/mod_installer/open_machine(density_to_set = FALSE)
if(state_open)
return FALSE
..()
return TRUE
/obj/machinery/mod_installer/close_machine(mob/living/carbon/user)
/obj/machinery/mod_installer/close_machine(mob/living/carbon/user, density_to_set = TRUE)
if(!state_open)
return FALSE
..()
@@ -399,7 +399,7 @@
update_appearance()
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
if (default_pry_open(weapon))
if (default_pry_open(weapon, close_after_pry = FALSE, open_density = FALSE, closed_density = TRUE))
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
if (default_deconstruction_crowbar(weapon))
@@ -452,7 +452,7 @@
say("Occupant has been injected with [bci_to_implant].")
bci_to_implant.Insert(carbon_occupant)
/obj/machinery/bci_implanter/open_machine()
/obj/machinery/bci_implanter/open_machine(drop = TRUE, density_to_set = FALSE)
if(state_open)
return FALSE
@@ -460,7 +460,7 @@
return TRUE
/obj/machinery/bci_implanter/close_machine(mob/living/carbon/user)
/obj/machinery/bci_implanter/close_machine(mob/living/carbon/user, density_to_set = TRUE)
if(!state_open)
return FALSE