Secure safe, secure briefcase, and vaults improvements (#93085)

Co-authored-by: SmArtKar <44720187+SmArtKar@users.noreply.github.com>
This commit is contained in:
Tim
2025-10-20 08:19:58 -05:00
committed by GitHub
parent f2529991f2
commit 0ee962c4b4
7 changed files with 253 additions and 21 deletions
+64 -2
View File
@@ -18,7 +18,14 @@ FLOOR SAFES
anchored = TRUE
density = TRUE
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
obj_flags = CONDUCTS_ELECTRICITY
interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND | INTERACT_ATOM_UI_INTERACT
custom_materials = list(
/datum/material/metalhydrogen = SHEET_MATERIAL_AMOUNT*10,
/datum/material/alloy/plastitanium = SHEET_MATERIAL_AMOUNT*5,
)
material_flags = MATERIAL_EFFECTS
/// The maximum combined w_class of stuff in the safe
var/maxspace = 24
/// The amount of tumblers that will be generated
@@ -41,14 +48,26 @@ FLOOR SAFES
/obj/structure/safe/Initialize(mapload)
. = ..()
update_appearance(UPDATE_ICON)
var/static/list/tool_behaviors = list(
TOOL_WRENCH = list(
SCREENTIP_CONTEXT_LMB = "Reset lock",
),
)
AddElement(/datum/element/contextual_screentip_tools, tool_behaviors)
// Combination generation
for(var/iterating in 1 to number_of_tumblers)
tumblers.Add(rand(0, 99))
if(!mapload)
if(density)
AddElement(/datum/element/climbable)
AddElement(/datum/element/elevation, pixel_shift = 22)
if(open && !locked)
return
update_appearance(UPDATE_ICON)
// Put as many items on our turf inside as possible
for(var/obj/item/inserting_item in loc)
if(space >= maxspace)
@@ -57,11 +76,46 @@ FLOOR SAFES
space += inserting_item.w_class
inserting_item.forceMove(src)
/obj/structure/safe/examine(mob/user)
. = ..()
. += span_notice("The locking mechanism gears are <b>wrenched</b> in place.")
/obj/structure/safe/update_icon_state()
//uses the same icon as the captain's spare safe (therefore lockable storage) so keep it in line with that
icon_state = "[initial(icon_state)][open ? null : "_locked"]"
return ..()
/obj/structure/safe/wrench_act(mob/living/user, obj/item/tool)
if(!open)
balloon_alert(user, "must be open!")
return ITEM_INTERACT_BLOCKING
balloon_alert(user, "resetting lock...")
to_chat(user, span_notice("You begin resetting the lock for [src]. You'll need to set [number_of_tumblers] numbers."))
var/list/new_tumblers = list()
for(var/tumbler_index in 1 to number_of_tumblers)
var/input_value = tgui_input_number(user, "Set tumbler #[tumbler_index] (0-99):", "Set Lock", 0, 99, 0)
if(isnull(input_value))
balloon_alert(user, "reset cancelled!")
return ITEM_INTERACT_BLOCKING
if(!user.can_perform_action(src))
balloon_alert(user, "reset interrupted!")
return ITEM_INTERACT_BLOCKING
new_tumblers.Add(input_value)
tool.play_tool_sound(src)
if(!do_after(user, 10 SECONDS, target = src))
return ITEM_INTERACT_BLOCKING
tumblers = new_tumblers
current_tumbler_index = 1
dial = 0
tool.play_tool_sound(src)
to_chat(user, span_notice("You successfully reset the lock for [src]. The new combination is: [tumblers.Join("-")]."))
balloon_alert(user, "lock set!")
return ITEM_INTERACT_SUCCESS
/obj/structure/safe/attackby(obj/item/attacking_item, mob/user, list/modifiers, list/attack_modifiers)
if(open)
. = TRUE //no afterattack
@@ -238,6 +292,10 @@ FLOOR SAFES
if(total_ticks == 1 || prob(SOUND_CHANCE))
balloon_alert(user, pick(sounds))
/obj/structure/safe/open
open = TRUE
locked = FALSE
//FLOOR SAFES
/obj/structure/safe/floor
name = "floor safe"
@@ -249,6 +307,10 @@ FLOOR SAFES
. = ..()
AddElement(/datum/element/undertile)
/obj/structure/safe/floor/open
open = TRUE
locked = FALSE
///Special safe for the station's vault. Not explicitly required, but the piggy bank inside it is.
/obj/structure/safe/vault
+97 -6
View File
@@ -6,6 +6,16 @@
base_icon_state = "wall_safe"
result_path = /obj/structure/secure_safe
pixel_shift = 32
w_class = WEIGHT_CLASS_GIGANTIC
obj_flags = CONDUCTS_ELECTRICITY
resistance_flags = FIRE_PROOF
custom_materials = list(
/datum/material/alloy/plasteel = SHEET_MATERIAL_AMOUNT*5,
/datum/material/titanium = SHEET_MATERIAL_AMOUNT*3,
)
material_flags = MATERIAL_EFFECTS
/// The lock code transferred from the structure
var/stored_lock_code
/obj/item/wallframe/secure_safe/Initialize(mapload)
. = ..()
@@ -13,12 +23,55 @@
max_specific_storage = WEIGHT_CLASS_GIGANTIC,
max_total_storage = 20,
)
atom_storage.set_locked(STORAGE_FULLY_LOCKED)
if(stored_lock_code && !(obj_flags & EMAGGED))
atom_storage.set_locked(STORAGE_FULLY_LOCKED)
update_appearance()
/obj/item/wallframe/secure_safe/after_attach(obj/attached_to)
/obj/item/wallframe/secure_safe/update_icon_state()
. = ..()
if(obj_flags & EMAGGED)
icon_state = "[base_icon_state]_broken"
else
icon_state = "[base_icon_state][stored_lock_code ? "_locked" : null]"
/obj/item/wallframe/secure_safe/emag_act(mob/user, obj/item/card/emag/emag_card)
. = ..()
if(obj_flags & EMAGGED)
return FALSE
obj_flags |= EMAGGED
visible_message(span_warning("Sparks fly from [src]!"), blind_message = span_hear("You hear a faint electrical spark."))
balloon_alert(user, "lock destroyed")
playsound(src, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
stored_lock_code = null
atom_storage.locked = STORAGE_NOT_LOCKED
update_appearance()
return TRUE
/obj/item/wallframe/secure_safe/after_attach(obj/structure/secure_safe/safe)
if(!istype(safe))
return ..()
for(var/obj/item in contents)
item.forceMove(attached_to)
item.forceMove(safe)
var/datum/component/lockable_storage/storage_component = safe.GetComponent(/datum/component/lockable_storage)
if(stored_lock_code)
storage_component?.set_lock_code(stored_lock_code)
if(obj_flags & EMAGGED)
storage_component?.break_lock()
return ..()
/datum/armor/secure_safe
melee = 30
bullet = 30
laser = 20
energy = 20
bomb = 30
fire = 95
acid = 30
/**
* Wall safes
@@ -33,21 +86,47 @@
base_icon_state = "wall_safe"
anchored = TRUE
density = FALSE
resistance_flags = FIRE_PROOF
obj_flags = CONDUCTS_ELECTRICITY
armor_type = /datum/armor/secure_safe
max_integrity = 300
damage_deflection = 21
custom_materials = list(
/datum/material/alloy/plasteel = SHEET_MATERIAL_AMOUNT*5,
/datum/material/titanium = SHEET_MATERIAL_AMOUNT*3,
)
material_flags = MATERIAL_EFFECTS
/// The lock code used to open the safe
var/stored_lock_code
MAPPING_DIRECTIONAL_HELPERS(/obj/structure/secure_safe, 32)
/obj/structure/secure_safe/Initialize(mapload)
. = ..()
//this will create the storage for us.
AddComponent(/datum/component/lockable_storage)
AddComponent(/datum/component/lockable_storage, stored_lock_code)
if(!density)
find_and_hang_on_wall()
if(mapload)
PopulateContents()
RegisterSignal(src, COMSIG_LOCKABLE_STORAGE_SET_CODE, PROC_REF(update_lock_code))
/obj/structure/secure_safe/atom_deconstruct(disassembled)
if(!density) //if we're a wall item, we'll drop a wall frame.
var/obj/item/wallframe/secure_safe/new_safe = new(get_turf(src))
// Transfer lock code to the wallframe
var/datum/component/lockable_storage/storage_component = GetComponent(/datum/component/lockable_storage)
if(storage_component)
new_safe.stored_lock_code = storage_component.lock_code
if(obj_flags & EMAGGED)
new_safe.obj_flags |= EMAGGED
new_safe.update_appearance()
for(var/obj/item in contents)
item.forceMove(new_safe)
@@ -55,6 +134,16 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/secure_safe, 32)
new /obj/item/paper(src)
new /obj/item/pen(src)
/obj/structure/secure_safe/proc/update_lock_code(obj/structure/secure_safe/safe, new_code)
SIGNAL_HANDLER
stored_lock_code = new_code
/obj/structure/secure_safe/ex_act(severity, target)
if(severity <= EXPLODE_LIGHT)
return FALSE
return ..()
/obj/structure/secure_safe/hos
name = "head of security's safe"
@@ -77,11 +166,13 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/secure_safe, 32)
icon_state = "spare_safe"
base_icon_state = "spare_safe"
armor_type = /datum/armor/safe_caps_spare
max_integrity = 300
damage_deflection = 30 // prevents stealing the captain's spare using null rods/lavaland monsters/AP projectiles
density = TRUE
anchored_tabletop_offset = 6
custom_materials = list(/datum/material/gold = SMALL_MATERIAL_AMOUNT)
custom_materials = list(
/datum/material/alloy/plasteel = SHEET_MATERIAL_AMOUNT*5,
/datum/material/gold = SHEET_MATERIAL_AMOUNT*3,
)
material_flags = MATERIAL_EFFECTS
/datum/armor/safe_caps_spare