mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-07-21 13:05:36 +01:00
Crate, Closet Refactors & Access Secured Stuff (#74754)
## About The Pull Request This PR is actually 2 parts, one that fixes runtimes with crates & the other that allows secured closets to be crafted along with a secured suit storage unit **Crate Fixes** Fixes #74708 The problem starts here https://github.com/tgstation/tgstation/blob/f1178342084bf89897a46f6ce9dc849233bed21b/code/game/objects/structures/crates_lockers/crates.dm#L31-L34 Not only does this if condition look ugly but it's highly error prone because one single call to `update_appearance()` can cause this to fail, and sure enough if you look at the parent `Initialize()` proc it calls just that https://github.com/tgstation/tgstation/blob/f1178342084bf89897a46f6ce9dc849233bed21b/code/game/objects/structures/crates_lockers/closets.dm#L81-L88 Since we know the appearance is guaranteed to be changed in some way before the if condition gets executed let's check what the final state of the crate would be before this if check https://github.com/tgstation/tgstation/blob/f1178342084bf89897a46f6ce9dc849233bed21b/code/game/objects/structures/crates_lockers/crates.dm#L54-L56 We see that the final icon state depends on the variable `opened` so if we want to place/spawn a crate that is opened at round start we have to ensure that `opened = TRUE` so the `if(icon_state == "[initial(icon_state)]open")` succeeds and does its job correctly. Sadly we did dum shit like this ``` /obj/structure/closet/crate{ icon_state = "crateopen" } ``` throughout the entire code base, we thought backwards and were only concerned in making the closet look open rather than setting its correct variables to actually say that it is opened. because none of these crates actually set `opened = TRUE` the final icon state becomes just "crate" NOT "crateopen" therefore the if condition fails and we add the component https://github.com/tgstation/tgstation/blob/f1178342084bf89897a46f6ce9dc849233bed21b/code/game/objects/structures/crates_lockers/crates.dm#L36-L37 with the wrong parameters, so when closing the closet after_close() removes the component with the wrong arguments https://github.com/tgstation/tgstation/blob/f1178342084bf89897a46f6ce9dc849233bed21b/code/game/objects/structures/crates_lockers/crates.dm#L81-L84 that is does not unregister the signals and readds the component i.e. re-registers the signals causing runtime. The solution just do this ``` /obj/structure/closet/crate/open[mapping helper] ``` To clearly state that you want the closet to be open, that way you don't have to memorize the icon_state for each different type of crate, it's consistent across all crates & you don't get runtimes. And that's exactly what i did everywhere Another issue that is fixed is "Houdini crates" i.e. crates which are open & appear empty but when you close & reopen them magical loot appears, Go ahead walk upto to cargo and find any empty crate that is open and do this Fixes #69779 https://user-images.githubusercontent.com/110812394/232234489-0193acde-22c8-4c19-af89-e897f3c23d53.mp4 You will be surprised, This is seriously harmful to players because they can just walk by a crate that appears to be open & empty only to realize later that it had some awesome loot. Just mean The reason this happens is because of the Late Initialization inside closets https://github.com/tgstation/tgstation/blob/f1178342084bf89897a46f6ce9dc849233bed21b/code/game/objects/structures/crates_lockers/closets.dm#L85-L86 What late initialization does is suck up all stuff on its turf https://github.com/tgstation/tgstation/blob/f1178342084bf89897a46f6ce9dc849233bed21b/code/game/objects/structures/crates_lockers/closets.dm#L97-L100 In theory this is supposed to work perfectly, if the closet is closed move everything on the turf into the closet and so when the player opens it, they all pop back out. But what happens if the closet is opened before ` LateInitialize()` is called? This breaking behaviour is caused by object spawners https://github.com/tgstation/tgstation/blob/f1178342084bf89897a46f6ce9dc849233bed21b/code/game/objects/effects/spawners/random/structure.dm#L94-L100 And maint crates https://github.com/tgstation/tgstation/blob/f1178342084bf89897a46f6ce9dc849233bed21b/code/game/objects/structures/crates_lockers/crates.dm#L141-L143 These 2 spawners open up the crate based on random probability before ` LateInitialize()` is called on the crate and so what happens is the crate is first opened and then stuff on the turf is sucked in causing an open but empty crate to appear. The solution is simple just check again in ` LateInitialize()` if our crate is still closed before we proceed.That's fixed now too **Code Refactors** 1. Introduced 2 new signals COMSIG_CLOSET_PRE/POST CLOSE which are the counter parts for the open signals. hook into them if you ever need to do stuff before & after closing the closet while return BLOCK_CLOSE for COMSIG_CLOSET_PRE_CLOSE if you want to block closing the closet for some reason 2. 2 new procs `before_open()` & `before_close()` which are the counter parts for `after_open()` & `after_close()`. If you need to write checks and do actions before opening the closet or before closing the closet override these procs & not the `open()` & `close()` procs directly **Secured Craftables** This is just a reopened version of #74115 after i accidently merged another branch without resolving the conflicts first so i'll just repaste everything here, since crates & closets are related might as well do all in one 1. **Access secured closets** - **What about them?** **1. Existing System** If you wanted to create a access secured closet with the existing system its an 4 step process - First construct a normal closet - Weld it shut so you can install the airlock electronics - Install the electronics [4 seconds] - Unweld This is a 4 step process which takes time & requires a welding tool **2. New system** Combine the 4 steps into 1 by crafting the secure closet directly  - **Bonus Features** **1. Card reader** The card reader acts as an interface between the airlock electronics & the player. Usually if you want to change access on a locker you have to - Weld the closet shut - Screw driver out the electronics - Change the settings - Install it back - Unweld With a card reader there is no need of a welder & screwdriver. You can change the access of the locker while its operational **How do i install the card reader?** 1. Weld the closet shut 3. Insert card reader with hand 4. To remove the card reader use crowbar or just deconstruct the whole closet with a welding tool 5. Unweld closet **How to change its access?** This will overwrite the settings on your airlock electronics. To do this 1. make sure the closet is first unlocked. This is important so that no random person who doesn't have access to the closet can change its access while its locked. It would be like giving the privilege of changing your current password without first confirming if you know the old password 2. attack/swipe the closet with your PDA. Make sure your ID card is inside the PDA for this to work. You can also just use your ID card directly without a PDA 3. You will get 3 options to decide the new access levels  They work as follows - **Personal**: As the name implies only you can access this locker and no one else. Make sure to have your ID on you at all times cause if you loose it then no one can open it - **Departmental**: This copies the access levels of your ID and will allow people having those exact same access levels. Say you want to create a closet accessible to only miners. Then have an miner choose this option and now only miners can open this closet. If the Hop sets custom access on your ID then only people with those specific access levels can open this closet - **None**: No access, free for all just like a normal closet **Security:** After you have set the access level it is important to lock the access panel with a "multi-tool", so no one else can change it. Unlock the panel again with the "multi-tool" to set the new access type **2. Give your own name & description** To rename the closet or change its description you must first make the closet access type as personel i.e. make it yours, then use an pen to complete the job. You cannot change names of departmental or no access closets because that's vandelism **3. Custom Paint Job** Use airlock painter. Not intuitive but does the job.  **4. Personal closets** Round start personal closets can have their access overridden by a new ID when in it's unlocked state. This is useful if the last person has no use for the closet & someone else wants to use it. - **Why its good for the game?** 1. Having your own personal closet with your own name & description gives you more privacy & security for your belongings so people don't steal your stuff. Personal access is more secure because it requires you to have the physical ID card you used to set this access and not an ID which has the same access levels as your previous ID 2. Make secure closets faster without an welding tool & screw driver 3. Bug fix where electronics could be screwed out from round start secured closets countless times spawning a new airlock electronic each time 2. **Access secured freezers** - **What about them?** The craftable freezer from #73942 has been modified to support secure access. These can be deconstructed with welders just as before  - **How does it work?** The access stuff works exactly the same as secure closets described above. You can rename & change description with pen just like the above described secure closets. No paint job for this. Install card reader with the same steps described above. - **Why it's good for the game?** 1. Make access secured freezers faster without a welder and screwdriver 2. Your own personally named & locked freezer for storing dead bodies is always a good thing 4. **Access secured suit storage unit** - **What about them?** Suit storage units now require airlock electronics for construction. The access levels you set on it will be used to decide 1. If a player can unlock the unit 2. If the player can open the unit after unlocking 3. If the player can disinfect whatever is inside By default all round start suit storage units have free access - **Install card reader** Provides the same functionality as secured closets described above. To install it 1. Open its panel with a screw driver 2. Add a card reader to it with hand 3. Close the panel When you deconstruct the machine the card reader pops back out - **Why it's good for the game?** 1. Having your own access protected and named suit storage unit so random people don't steal your mod suits? Who wouldn't want that.? Provides security for department storage units. 2. If you have the unit locked then you cannot deconstruct the machine with a crowbar providing additional security 3. Fixes #70552 , random people can't open/unlock the suit storage unit without access. You can set personal access to make sure only you can access the unit ## Changelog 🆑 add: Access secured closets. Personal closets can have their access overwritten by an new id in it's unlocked state add: Access secured freezers. add: Access secured suit storage units. fix: Suit storage unit not having access restrictions. fix: airlock electronics not properly getting removed after screwing them out from round start lockers fix: round spawned open crates run timing when closed fix: open crates hiding stuff in plain sight fix: open closets/crates sucking up contents during late initialize causing them appear empty & open /🆑 --------- Co-authored-by: Tim <timothymtorres@gmail.com>
This commit is contained in:
@@ -11,6 +11,10 @@
|
||||
integrity_failure = 0.25
|
||||
armor_type = /datum/armor/structure_closet
|
||||
blocks_emissive = EMISSIVE_BLOCK_GENERIC
|
||||
/// How close being inside of the thing provides complete pressure safety. Must be between 0 and 1!
|
||||
contents_pressure_protection = 0
|
||||
/// How insulated the thing is, for the purposes of calculating body temperature. Must be between 0 and 1!
|
||||
contents_thermal_insulation = 0
|
||||
|
||||
/// The overlay for the closet's door
|
||||
var/obj/effect/overlay/closet_door/door_obj
|
||||
@@ -24,13 +28,13 @@
|
||||
var/door_hinge_x = -6.5
|
||||
/// Amount of time it takes for the door animation to play
|
||||
var/door_anim_time = 1.5 // set to 0 to make the door not animate at all
|
||||
|
||||
/// Paint jobs for this closet, crates are a subtype of closet so they override these values
|
||||
var/list/paint_jobs = TRUE
|
||||
/// Controls whether a door overlay should be applied using the icon_door value as the icon state
|
||||
var/enable_door_overlay = TRUE
|
||||
var/has_opened_overlay = TRUE
|
||||
var/has_closed_overlay = TRUE
|
||||
var/icon_door = null
|
||||
var/secure = FALSE //secure locker or not, also used if overriding a non-secure locker with a secure door overlay to add fancy lights
|
||||
var/opened = FALSE
|
||||
var/welded = FALSE
|
||||
var/locked = FALSE
|
||||
@@ -56,19 +60,23 @@
|
||||
var/delivery_icon = "deliverycloset" //which icon to use when packagewrapped. null to be unwrappable.
|
||||
var/anchorable = TRUE
|
||||
var/icon_welded = "welded"
|
||||
/// How close being inside of the thing provides complete pressure safety. Must be between 0 and 1!
|
||||
contents_pressure_protection = 0
|
||||
/// How insulated the thing is, for the purposes of calculating body temperature. Must be between 0 and 1!
|
||||
contents_thermal_insulation = 0
|
||||
/// Whether a skittish person can dive inside this closet. Disable if opening the closet causes "bad things" to happen or that it leads to a logical inconsistency.
|
||||
var/divable = TRUE
|
||||
/// true whenever someone with the strong pull component (or magnet modsuit module) is dragging this, preventing opening
|
||||
var/strong_grab = FALSE
|
||||
///electronics for access
|
||||
var/obj/item/electronics/airlock/electronics
|
||||
/// secure locker or not, also used if overriding a non-secure locker with a secure door overlay to add fancy lights
|
||||
var/secure = FALSE
|
||||
var/can_install_electronics = TRUE
|
||||
|
||||
var/contents_initialized = FALSE
|
||||
/// is this closet locked by an exclusive id, i.e. your own personal locker
|
||||
var/datum/weakref/id_card = null
|
||||
/// should we prevent furthur access change
|
||||
var/access_locked = FALSE
|
||||
/// is the card reader installed in this machine
|
||||
var/card_reader_installed = FALSE
|
||||
/// access types for card reader
|
||||
var/list/access_choices = TRUE
|
||||
|
||||
/datum/armor/structure_closet
|
||||
melee = 20
|
||||
@@ -81,11 +89,32 @@
|
||||
/obj/structure/closet/Initialize(mapload)
|
||||
. = ..()
|
||||
|
||||
var/static/list/closet_paint_jobs = list(
|
||||
"Cargo" = list("icon_state" = "qm"),
|
||||
"Engineering" = list("icon_state" = "ce"),
|
||||
"Engineering Secure" = list("icon_state" = "eng_secure"),
|
||||
"Radiation" = list("icon_state" = "eng", "icon_door" = "eng_rad"),
|
||||
"Tool Storage" = list("icon_state" = "eng", "icon_door" = "eng_tool"),
|
||||
"Fire Equipment" = list("icon_state" = "fire"),
|
||||
"Emergency" = list("icon_state" = "emergency"),
|
||||
"Hydroponics" = list("icon_state" = "hydro"),
|
||||
"Medical" = list("icon_state" = "med"),
|
||||
"Science" = list("icon_state" = "rd"),
|
||||
"Security" = list("icon_state" = "cap"),
|
||||
"Mining" = list("icon_state" = "mining"),
|
||||
"Virology" = list("icon_state" = "bio_viro"),
|
||||
)
|
||||
if(paint_jobs)
|
||||
paint_jobs = closet_paint_jobs
|
||||
|
||||
if(access_choices)
|
||||
var/static/list/choices = list("Personal", "Departmental", "None")
|
||||
access_choices = choices
|
||||
|
||||
// if closed, any item at the crate's loc is put in the contents
|
||||
if (mapload && !opened)
|
||||
. = INITIALIZE_HINT_LATELOAD
|
||||
|
||||
update_appearance()
|
||||
populate_contents_immediate()
|
||||
var/static/list/loc_connections = list(
|
||||
COMSIG_CARBON_DISARM_COLLIDE = PROC_REF(locker_carbon),
|
||||
@@ -94,10 +123,16 @@
|
||||
AddElement(/datum/element/connect_loc, loc_connections)
|
||||
register_context()
|
||||
|
||||
if(opened)
|
||||
opened = FALSE //nessassary because open() proc will early return if its true
|
||||
if(open(special_effects = FALSE)) //closets which are meant to be open by default dont need to be animated open
|
||||
return
|
||||
update_appearance()
|
||||
|
||||
/obj/structure/closet/LateInitialize()
|
||||
. = ..()
|
||||
|
||||
take_contents()
|
||||
if(!opened)
|
||||
take_contents()
|
||||
|
||||
//USE THIS TO FILL IT, NOT INITIALIZE OR NEW
|
||||
/obj/structure/closet/proc/PopulateContents()
|
||||
@@ -109,8 +144,8 @@
|
||||
return
|
||||
|
||||
/obj/structure/closet/Destroy()
|
||||
id_card = null
|
||||
QDEL_NULL(door_obj)
|
||||
QDEL_NULL(electronics)
|
||||
return ..()
|
||||
|
||||
/obj/structure/closet/update_appearance(updates=ALL)
|
||||
@@ -124,7 +159,6 @@
|
||||
. = ..()
|
||||
if(issupplypod(src))
|
||||
return
|
||||
|
||||
layer = opened ? BELOW_OBJ_LAYER : OBJ_LAYER
|
||||
|
||||
/obj/structure/closet/update_overlays()
|
||||
@@ -134,12 +168,13 @@
|
||||
/obj/structure/closet/proc/closet_update_overlays(list/new_overlays)
|
||||
. = new_overlays
|
||||
if(enable_door_overlay && !is_animating_door)
|
||||
var/overlay_state = isnull(base_icon_state) ? initial(icon_state) : base_icon_state
|
||||
if(opened && has_opened_overlay)
|
||||
var/mutable_appearance/door_overlay = mutable_appearance(icon, "[icon_state]_open", alpha = src.alpha)
|
||||
var/mutable_appearance/door_overlay = mutable_appearance(icon, "[overlay_state]_open", alpha = src.alpha)
|
||||
. += door_overlay
|
||||
door_overlay.overlays += emissive_blocker(door_overlay.icon, door_overlay.icon_state, src, alpha = door_overlay.alpha) // If we don't do this the door doesn't block emissives and it looks weird.
|
||||
else if(has_closed_overlay)
|
||||
. += "[icon_door || icon_state]_door"
|
||||
. += "[icon_door || overlay_state]_door"
|
||||
|
||||
if(opened)
|
||||
return
|
||||
@@ -157,10 +192,10 @@
|
||||
if(vname == NAMEOF(src, opened))
|
||||
if(vval == opened)
|
||||
return FALSE
|
||||
if(vval && !opened && open(null, TRUE))
|
||||
if(vval && !opened && open(force = TRUE))
|
||||
datum_flags |= DF_VAR_EDITED
|
||||
return TRUE
|
||||
else if(!vval && opened && close(null))
|
||||
else if(!vval && opened && close())
|
||||
datum_flags |= DF_VAR_EDITED
|
||||
return TRUE
|
||||
return FALSE
|
||||
@@ -188,6 +223,7 @@
|
||||
|
||||
for(var/step in 0 to num_steps)
|
||||
var/angle = door_anim_angle * (closing ? 1 - (step/num_steps) : (step/num_steps))
|
||||
|
||||
var/matrix/door_transform = get_door_transform(angle)
|
||||
var/door_state
|
||||
var/door_layer
|
||||
@@ -225,13 +261,33 @@
|
||||
|
||||
/obj/structure/closet/examine(mob/user)
|
||||
. = ..()
|
||||
|
||||
. += span_notice("It can be [EXAMINE_HINT("welded")] apart.")
|
||||
. += span_notice("It can be [EXAMINE_HINT("bolted")] to the ground.")
|
||||
|
||||
if(id_card)
|
||||
. += span_notice("It can be [EXAMINE_HINT("marked")] with a pen.")
|
||||
if(can_weld_shut && !welded)
|
||||
. += span_notice("Its can be [EXAMINE_HINT("welded")] shut.")
|
||||
if(welded)
|
||||
. += span_notice("Its [EXAMINE_HINT("welded")] shut.")
|
||||
if(anchorable && !anchored)
|
||||
. += span_notice("It can be [EXAMINE_HINT("bolted")] to the ground.")
|
||||
if(anchored)
|
||||
. += span_notice("Its [EXAMINE_HINT("bolted")] to the ground.")
|
||||
if(length(paint_jobs))
|
||||
. += span_notice("It can be [EXAMINE_HINT("painted")] another texture.")
|
||||
if(HAS_TRAIT(user, TRAIT_SKITTISH) && divable)
|
||||
. += span_notice("If you bump into [p_them()] while running, you will jump inside.")
|
||||
|
||||
if(can_install_electronics)
|
||||
if(!secure)
|
||||
. += span_notice("You can install airlock electronics for access control.")
|
||||
else
|
||||
. += span_notice("Its airlock electronics are [EXAMINE_HINT("screwed")] in place.")
|
||||
if(!card_reader_installed && length(access_choices))
|
||||
. += span_notice("You can install a card reader for furthur access control.")
|
||||
else if(card_reader_installed)
|
||||
. += span_notice("The card reader could be [EXAMINE_HINT("pried")] out.")
|
||||
. += span_notice("Swipe your PDA with an ID card/Just ID to change access levels.")
|
||||
. += span_notice("Use multitool to [access_locked ? "unlock" : "lock"] the access panel.")
|
||||
|
||||
/obj/structure/closet/add_context(atom/source, list/context, obj/item/held_item, mob/user)
|
||||
. = ..()
|
||||
var/screentip_change = FALSE
|
||||
@@ -247,13 +303,45 @@
|
||||
if(opened)
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Deconstruct"
|
||||
else
|
||||
context[SCREENTIP_CONTEXT_LMB] = welded ? "Unweld" : "Weld"
|
||||
screentip_change = TRUE
|
||||
if(!welded && can_weld_shut)
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Weld"
|
||||
screentip_change = TRUE
|
||||
else if(welded)
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Unweld"
|
||||
screentip_change = TRUE
|
||||
|
||||
if(istype(held_item) && held_item.tool_behaviour == TOOL_WRENCH)
|
||||
context[SCREENTIP_CONTEXT_RMB] = anchored ? "Unanchor" : "Anchor"
|
||||
screentip_change = TRUE
|
||||
|
||||
if(!locked && (welded || !can_weld_shut))
|
||||
if(!secure)
|
||||
if(!broken && can_install_electronics && istype(held_item, /obj/item/electronics/airlock))
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Install Electronics"
|
||||
screentip_change = TRUE
|
||||
else
|
||||
if(istype(held_item) && held_item.tool_behaviour == TOOL_SCREWDRIVER)
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Remove Electronics"
|
||||
screentip_change = TRUE
|
||||
if(!card_reader_installed && length(access_choices) && !broken && can_install_electronics && istype(held_item, /obj/item/stock_parts/card_reader))
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Install Reader"
|
||||
screentip_change = TRUE
|
||||
if(card_reader_installed && istype(held_item) && held_item.tool_behaviour == TOOL_CROWBAR)
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Remove Reader"
|
||||
screentip_change = TRUE
|
||||
|
||||
if(!locked && !opened)
|
||||
if(id_card && istype(held_item, /obj/item/pen))
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Rename"
|
||||
screentip_change = TRUE
|
||||
if(secure && card_reader_installed && !broken)
|
||||
if(!access_locked && istype(held_item) && !isnull(held_item.GetID()))
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Change Access"
|
||||
screentip_change = TRUE
|
||||
if(istype(held_item) && istype(held_item) && held_item.tool_behaviour == TOOL_MULTITOOL)
|
||||
context[SCREENTIP_CONTEXT_LMB] = "[access_locked ? "Unlock" : "Lock"] Access Panel"
|
||||
screentip_change = TRUE
|
||||
|
||||
return screentip_change ? CONTEXTUAL_SCREENTIP_SET : NONE
|
||||
|
||||
/obj/structure/closet/CanAllowThrough(atom/movable/mover, border_dir)
|
||||
@@ -267,7 +355,8 @@
|
||||
if(welded || locked)
|
||||
return FALSE
|
||||
if(strong_grab)
|
||||
to_chat(user, span_danger("[pulledby] has an incredibly strong grip on [src], preventing it from opening."))
|
||||
if(user)
|
||||
to_chat(user, span_danger("[pulledby] has an incredibly strong grip on [src], preventing it from opening."))
|
||||
return FALSE
|
||||
var/turf/T = get_turf(src)
|
||||
for(var/mob/living/L in T)
|
||||
@@ -317,25 +406,28 @@
|
||||
var/atom/movable/thing = i
|
||||
thing.atom_storage?.close_all()
|
||||
|
||||
/obj/structure/closet/proc/open(mob/living/user, force = FALSE)
|
||||
if(!can_open(user, force))
|
||||
///Proc to write checks before opening a door
|
||||
/obj/structure/closet/proc/before_open(mob/living/user, force)
|
||||
return TRUE
|
||||
|
||||
/obj/structure/closet/proc/open(mob/living/user, force = FALSE, special_effects = TRUE)
|
||||
if(opened || !can_open(user, force))
|
||||
return FALSE
|
||||
if(opened)
|
||||
return FALSE
|
||||
if(SEND_SIGNAL(src, COMSIG_CLOSET_PRE_OPEN, user, force) & BLOCK_OPEN)
|
||||
if(!before_open(user, force) || (SEND_SIGNAL(src, COMSIG_CLOSET_PRE_OPEN, user, force) & BLOCK_OPEN))
|
||||
return FALSE
|
||||
welded = FALSE
|
||||
locked = FALSE
|
||||
playsound(loc, open_sound, open_sound_volume, TRUE, -3)
|
||||
if(special_effects)
|
||||
playsound(loc, open_sound, open_sound_volume, TRUE, -3)
|
||||
opened = TRUE
|
||||
if(!dense_when_open)
|
||||
set_density(FALSE)
|
||||
dump_contents()
|
||||
animate_door(FALSE)
|
||||
if(special_effects)
|
||||
animate_door(FALSE)
|
||||
update_appearance()
|
||||
|
||||
after_open(user, force)
|
||||
SEND_SIGNAL(src, COMSIG_CLOSET_POST_OPEN, force)
|
||||
SEND_SIGNAL(src, COMSIG_CLOSET_POST_OPEN, user, force)
|
||||
return TRUE
|
||||
|
||||
///Proc to override for effects after opening a door
|
||||
@@ -388,9 +480,15 @@
|
||||
|
||||
return TRUE
|
||||
|
||||
///Proc to write checks before closing a door
|
||||
/obj/structure/closet/proc/before_close(mob/living/user)
|
||||
return TRUE
|
||||
|
||||
/obj/structure/closet/proc/close(mob/living/user)
|
||||
if(!opened || !can_close(user))
|
||||
return FALSE
|
||||
if(!before_close(user) || (SEND_SIGNAL(src, COMSIG_CLOSET_PRE_CLOSE, user) & BLOCK_CLOSE))
|
||||
return FALSE
|
||||
take_contents()
|
||||
playsound(loc, close_sound, close_sound_volume, TRUE, -3)
|
||||
opened = FALSE
|
||||
@@ -398,9 +496,10 @@
|
||||
animate_door(TRUE)
|
||||
update_appearance()
|
||||
after_close(user)
|
||||
SEND_SIGNAL(src, COMSIG_CLOSET_POST_CLOSE, user)
|
||||
return TRUE
|
||||
|
||||
///Proc to override for effects after closing a door
|
||||
///Proc to do effects after closet has closed
|
||||
/obj/structure/closet/proc/after_close(mob/living/user)
|
||||
return
|
||||
|
||||
@@ -417,10 +516,15 @@
|
||||
if (!(flags_1 & NODECONSTRUCT_1))
|
||||
if(ispath(material_drop) && material_drop_amount)
|
||||
new material_drop(loc, material_drop_amount)
|
||||
if (electronics)
|
||||
var/obj/item/electronics/airlock/electronics_ref = electronics
|
||||
electronics = null
|
||||
electronics_ref.forceMove(drop_location())
|
||||
if (secure)
|
||||
var/obj/item/electronics/airlock/electronics = new(drop_location())
|
||||
if(length(req_one_access))
|
||||
electronics.one_access = TRUE
|
||||
electronics.accesses = req_one_access
|
||||
else
|
||||
electronics.accesses = req_access
|
||||
if(card_reader_installed)
|
||||
new /obj/item/stock_parts/card_reader(drop_location())
|
||||
dump_contents()
|
||||
qdel(src)
|
||||
|
||||
@@ -429,6 +533,38 @@
|
||||
if(!broken && !(flags_1 & NODECONSTRUCT_1))
|
||||
bust_open()
|
||||
|
||||
/obj/structure/closet/CheckParts(list/parts_list)
|
||||
var/obj/item/electronics/airlock/access_control = locate() in parts_list
|
||||
if(QDELETED(access_control))
|
||||
return
|
||||
|
||||
if (access_control.one_access)
|
||||
req_one_access = access_control.accesses
|
||||
req_access = null
|
||||
else
|
||||
req_access = access_control.accesses
|
||||
req_one_access = null
|
||||
access_control.moveToNullspace()
|
||||
|
||||
parts_list -= access_control
|
||||
qdel(access_control)
|
||||
|
||||
/obj/structure/closet/multitool_act(mob/living/user, obj/item/tool)
|
||||
if(!secure || !card_reader_installed || broken || locked || opened)
|
||||
return
|
||||
access_locked = !access_locked
|
||||
balloon_alert(user, "access panel [access_locked ? "locked" : "unlocked"]")
|
||||
return TRUE
|
||||
|
||||
/// sets the access for the closets from the swiped ID card
|
||||
/obj/structure/closet/proc/set_access(list/accesses)
|
||||
if(length(req_one_access))
|
||||
req_one_access = accesses
|
||||
req_access = null
|
||||
else
|
||||
req_access = accesses
|
||||
req_one_access = null
|
||||
|
||||
/obj/structure/closet/attackby(obj/item/W, mob/user, params)
|
||||
if(user in src)
|
||||
return
|
||||
@@ -437,94 +573,253 @@
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/structure/closet/proc/tool_interact(obj/item/W, mob/living/user)//returns TRUE if attackBy call shouldn't be continued (because tool was used/closet was of wrong type), FALSE if otherwise
|
||||
/// check if we can install airlock electronics in this closet
|
||||
/obj/structure/closet/proc/can_install_airlock_electronics(mob/user)
|
||||
if(secure || !can_install_electronics || !(welded || !can_weld_shut))
|
||||
return FALSE
|
||||
|
||||
if(broken)
|
||||
balloon_alert(user, "its broken!")
|
||||
return FALSE
|
||||
|
||||
if(locked)
|
||||
balloon_alert(user, "unlock first!")
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
/// check if we can unscrew airlock electronics from this closet
|
||||
/obj/structure/closet/proc/can_unscrew_airlock_electronics(mob/user)
|
||||
if(!secure || !(welded || !can_weld_shut))
|
||||
return FALSE
|
||||
|
||||
if(locked)
|
||||
balloon_alert(user, "unlock first!")
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
/// check if we can install card reader in this closet
|
||||
/obj/structure/closet/proc/can_install_card_reader(mob/user)
|
||||
if(card_reader_installed || !can_install_electronics || !length(access_choices) || !(welded || !can_weld_shut))
|
||||
return FALSE
|
||||
|
||||
if(broken)
|
||||
balloon_alert(user, "its broken!")
|
||||
return FALSE
|
||||
|
||||
if(!secure)
|
||||
balloon_alert(user, "no electronics inside!")
|
||||
return FALSE
|
||||
|
||||
if(locked)
|
||||
balloon_alert(user, "unlock first!")
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
/// check if we can pry out the card reader from this closet
|
||||
/obj/structure/closet/proc/can_pryout_card_reader(mob/user)
|
||||
if(!card_reader_installed || !(welded || !can_weld_shut))
|
||||
return FALSE
|
||||
|
||||
if(locked)
|
||||
balloon_alert(user, "unlock first!")
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
/// returns TRUE if attackBy call shouldn't be continued (because tool weaponas used/closet weaponas of weaponrong type), FALSE if otherweaponise
|
||||
/obj/structure/closet/proc/tool_interact(obj/item/weapon, mob/living/user)
|
||||
. = TRUE
|
||||
if(opened)
|
||||
if(istype(W, cutting_tool))
|
||||
if(W.tool_behaviour == TOOL_WELDER)
|
||||
if(!W.tool_start_check(user, amount=0))
|
||||
var/obj/item/card/id/id = null
|
||||
if(!opened && istype(weapon, /obj/item/airlock_painter))
|
||||
if(!length(paint_jobs))
|
||||
return
|
||||
var/choice = tgui_input_list(user, "Set Closet Paintjob", "Paintjob", paint_jobs)
|
||||
if(isnull(choice))
|
||||
return
|
||||
|
||||
var/obj/item/airlock_painter/painter = weapon
|
||||
if(!painter.use_paint(user))
|
||||
return
|
||||
var/list/paint_job = paint_jobs[choice]
|
||||
icon_state = paint_job["icon_state"]
|
||||
base_icon_state = icon_state
|
||||
icon_door = paint_job["icon_door"]
|
||||
|
||||
update_appearance()
|
||||
|
||||
else if(istype(weapon, /obj/item/electronics/airlock) && can_install_airlock_electronics(user))
|
||||
user.visible_message(span_notice("[user] installs the electronics into the [src]."),\
|
||||
span_notice("You start to install electronics into the [src]..."))
|
||||
|
||||
if(!do_after(user, 4 SECONDS, target = src, extra_checks = CALLBACK(src, PROC_REF(can_install_airlock_electronics), user)))
|
||||
return
|
||||
if(!user.transferItemToLoc(weapon, src))
|
||||
return
|
||||
|
||||
CheckParts(list(weapon))
|
||||
secure = TRUE
|
||||
balloon_alert(user, "electronics installed")
|
||||
|
||||
update_appearance()
|
||||
|
||||
else if(weapon.tool_behaviour == TOOL_SCREWDRIVER && can_unscrew_airlock_electronics(user))
|
||||
user.visible_message(span_notice("[user] begins to remove the electronics from the [src]."),\
|
||||
span_notice("You begin to remove the electronics from the [src]..."))
|
||||
|
||||
if (!weapon.use_tool(src, user, 40, volume = 50, extra_checks = CALLBACK(src, PROC_REF(can_unscrew_airlock_electronics), user)))
|
||||
return
|
||||
|
||||
var/obj/item/electronics/airlock/airlock_electronics = new(drop_location())
|
||||
if(length(req_one_access))
|
||||
airlock_electronics.one_access = TRUE
|
||||
airlock_electronics.accesses = req_one_access
|
||||
else
|
||||
airlock_electronics.accesses = req_access
|
||||
|
||||
req_access = list()
|
||||
req_one_access = null
|
||||
id_card = null
|
||||
secure = FALSE
|
||||
balloon_alert(user, "electronics removed")
|
||||
|
||||
update_appearance()
|
||||
|
||||
else if(istype(weapon, /obj/item/stock_parts/card_reader) && can_install_card_reader(user))
|
||||
user.visible_message(span_notice("[user] is installing a card reader."),
|
||||
span_notice("You begin installing the card reader."))
|
||||
|
||||
if(!do_after(user, 4 SECONDS, target = src, extra_checks = CALLBACK(src, PROC_REF(can_install_card_reader), user)))
|
||||
return
|
||||
|
||||
qdel(weapon)
|
||||
card_reader_installed = TRUE
|
||||
|
||||
balloon_alert(user, "card reader installed")
|
||||
|
||||
else if(weapon.tool_behaviour == TOOL_CROWBAR && can_pryout_card_reader(user))
|
||||
user.visible_message(span_notice("[user] begins to pry the card reader out from [src]."),\
|
||||
span_notice("You begin to pry the card reader out from [src]..."))
|
||||
|
||||
if(!weapon.use_tool(src, user, 4 SECONDS, extra_checks = CALLBACK(src, PROC_REF(can_pryout_card_reader), user)))
|
||||
return
|
||||
|
||||
new /obj/item/stock_parts/card_reader(drop_location())
|
||||
card_reader_installed = FALSE
|
||||
|
||||
balloon_alert(user, "card reader removed")
|
||||
|
||||
else if(secure && !broken && card_reader_installed && !locked && !opened && !access_locked && !isnull((id = weapon.GetID())))
|
||||
var/num_choices = length(access_choices)
|
||||
if(!num_choices)
|
||||
return
|
||||
|
||||
var/choice
|
||||
if(num_choices == 1)
|
||||
choice = access_choices[1]
|
||||
else
|
||||
choice = tgui_input_list(user, "Set Access Type", "Access Type", access_choices)
|
||||
if(isnull(choice))
|
||||
return
|
||||
|
||||
id_card = null
|
||||
switch(choice)
|
||||
if("Personal") //only the player weaponho sweaponiped their id has access.
|
||||
id_card = WEAKREF(id)
|
||||
name = "[id.registered_name] locker"
|
||||
desc = "now owned by [id.registered_name]. [initial(desc)]"
|
||||
if("Departmental") //anyone weaponho has the same access permissions as this id has access
|
||||
name = "[id.assignment] closet"
|
||||
desc = "Its a [id.assignment] closet. [initial(desc)]"
|
||||
set_access(id.GetAccess())
|
||||
if("None") //free for all
|
||||
name = initial(name)
|
||||
desc = initial(desc)
|
||||
req_access = list()
|
||||
req_one_access = null
|
||||
set_access(list())
|
||||
|
||||
if(!isnull(id_card))
|
||||
balloon_alert(user, "now owned by [id.registered_name]")
|
||||
else
|
||||
balloon_alert(user, "set to [choice]")
|
||||
|
||||
else if(!opened && istype(weapon, /obj/item/pen))
|
||||
if(locked)
|
||||
balloon_alert(user, "unlock first!")
|
||||
return
|
||||
|
||||
if(isnull(id_card))
|
||||
balloon_alert(user, "not yours to rename!")
|
||||
return
|
||||
|
||||
var/name_set = FALSE
|
||||
var/desc_set = FALSE
|
||||
|
||||
var/str = tgui_input_text(user, "Personal Locker Name", "Locker Name")
|
||||
if(!isnull(str))
|
||||
name = str
|
||||
name_set = TRUE
|
||||
|
||||
str = tgui_input_text(user, "Personal Locker Description", "Locker Description")
|
||||
if(!isnull(str))
|
||||
desc = str
|
||||
desc_set = TRUE
|
||||
|
||||
var/bit_flag = NONE
|
||||
if(name_set)
|
||||
bit_flag |= UPDATE_NAME
|
||||
if(desc_set)
|
||||
bit_flag |= UPDATE_DESC
|
||||
if(bit_flag)
|
||||
update_appearance(bit_flag)
|
||||
|
||||
else if(opened)
|
||||
if(istype(weapon, cutting_tool))
|
||||
if(weapon.tool_behaviour == TOOL_WELDER)
|
||||
if(!weapon.tool_start_check(user, amount=0))
|
||||
return
|
||||
|
||||
to_chat(user, span_notice("You begin cutting \the [src] apart..."))
|
||||
if(W.use_tool(src, user, 40, volume=50))
|
||||
if(weapon.use_tool(src, user, 40, volume=50))
|
||||
if(!opened)
|
||||
return
|
||||
user.visible_message(span_notice("[user] slices apart \the [src]."),
|
||||
span_notice("You cut \the [src] apart with \the [W]."),
|
||||
span_hear("You hear welding."))
|
||||
span_notice("You cut \the [src] apart weaponith \the [weapon]."),
|
||||
span_hear("You hear weaponelding."))
|
||||
deconstruct(TRUE)
|
||||
return
|
||||
else // for example cardboard box is cut with wirecutters
|
||||
else // for example cardboard box is cut weaponith weaponirecutters
|
||||
user.visible_message(span_notice("[user] cut apart \the [src]."), \
|
||||
span_notice("You cut \the [src] apart with \the [W]."))
|
||||
span_notice("You cut \the [src] apart weaponith \the [weapon]."))
|
||||
deconstruct(TRUE)
|
||||
return
|
||||
if (user.combat_mode)
|
||||
return FALSE
|
||||
if(user.transferItemToLoc(W, drop_location())) // so we put in unlit welder too
|
||||
return
|
||||
else if(W.tool_behaviour == TOOL_WELDER && can_weld_shut)
|
||||
if(!W.tool_start_check(user, amount=0))
|
||||
if(user.transferItemToLoc(weapon, drop_location())) // so weapone put in unlit weaponelder too
|
||||
return
|
||||
|
||||
to_chat(user, span_notice("You begin [welded ? "unwelding":"welding"] \the [src]..."))
|
||||
if(W.use_tool(src, user, 40, volume=50))
|
||||
else if(weapon.tool_behaviour == TOOL_WELDER && can_weld_shut)
|
||||
if(!weapon.tool_start_check(user, amount=0))
|
||||
return
|
||||
|
||||
if(weapon.use_tool(src, user, 40, volume=50))
|
||||
if(opened)
|
||||
return
|
||||
welded = !welded
|
||||
after_weld(welded)
|
||||
user.visible_message(span_notice("[user] [welded ? "welds shut" : "unwelded"] \the [src]."),
|
||||
span_notice("You [welded ? "weld" : "unwelded"] \the [src] with \the [W]."),
|
||||
span_notice("You [welded ? "weld" : "unwelded"] \the [src] with \the [weapon]."),
|
||||
span_hear("You hear welding."))
|
||||
user.log_message("[welded ? "welded":"unwelded"] closet [src] with [W]", LOG_GAME)
|
||||
user.log_message("[welded ? "welded":"unwelded"] closet [src] with [weapon]", LOG_GAME)
|
||||
update_appearance()
|
||||
else if (can_install_electronics && istype(W, /obj/item/electronics/airlock)\
|
||||
&& !secure && !electronics && !locked && (welded || !can_weld_shut) && !broken)
|
||||
user.visible_message(span_notice("[user] installs the electronics into the [src]."),\
|
||||
span_notice("You start to install electronics into the [src]..."))
|
||||
if (!do_after(user, 4 SECONDS, target = src))
|
||||
return FALSE
|
||||
if (electronics || secure)
|
||||
return FALSE
|
||||
if (!user.transferItemToLoc(W, src))
|
||||
return FALSE
|
||||
W.moveToNullspace()
|
||||
to_chat(user, span_notice("You install the electronics."))
|
||||
electronics = W
|
||||
if (electronics.one_access)
|
||||
req_one_access = electronics.accesses
|
||||
else
|
||||
req_access = electronics.accesses
|
||||
secure = TRUE
|
||||
update_appearance()
|
||||
else if (can_install_electronics && W.tool_behaviour == TOOL_SCREWDRIVER\
|
||||
&& (secure || electronics) && !locked && (welded || !can_weld_shut))
|
||||
user.visible_message(span_notice("[user] begins to remove the electronics from the [src]."),\
|
||||
span_notice("You begin to remove the electronics from the [src]..."))
|
||||
var/had_electronics = !!electronics
|
||||
var/was_secure = secure
|
||||
if (!do_after(user, 4 SECONDS, target = src))
|
||||
return FALSE
|
||||
if ((had_electronics && !electronics) || (was_secure && !secure))
|
||||
return FALSE
|
||||
var/obj/item/electronics/airlock/electronics_ref
|
||||
if (!electronics)
|
||||
electronics_ref = new /obj/item/electronics/airlock(loc)
|
||||
if (req_one_access.len)
|
||||
electronics_ref.one_access = 1
|
||||
electronics_ref.accesses = req_one_access
|
||||
else
|
||||
electronics_ref.accesses = req_access
|
||||
else
|
||||
electronics_ref = electronics
|
||||
electronics = null
|
||||
electronics_ref.forceMove(drop_location())
|
||||
secure = FALSE
|
||||
update_appearance()
|
||||
|
||||
else if(!user.combat_mode)
|
||||
var/item_is_id = W.GetID()
|
||||
var/item_is_id = weapon.GetID()
|
||||
if(!item_is_id)
|
||||
return FALSE
|
||||
return
|
||||
if((item_is_id || !toggle(user)) && !opened)
|
||||
togglelock(user)
|
||||
else
|
||||
@@ -692,7 +987,7 @@
|
||||
welded = FALSE //applies to all lockers
|
||||
locked = FALSE //applies to critter crates and secure lockers only
|
||||
broken = TRUE //applies to secure lockers only
|
||||
open()
|
||||
open(force = TRUE, special_effects = FALSE)
|
||||
|
||||
/obj/structure/closet/attack_hand_secondary(mob/user, modifiers)
|
||||
. = ..()
|
||||
@@ -705,19 +1000,37 @@
|
||||
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
||||
|
||||
/obj/structure/closet/proc/togglelock(mob/living/user, silent)
|
||||
if(secure && !broken)
|
||||
if(allowed(user))
|
||||
if(iscarbon(user))
|
||||
add_fingerprint(user)
|
||||
balloon_alert_to_viewers(locked ? "unlocked" : "locked")
|
||||
locked = !locked
|
||||
user.visible_message(span_notice("[user] [locked ? null : "un"]locks [src]."),
|
||||
span_notice("You [locked ? null : "un"]lock [src]."))
|
||||
update_appearance()
|
||||
else if(!silent)
|
||||
balloon_alert(user, "access denied!")
|
||||
else if(secure && broken)
|
||||
balloon_alert(user, "broken!")
|
||||
if(!secure || broken)
|
||||
return
|
||||
|
||||
if(locked) //only apply checks while unlocking else allow anyone to lock it
|
||||
var/error_msg = ""
|
||||
if(!isnull(id_card))
|
||||
var/obj/item/card/id/advanced/prisoner/registered_id = id_card.resolve()
|
||||
if(!registered_id) //id was deleted at some point. make this closet public access again
|
||||
name = initial(name)
|
||||
desc = initial(desc)
|
||||
id_card = null
|
||||
req_access = list()
|
||||
req_one_access = null
|
||||
togglelock(user, silent)
|
||||
return
|
||||
if(registered_id != user.get_idcard())
|
||||
error_msg = "not your locker!"
|
||||
else if(!allowed(user)) //allow anyone to lock the closet for safe keeping but apply checks only when unlocking
|
||||
error_msg = "access denied!"
|
||||
if(error_msg)
|
||||
if(!silent)
|
||||
balloon_alert(user, error_msg)
|
||||
return
|
||||
|
||||
if(iscarbon(user))
|
||||
add_fingerprint(user)
|
||||
locked = !locked
|
||||
user.visible_message(span_notice("[user] [locked ? "locks" : "unlocks"][src]."),
|
||||
span_notice("You [locked ? "locked" : "unlocked"] [src]."))
|
||||
update_appearance()
|
||||
|
||||
|
||||
/obj/structure/closet/emag_act(mob/user)
|
||||
if(secure && !broken)
|
||||
@@ -805,4 +1118,7 @@
|
||||
locked = FALSE
|
||||
INVOKE_ASYNC(src, PROC_REF(open))
|
||||
|
||||
/obj/structure/closet/preopen
|
||||
opened = TRUE
|
||||
|
||||
#undef LOCKER_FULL
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
/obj/structure/closet/body_bag
|
||||
name = "body bag"
|
||||
desc = "A plastic bag designed for the storage and transportation of cadavers."
|
||||
@@ -18,11 +17,13 @@
|
||||
drag_slowdown = 0
|
||||
has_closed_overlay = FALSE
|
||||
can_install_electronics = FALSE
|
||||
paint_jobs = null
|
||||
|
||||
///The tagged name of the bodybag, also used to check if the bodybag IS tagged.
|
||||
var/tag_name
|
||||
var/foldedbag_path = /obj/item/bodybag
|
||||
var/obj/item/bodybag/foldedbag_instance = null
|
||||
/// The tagged name of the bodybag, also used to check if the bodybag IS tagged.
|
||||
var/tag_name
|
||||
|
||||
|
||||
/obj/structure/closet/body_bag/Initialize(mapload)
|
||||
. = ..()
|
||||
@@ -72,10 +73,9 @@
|
||||
if(tag_name)
|
||||
. += "bodybag_label"
|
||||
|
||||
/obj/structure/closet/body_bag/close(mob/living/user)
|
||||
/obj/structure/closet/body_bag/after_close(mob/living/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
set_density(FALSE)
|
||||
set_density(FALSE)
|
||||
|
||||
/obj/structure/closet/body_bag/attack_hand_secondary(mob/user, list/modifiers)
|
||||
. = ..()
|
||||
@@ -257,6 +257,18 @@
|
||||
to_chat(the_folder, span_warning("You wrestle with [src], but it won't fold while its straps are fastened."))
|
||||
return ..()
|
||||
|
||||
/obj/structure/closet/body_bag/environmental/prisoner/before_open(mob/living/user, force)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
|
||||
if(sinched && !force)
|
||||
to_chat(user, span_danger("The buckles on [src] are sinched down, preventing it from opening."))
|
||||
return FALSE
|
||||
|
||||
sinched = FALSE //in case it was forced open unsinch it
|
||||
return TRUE
|
||||
|
||||
/obj/structure/closet/body_bag/environmental/prisoner/update_icon()
|
||||
. = ..()
|
||||
if(sinched)
|
||||
@@ -264,22 +276,6 @@
|
||||
else
|
||||
icon_state = initial(icon_state)
|
||||
|
||||
/obj/structure/closet/body_bag/environmental/prisoner/open(mob/living/user, force = FALSE)
|
||||
if(sinched && !force)
|
||||
to_chat(user, span_danger("The buckles on [src] are sinched down, preventing it from opening."))
|
||||
return TRUE
|
||||
if(opened)
|
||||
return FALSE
|
||||
sinched = FALSE
|
||||
playsound(loc, open_sound, open_sound_volume, TRUE, -3)
|
||||
opened = TRUE
|
||||
if(!dense_when_open)
|
||||
set_density(FALSE)
|
||||
dump_contents()
|
||||
update_appearance()
|
||||
after_open(user, force)
|
||||
return TRUE
|
||||
|
||||
/obj/structure/closet/body_bag/environmental/prisoner/container_resist_act(mob/living/user)
|
||||
/// copy-pasted with changes because flavor text as well as some other misc stuff
|
||||
if(opened)
|
||||
@@ -291,7 +287,7 @@
|
||||
location.relay_container_resist_act(user, src)
|
||||
return
|
||||
if(!sinched)
|
||||
open()
|
||||
open(user)
|
||||
return
|
||||
|
||||
user.changeNext_move(CLICK_CD_BREAKOUT)
|
||||
|
||||
@@ -17,15 +17,19 @@
|
||||
close_sound_volume = 35
|
||||
has_closed_overlay = FALSE
|
||||
door_anim_time = 0 // no animation
|
||||
var/move_speed_multiplier = 1
|
||||
var/move_delay = FALSE
|
||||
can_install_electronics = FALSE
|
||||
|
||||
paint_jobs = null
|
||||
/// Cooldown controlling when the box can trigger the Metal Gear Solid-style '!' alert.
|
||||
COOLDOWN_DECLARE(alert_cooldown)
|
||||
|
||||
/// How much time must pass before the box can trigger the next Metal Gear Solid-style '!' alert.
|
||||
var/time_between_alerts = 60 SECONDS
|
||||
/// List of viewers around the box
|
||||
var/list/alerted
|
||||
/// How fast a mob can move inside this box
|
||||
var/move_speed_multiplier = 1
|
||||
/// If the speed multiplier should be applied to mobs inside this box
|
||||
var/move_delay = FALSE
|
||||
|
||||
/obj/structure/closet/cardboard/relaymove(mob/living/user, direction)
|
||||
if(opened || move_delay || user.incapacitated() || !isturf(loc) || !has_gravity(loc))
|
||||
@@ -41,32 +45,34 @@
|
||||
/obj/structure/closet/cardboard/proc/ResetMoveDelay()
|
||||
move_delay = FALSE
|
||||
|
||||
/obj/structure/closet/cardboard/open(mob/living/user, force = FALSE)
|
||||
var/do_alert = (COOLDOWN_FINISHED(src, alert_cooldown) && (locate(/mob/living) in contents))
|
||||
|
||||
if(!do_alert)
|
||||
return ..()
|
||||
|
||||
// Get mobs in view before we open the box.
|
||||
var/list/alerted = list()
|
||||
for(var/mob/living/alerted_mob in viewers(7, src))
|
||||
if(alerted_mob.stat != CONSCIOUS || alerted_mob.is_blind())
|
||||
continue
|
||||
alerted += alerted_mob
|
||||
|
||||
// There are no mobs to alert?
|
||||
if(!length(alerted))
|
||||
return ..()
|
||||
|
||||
/obj/structure/closet/cardboard/before_open(mob/living/user, force)
|
||||
. = ..()
|
||||
|
||||
// Box didn't open?
|
||||
if(!.)
|
||||
return FALSE
|
||||
|
||||
alerted = null
|
||||
var/do_alert = (COOLDOWN_FINISHED(src, alert_cooldown) && (locate(/mob/living) in contents))
|
||||
if(!do_alert)
|
||||
|
||||
return TRUE
|
||||
// Cache the list before we open the box.
|
||||
alerted = viewers(7, src)
|
||||
// There are no mobs to alert? clear the list & prevent furthur action after opening the box
|
||||
if(!(locate(/mob/living) in alerted))
|
||||
alerted = null
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/structure/closet/cardboard/after_open(mob/living/user, force)
|
||||
. = ..()
|
||||
if(!length(alerted))
|
||||
return
|
||||
|
||||
COOLDOWN_START(src, alert_cooldown, time_between_alerts)
|
||||
|
||||
for(var/mob/living/alerted_mob as anything in alerted)
|
||||
if(alerted_mob.stat != CONSCIOUS || alerted_mob.is_blind())
|
||||
continue
|
||||
if(!alerted_mob.incapacitated(IGNORE_RESTRAINTS))
|
||||
alerted_mob.face_atom(src)
|
||||
alerted_mob.do_alert_animation()
|
||||
|
||||
@@ -23,9 +23,9 @@
|
||||
if(replicating_type && !opened && (length(contents) < stop_replicating_at))
|
||||
new replicating_type(src)
|
||||
|
||||
/obj/structure/closet/infinite/open(mob/living/user, force = FALSE)
|
||||
/obj/structure/closet/infinite/after_close(mob/living/user, force)
|
||||
. = ..()
|
||||
if(. && auto_close_time)
|
||||
if(auto_close_time)
|
||||
addtimer(CALLBACK(src, PROC_REF(close_on_my_own)), auto_close_time, TIMER_OVERRIDE | TIMER_UNIQUE)
|
||||
|
||||
/obj/structure/closet/infinite/proc/close_on_my_own()
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
open_sound_volume = 25
|
||||
close_sound_volume = 50
|
||||
door_anim_time = 0 // no animation
|
||||
paint_jobs = null
|
||||
|
||||
/obj/structure/closet/secure_closet/bar/PopulateContents()
|
||||
..()
|
||||
|
||||
@@ -1,11 +1,25 @@
|
||||
/obj/structure/closet/secure_closet/freezer
|
||||
icon_state = "freezer"
|
||||
base_icon_state = "freezer"
|
||||
flags_1 = PREVENT_CONTENTS_EXPLOSION_1
|
||||
door_anim_squish = 0.22
|
||||
door_anim_angle = 123
|
||||
door_anim_time = 4
|
||||
/// If FALSE, we will protect the first person in the freezer from an explosion / nuclear blast.
|
||||
var/jones = FALSE
|
||||
paint_jobs = null
|
||||
|
||||
/obj/structure/closet/secure_closet/freezer/before_open(mob/living/user, force)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
|
||||
toggle_organ_decay(src)
|
||||
return TRUE
|
||||
|
||||
/obj/structure/closet/secure_closet/freezer/after_close(mob/living/user)
|
||||
. = ..()
|
||||
toggle_organ_decay(src)
|
||||
|
||||
/obj/structure/closet/secure_closet/freezer/Destroy()
|
||||
toggle_organ_decay(src)
|
||||
@@ -15,17 +29,6 @@
|
||||
. = ..()
|
||||
toggle_organ_decay(src)
|
||||
|
||||
/obj/structure/closet/secure_closet/freezer/open(mob/living/user, force = FALSE)
|
||||
if(opened || !can_open(user, force)) //dupe check just so we don't let the organs decay when someone fails to open the locker
|
||||
return FALSE
|
||||
toggle_organ_decay(src)
|
||||
return ..()
|
||||
|
||||
/obj/structure/closet/secure_closet/freezer/close(mob/living/user)
|
||||
if(..()) //if we actually closed the locker
|
||||
toggle_organ_decay(src)
|
||||
return TRUE
|
||||
|
||||
/obj/structure/closet/secure_closet/freezer/ex_act()
|
||||
if(jones)
|
||||
return ..()
|
||||
@@ -33,27 +36,11 @@
|
||||
flags_1 &= ~PREVENT_CONTENTS_EXPLOSION_1
|
||||
return FALSE
|
||||
|
||||
/obj/structure/closet/secure_closet/freezer/atom_destruction(damage_flag)
|
||||
new /obj/item/stack/sheet/iron(drop_location(), 1)
|
||||
new /obj/item/assembly/igniter/condenser(drop_location())
|
||||
return ..()
|
||||
|
||||
/obj/structure/closet/secure_closet/freezer/welder_act(mob/living/user, obj/item/tool)
|
||||
/obj/structure/closet/secure_closet/freezer/deconstruct(disassembled)
|
||||
if (!(flags_1 & NODECONSTRUCT_1))
|
||||
new /obj/item/assembly/igniter/condenser(drop_location())
|
||||
. = ..()
|
||||
|
||||
if(!opened)
|
||||
balloon_alert(user, "open it first!")
|
||||
return TRUE
|
||||
|
||||
if(!tool.use_tool(src, user, 40, volume=50))
|
||||
return TRUE
|
||||
|
||||
new /obj/item/stack/sheet/iron(drop_location(), 2)
|
||||
new /obj/item/assembly/igniter/condenser(drop_location())
|
||||
qdel(src)
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/structure/closet/secure_closet/freezer/empty
|
||||
name = "freezer"
|
||||
|
||||
@@ -98,8 +85,8 @@
|
||||
new /obj/item/food/meat/slab/monkey(src)
|
||||
|
||||
/obj/structure/closet/secure_closet/freezer/meat/open
|
||||
req_access = list()
|
||||
locked = FALSE
|
||||
req_access = list()
|
||||
|
||||
/obj/structure/closet/secure_closet/freezer/gulag_fridge
|
||||
name = "refrigerator"
|
||||
@@ -125,6 +112,11 @@
|
||||
req_access = null
|
||||
locked = FALSE
|
||||
|
||||
/obj/structure/closet/secure_closet/freezer/fridge/preopen
|
||||
req_access = null
|
||||
locked = FALSE
|
||||
opened = TRUE
|
||||
|
||||
/obj/structure/closet/secure_closet/freezer/money
|
||||
name = "freezer"
|
||||
desc = "This contains cold hard cash."
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
/obj/structure/closet/secure_closet/personal
|
||||
desc = "It's a secure locker for personnel. The first card swiped gains control."
|
||||
desc = "It's a secure locker for personnel. The first person to open this closet gains control."
|
||||
name = "personal closet"
|
||||
req_access = list(ACCESS_ALL_PERSONAL_LOCKERS)
|
||||
var/registered_name = null
|
||||
card_reader_installed = TRUE
|
||||
|
||||
/obj/structure/closet/secure_closet/personal/Initialize(mapload)
|
||||
. = ..()
|
||||
var/static/list/choices = list("Personal")
|
||||
access_choices = choices
|
||||
|
||||
/obj/structure/closet/secure_closet/personal/PopulateContents()
|
||||
..()
|
||||
@@ -34,33 +39,3 @@
|
||||
new /obj/item/storage/backpack/satchel/leather/withwallet( src )
|
||||
new /obj/item/instrument/piano_synth(src)
|
||||
new /obj/item/radio/headset( src )
|
||||
|
||||
/obj/structure/closet/secure_closet/personal/attackby(obj/item/W, mob/user, params)
|
||||
var/obj/item/card/id/I = W.GetID()
|
||||
if(istype(I))
|
||||
if(broken)
|
||||
to_chat(user, span_danger("It appears to be broken."))
|
||||
return
|
||||
if(!I || !I.registered_name)
|
||||
return
|
||||
if(allowed(user) || !registered_name || (istype(I) && (registered_name == I.registered_name)))
|
||||
//they can open all lockers, or nobody owns this, or they own this locker
|
||||
locked = !locked
|
||||
update_appearance()
|
||||
|
||||
if(!registered_name)
|
||||
registered_name = I.registered_name
|
||||
desc = "Owned by [I.registered_name]."
|
||||
else
|
||||
to_chat(user, span_danger("Access Denied."))
|
||||
else
|
||||
return ..()
|
||||
|
||||
/obj/structure/closet/secure_closet/personal/allowed(mob/mob_to_check)
|
||||
. = ..()
|
||||
if (. || !ishuman(mob_to_check))
|
||||
return
|
||||
var/mob/living/carbon/human/human_to_check = mob_to_check
|
||||
var/obj/item/card/id/id_card = human_to_check.wear_id?.GetID()
|
||||
if (istype(id_card) && id_card.registered_name == registered_name)
|
||||
return TRUE
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
armor_type = /datum/armor/closet_secure_closet
|
||||
secure = TRUE
|
||||
damage_deflection = 20
|
||||
material_drop_amount = 5
|
||||
|
||||
/datum/armor/closet_secure_closet
|
||||
melee = 30
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/obj/structure/closet/secure_closet/captains
|
||||
name = "captain's locker"
|
||||
req_access = list(ACCESS_CAPTAIN)
|
||||
icon_state = "cap"
|
||||
req_access = list(ACCESS_CAPTAIN)
|
||||
|
||||
/obj/structure/closet/secure_closet/captains/PopulateContents()
|
||||
..()
|
||||
@@ -23,8 +23,8 @@
|
||||
|
||||
/obj/structure/closet/secure_closet/hop
|
||||
name = "head of personnel's locker"
|
||||
req_access = list(ACCESS_HOP)
|
||||
icon_state = "hop"
|
||||
req_access = list(ACCESS_HOP)
|
||||
|
||||
/obj/structure/closet/secure_closet/hop/PopulateContents()
|
||||
..()
|
||||
@@ -47,8 +47,8 @@
|
||||
|
||||
/obj/structure/closet/secure_closet/hos
|
||||
name = "head of security's locker"
|
||||
req_access = list(ACCESS_HOS)
|
||||
icon_state = "hos"
|
||||
req_access = list(ACCESS_HOS)
|
||||
|
||||
/obj/structure/closet/secure_closet/hos/PopulateContents()
|
||||
..()
|
||||
@@ -75,8 +75,8 @@
|
||||
|
||||
/obj/structure/closet/secure_closet/warden
|
||||
name = "warden's locker"
|
||||
req_access = list(ACCESS_ARMORY)
|
||||
icon_state = "warden"
|
||||
req_access = list(ACCESS_ARMORY)
|
||||
|
||||
/obj/structure/closet/secure_closet/warden/PopulateContents()
|
||||
..()
|
||||
@@ -101,8 +101,8 @@
|
||||
|
||||
/obj/structure/closet/secure_closet/security
|
||||
name = "security officer's locker"
|
||||
req_access = list(ACCESS_BRIG)
|
||||
icon_state = "sec"
|
||||
req_access = list(ACCESS_BRIG)
|
||||
|
||||
/obj/structure/closet/secure_closet/security/PopulateContents()
|
||||
..()
|
||||
@@ -150,13 +150,13 @@
|
||||
|
||||
/obj/structure/closet/secure_closet/detective
|
||||
name = "\improper detective's cabinet"
|
||||
req_access = list(ACCESS_DETECTIVE)
|
||||
icon_state = "cabinet"
|
||||
resistance_flags = FLAMMABLE
|
||||
max_integrity = 70
|
||||
door_anim_time = 0 // no animation
|
||||
open_sound = 'sound/machines/wooden_closet_open.ogg'
|
||||
close_sound = 'sound/machines/wooden_closet_close.ogg'
|
||||
req_access = list(ACCESS_DETECTIVE)
|
||||
|
||||
/obj/structure/closet/secure_closet/detective/PopulateContents()
|
||||
..()
|
||||
@@ -183,62 +183,54 @@
|
||||
|
||||
/obj/structure/closet/secure_closet/brig
|
||||
name = "brig locker"
|
||||
req_one_access = list(ACCESS_BRIG)
|
||||
anchored = TRUE
|
||||
req_one_access = list(ACCESS_BRIG)
|
||||
var/id = null
|
||||
|
||||
/obj/structure/closet/secure_closet/brig/genpop
|
||||
name = "genpop storage locker"
|
||||
desc = "Used for storing the belongings of genpop's tourists visiting the locals."
|
||||
|
||||
///Reference to the ID linked to the locker, done by swiping a prisoner ID on it
|
||||
var/datum/weakref/assigned_id_ref = null
|
||||
|
||||
/obj/structure/closet/secure_closet/brig/genpop/Destroy()
|
||||
assigned_id_ref = null
|
||||
return ..()
|
||||
access_choices = FALSE
|
||||
paint_jobs = null
|
||||
|
||||
/obj/structure/closet/secure_closet/brig/genpop/examine(mob/user)
|
||||
. = ..()
|
||||
. += span_notice("<b>Right-click</b> with a Security-level ID to reset [src]'s registered ID.")
|
||||
|
||||
/obj/structure/closet/secure_closet/brig/genpop/attackby(obj/item/card/id/advanced/prisoner/used_id, mob/user, params)
|
||||
. = ..()
|
||||
if(!istype(used_id, /obj/item/card/id/advanced/prisoner))
|
||||
return
|
||||
/obj/structure/closet/secure_closet/brig/genpop/attackby(obj/item/card/id/advanced/prisoner/user_id, mob/user, params)
|
||||
if(!secure || !istype(user_id))
|
||||
return ..()
|
||||
|
||||
if(!assigned_id_ref)
|
||||
if(isnull(id_card))
|
||||
say("Prisoner ID linked to locker.")
|
||||
assigned_id_ref = WEAKREF(used_id)
|
||||
name = "genpop storage locker - [used_id.registered_name]"
|
||||
return
|
||||
var/obj/item/card/id/advanced/prisoner/registered_id = assigned_id_ref.resolve()
|
||||
if(used_id == registered_id)
|
||||
say("Authorized ID detected. Unlocking locker and resetting ID.")
|
||||
locked = FALSE
|
||||
assigned_id_ref = null
|
||||
name = initial(name)
|
||||
update_appearance()
|
||||
id_card = WEAKREF(user_id)
|
||||
name = "genpop storage locker - [user_id.registered_name]"
|
||||
|
||||
/obj/structure/closet/secure_closet/brig/genpop/proc/clear_access()
|
||||
say("Authorized ID detected. Unlocking locker and resetting ID.")
|
||||
locked = FALSE
|
||||
id_card = null
|
||||
name = initial(name)
|
||||
update_appearance()
|
||||
|
||||
/obj/structure/closet/secure_closet/brig/genpop/attackby_secondary(obj/item/card/id/advanced/used_id, mob/user, params)
|
||||
. = ..()
|
||||
if(!secure || !istype(used_id))
|
||||
return ..()
|
||||
|
||||
var/list/id_access = used_id.GetAccess()
|
||||
if(assigned_id_ref && (ACCESS_BRIG in id_access))
|
||||
say("Authorized ID detected. Unlocking locker and resetting ID.")
|
||||
locked = FALSE
|
||||
assigned_id_ref = null
|
||||
name = initial(name)
|
||||
update_appearance()
|
||||
if(!isnull(id_card) && (ACCESS_BRIG in id_access))
|
||||
clear_access()
|
||||
|
||||
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
||||
|
||||
/obj/structure/closet/secure_closet/evidence
|
||||
anchored = TRUE
|
||||
name = "secure evidence closet"
|
||||
req_one_access = list("armory","detective")
|
||||
req_one_access = list(ACCESS_ARMORY, ACCESS_DETECTIVE)
|
||||
|
||||
/obj/structure/closet/secure_closet/brig/PopulateContents()
|
||||
..()
|
||||
|
||||
new /obj/item/clothing/under/rank/prisoner( src )
|
||||
new /obj/item/clothing/under/rank/prisoner/skirt( src )
|
||||
new /obj/item/clothing/shoes/sneakers/orange( src )
|
||||
@@ -265,14 +257,14 @@
|
||||
req_access = list(ACCESS_ARMORY)
|
||||
|
||||
/obj/structure/closet/secure_closet/contraband/heads
|
||||
anchored = TRUE
|
||||
name = "contraband locker"
|
||||
req_access = list(ACCESS_COMMAND)
|
||||
anchored = TRUE
|
||||
|
||||
/obj/structure/closet/secure_closet/armory1
|
||||
name = "armory armor locker"
|
||||
req_access = list(ACCESS_ARMORY)
|
||||
icon_state = "armory"
|
||||
req_access = list(ACCESS_ARMORY)
|
||||
|
||||
/obj/structure/closet/secure_closet/armory1/PopulateContents()
|
||||
..()
|
||||
@@ -291,8 +283,8 @@
|
||||
|
||||
/obj/structure/closet/secure_closet/armory2
|
||||
name = "armory ballistics locker"
|
||||
req_access = list(ACCESS_ARMORY)
|
||||
icon_state = "armory"
|
||||
req_access = list(ACCESS_ARMORY)
|
||||
|
||||
/obj/structure/closet/secure_closet/armory2/PopulateContents()
|
||||
..()
|
||||
@@ -304,8 +296,8 @@
|
||||
|
||||
/obj/structure/closet/secure_closet/armory3
|
||||
name = "armory energy gun locker"
|
||||
req_access = list(ACCESS_ARMORY)
|
||||
icon_state = "armory"
|
||||
req_access = list(ACCESS_ARMORY)
|
||||
|
||||
/obj/structure/closet/secure_closet/armory3/PopulateContents()
|
||||
..()
|
||||
@@ -320,8 +312,8 @@
|
||||
|
||||
/obj/structure/closet/secure_closet/tac
|
||||
name = "armory tac locker"
|
||||
req_access = list(ACCESS_ARMORY)
|
||||
icon_state = "tac"
|
||||
req_access = list(ACCESS_ARMORY)
|
||||
|
||||
/obj/structure/closet/secure_closet/tac/PopulateContents()
|
||||
..()
|
||||
@@ -332,8 +324,8 @@
|
||||
|
||||
/obj/structure/closet/secure_closet/labor_camp_security
|
||||
name = "labor camp security locker"
|
||||
req_access = list(ACCESS_SECURITY)
|
||||
icon_state = "sec"
|
||||
req_access = list(ACCESS_SECURITY)
|
||||
|
||||
/obj/structure/closet/secure_closet/labor_camp_security/PopulateContents()
|
||||
..()
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
name = "armory closet"
|
||||
desc = "Why is this here?"
|
||||
icon_state = "syndicate"
|
||||
armor_type = /datum/armor/closet_syndicate
|
||||
paint_jobs = null
|
||||
|
||||
/datum/armor/closet_syndicate
|
||||
melee = 70
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
desc = "A rectangular steel crate."
|
||||
icon = 'icons/obj/storage/crates.dmi'
|
||||
icon_state = "crate"
|
||||
base_icon_state = "crate"
|
||||
req_access = null
|
||||
can_weld_shut = FALSE
|
||||
horizontal = TRUE
|
||||
@@ -29,13 +30,20 @@
|
||||
var/lid_y = 0
|
||||
|
||||
/obj/structure/closet/crate/Initialize(mapload)
|
||||
AddElement(/datum/element/climbable, climb_time = crate_climb_time, climb_stun = 0) //add element in closed state before parent init opens it(if it does)
|
||||
. = ..()
|
||||
if(icon_state == "[initial(icon_state)]open")
|
||||
opened = TRUE
|
||||
AddElement(/datum/element/climbable, climb_time = crate_climb_time * 0.5, climb_stun = 0)
|
||||
else
|
||||
AddElement(/datum/element/climbable, climb_time = crate_climb_time, climb_stun = 0)
|
||||
update_appearance()
|
||||
|
||||
var/static/list/crate_paint_jobs = list(
|
||||
"Internals" = list("icon_state" = "o2crate"),
|
||||
"Medical" = list("icon_state" = "medicalcrate"),
|
||||
"Radiation" = list("icon_state" = "radiation"),
|
||||
"Hydrophonics" = list("icon_state" = "hydrocrate"),
|
||||
"Science" = list("icon_state" = "scicrate"),
|
||||
"Solar" = list("icon_state" = "engi_e_crate"),
|
||||
"Engineering" = list("icon_state" = "engi_crate")
|
||||
)
|
||||
if(!isnull(paint_jobs))
|
||||
paint_jobs = crate_paint_jobs
|
||||
|
||||
/obj/structure/closet/crate/Destroy()
|
||||
QDEL_NULL(manifest)
|
||||
@@ -52,7 +60,7 @@
|
||||
return TRUE
|
||||
|
||||
/obj/structure/closet/crate/update_icon_state()
|
||||
icon_state = "[initial(icon_state)][opened ? "open" : ""]"
|
||||
icon_state = "[isnull(base_icon_state) ? initial(icon_state) : base_icon_state][opened ? "open" : ""]"
|
||||
return ..()
|
||||
|
||||
/obj/structure/closet/crate/closet_update_overlays(list/new_overlays)
|
||||
@@ -65,6 +73,12 @@
|
||||
. += "securecrater"
|
||||
else if(secure)
|
||||
. += "securecrateg"
|
||||
if(opened && lid_icon_state)
|
||||
var/mutable_appearance/lid = mutable_appearance(icon = lid_icon, icon_state = lid_icon_state)
|
||||
lid.pixel_x = lid_x
|
||||
lid.pixel_y = lid_y
|
||||
lid.layer = layer
|
||||
. += lid
|
||||
|
||||
/obj/structure/closet/crate/attack_hand(mob/user, list/modifiers)
|
||||
. = ..()
|
||||
@@ -77,22 +91,17 @@
|
||||
. = ..()
|
||||
RemoveElement(/datum/element/climbable, climb_time = crate_climb_time, climb_stun = 0)
|
||||
AddElement(/datum/element/climbable, climb_time = crate_climb_time * 0.5, climb_stun = 0)
|
||||
|
||||
/obj/structure/closet/crate/after_close(mob/living/user, force)
|
||||
. = ..()
|
||||
RemoveElement(/datum/element/climbable, climb_time = crate_climb_time * 0.5, climb_stun = 0)
|
||||
AddElement(/datum/element/climbable, climb_time = crate_climb_time, climb_stun = 0)
|
||||
|
||||
|
||||
/obj/structure/closet/crate/open(mob/living/user, force = FALSE)
|
||||
. = ..()
|
||||
if(. && !QDELETED(manifest))
|
||||
to_chat(user, span_notice("The manifest is torn off [src]."))
|
||||
if(!QDELETED(manifest))
|
||||
playsound(src, 'sound/items/poster_ripped.ogg', 75, TRUE)
|
||||
manifest.forceMove(get_turf(src))
|
||||
manifest = null
|
||||
update_appearance()
|
||||
|
||||
/obj/structure/closet/crate/after_close(mob/living/user)
|
||||
. = ..()
|
||||
RemoveElement(/datum/element/climbable, climb_time = crate_climb_time * 0.5, climb_stun = 0)
|
||||
AddElement(/datum/element/climbable, climb_time = crate_climb_time, climb_stun = 0)
|
||||
|
||||
/obj/structure/closet/crate/proc/tear_manifest(mob/user)
|
||||
to_chat(user, span_notice("You tear the manifest off of [src]."))
|
||||
playsound(src, 'sound/items/poster_ripped.ogg', 75, TRUE)
|
||||
@@ -103,20 +112,15 @@
|
||||
manifest = null
|
||||
update_appearance()
|
||||
|
||||
/obj/structure/closet/crate/closet_update_overlays(list/new_overlays)
|
||||
. = new_overlays
|
||||
if(opened && lid_icon_state)
|
||||
var/mutable_appearance/lid = mutable_appearance(icon = lid_icon, icon_state = lid_icon_state)
|
||||
lid.pixel_x = lid_x
|
||||
lid.pixel_y = lid_y
|
||||
lid.layer = layer
|
||||
. += lid
|
||||
. += ..()
|
||||
/obj/structure/closet/crate/preopen
|
||||
opened = TRUE
|
||||
icon_state = "crateopen"
|
||||
|
||||
/obj/structure/closet/crate/coffin
|
||||
name = "coffin"
|
||||
desc = "It's a burial receptacle for the dearly departed."
|
||||
icon_state = "coffin"
|
||||
base_icon_state = "coffin"
|
||||
resistance_flags = FLAMMABLE
|
||||
max_integrity = 70
|
||||
material_drop = /obj/item/stack/sheet/mineral/wood
|
||||
@@ -126,6 +130,7 @@
|
||||
open_sound_volume = 25
|
||||
close_sound_volume = 50
|
||||
can_install_electronics = FALSE
|
||||
paint_jobs = null
|
||||
|
||||
/obj/structure/closet/crate/maint
|
||||
|
||||
@@ -135,12 +140,10 @@
|
||||
var/static/list/possible_crates = RANDOM_CRATE_LOOT
|
||||
|
||||
var/crate_path = pick_weight(possible_crates)
|
||||
|
||||
var/obj/structure/closet/crate = new crate_path(loc)
|
||||
crate.RegisterSignal(crate, COMSIG_CLOSET_POPULATE_CONTENTS, TYPE_PROC_REF(/obj/structure/closet/, populate_with_random_maint_loot))
|
||||
var/obj/structure/closet/crate/random_crate = new crate_path(loc)
|
||||
random_crate.RegisterSignal(random_crate, COMSIG_CLOSET_POPULATE_CONTENTS, TYPE_PROC_REF(/obj/structure/closet/, populate_with_random_maint_loot))
|
||||
if (prob(50))
|
||||
crate.opened = TRUE
|
||||
crate.update_appearance()
|
||||
random_crate.open(null, special_effects = FALSE) //crates spawned as immediatly opened don't need to animate into being opened
|
||||
|
||||
return INITIALIZE_HINT_QDEL
|
||||
|
||||
@@ -172,12 +175,15 @@
|
||||
desc = "An internals crate."
|
||||
name = "internals crate"
|
||||
icon_state = "o2crate"
|
||||
base_icon_state = "o2crate"
|
||||
|
||||
/obj/structure/closet/crate/trashcart //please make this a generic cart path later after things calm down a little
|
||||
desc = "A heavy, metal trashcart with wheels."
|
||||
name = "trash cart"
|
||||
icon_state = "trashcart"
|
||||
base_icon_state = "trashcart"
|
||||
can_install_electronics = FALSE
|
||||
paint_jobs = null
|
||||
|
||||
/obj/structure/closet/crate/trashcart/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change = TRUE)
|
||||
. = ..()
|
||||
@@ -188,36 +194,37 @@
|
||||
name = "laundry cart"
|
||||
desc = "A large cart for hauling around large amounts of laundry."
|
||||
icon_state = "laundry"
|
||||
base_icon_state = "laundry"
|
||||
|
||||
/obj/structure/closet/crate/medical
|
||||
desc = "A medical crate."
|
||||
name = "medical crate"
|
||||
icon_state = "medicalcrate"
|
||||
base_icon_state = "medicalcrate"
|
||||
|
||||
/obj/structure/closet/crate/freezer
|
||||
desc = "A freezer."
|
||||
name = "freezer"
|
||||
icon_state = "freezer"
|
||||
base_icon_state = "freezer"
|
||||
paint_jobs = null
|
||||
|
||||
//Snowflake organ freezer code
|
||||
//Order is important, since we check source, we need to do the check whenever we have all the organs in the crate
|
||||
/obj/structure/closet/crate/freezer/before_open(mob/living/user, force)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
|
||||
/obj/structure/closet/crate/freezer/open(mob/living/user, force = FALSE)
|
||||
toggle_organ_decay(src)
|
||||
..()
|
||||
return TRUE
|
||||
|
||||
/obj/structure/closet/crate/freezer/close()
|
||||
..()
|
||||
/obj/structure/closet/crate/freezer/after_close(mob/living/user)
|
||||
. = ..()
|
||||
toggle_organ_decay(src)
|
||||
|
||||
/obj/structure/closet/crate/freezer/Destroy()
|
||||
toggle_organ_decay(src)
|
||||
return ..()
|
||||
|
||||
/obj/structure/closet/crate/freezer/Initialize(mapload)
|
||||
. = ..()
|
||||
toggle_organ_decay(src)
|
||||
|
||||
/obj/structure/closet/crate/freezer/blood
|
||||
name = "blood freezer"
|
||||
desc = "A freezer containing packs of blood."
|
||||
@@ -255,23 +262,28 @@
|
||||
desc = "A crate with a radiation sign on it."
|
||||
name = "radiation crate"
|
||||
icon_state = "radiation"
|
||||
base_icon_state = "radiation"
|
||||
|
||||
/obj/structure/closet/crate/hydroponics
|
||||
name = "hydroponics crate"
|
||||
desc = "All you need to destroy those pesky weeds and pests."
|
||||
icon_state = "hydrocrate"
|
||||
base_icon_state = "hydrocrate"
|
||||
|
||||
/obj/structure/closet/crate/engineering
|
||||
name = "engineering crate"
|
||||
icon_state = "engi_crate"
|
||||
base_icon_state = "engi_crate"
|
||||
|
||||
/obj/structure/closet/crate/engineering/electrical
|
||||
icon_state = "engi_e_crate"
|
||||
base_icon_state = "engi_e_crate"
|
||||
|
||||
/obj/structure/closet/crate/rcd
|
||||
desc = "A crate for the storage of an RCD."
|
||||
name = "\improper RCD crate"
|
||||
icon_state = "engi_crate"
|
||||
base_icon_state = "engi_crate"
|
||||
|
||||
/obj/structure/closet/crate/rcd/PopulateContents()
|
||||
..()
|
||||
@@ -283,10 +295,12 @@
|
||||
name = "science crate"
|
||||
desc = "A science crate."
|
||||
icon_state = "scicrate"
|
||||
base_icon_state = "scicrate"
|
||||
|
||||
/obj/structure/closet/crate/solarpanel_small
|
||||
name = "budget solar panel crate"
|
||||
icon_state = "engi_e_crate"
|
||||
base_icon_state = "engi_e_crate"
|
||||
|
||||
/obj/structure/closet/crate/solarpanel_small/PopulateContents()
|
||||
..()
|
||||
@@ -319,6 +333,7 @@
|
||||
|
||||
/obj/structure/closet/crate/decorations
|
||||
icon_state = "engi_crate"
|
||||
base_icon_state = "engi_crate"
|
||||
|
||||
/obj/structure/closet/crate/decorations/PopulateContents()
|
||||
. = ..()
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
desc = "A trash bin, place your trash here for the janitor to collect."
|
||||
name = "trash bin"
|
||||
icon_state = "largebins"
|
||||
base_icon_state = "largebins"
|
||||
open_sound = 'sound/effects/bin_open.ogg'
|
||||
close_sound = 'sound/effects/bin_close.ogg'
|
||||
anchored = TRUE
|
||||
horizontal = FALSE
|
||||
delivery_icon = null
|
||||
can_install_electronics = FALSE
|
||||
paint_jobs = null
|
||||
|
||||
/obj/structure/closet/crate/bin/Initialize(mapload)
|
||||
. = ..()
|
||||
|
||||
@@ -5,17 +5,21 @@
|
||||
material_drop = /obj/item/stack/sheet/cardboard
|
||||
material_drop_amount = 4
|
||||
icon_state = "cardboard"
|
||||
base_icon_state = "cardboard"
|
||||
open_sound = 'sound/items/poster_ripped.ogg'
|
||||
close_sound = 'sound/machines/cardboard_box.ogg'
|
||||
open_sound_volume = 25
|
||||
close_sound_volume = 25
|
||||
paint_jobs = null
|
||||
|
||||
/obj/structure/closet/crate/cardboard/mothic
|
||||
name = "\improper Mothic Fleet box"
|
||||
desc = "For holding moths, presumably."
|
||||
icon_state = "cardboard_moth"
|
||||
base_icon_state = "cardboard_moth"
|
||||
|
||||
/obj/structure/closet/crate/cardboard/tiziran
|
||||
name = "\improper Tiziran shipment box"
|
||||
desc = "For holding lizards, presumably."
|
||||
icon_state = "cardboard_tiziran"
|
||||
base_icon_state = "cardboard_tiziran"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
name = "critter crate"
|
||||
desc = "A crate designed for safe transport of animals. It has an oxygen tank for safe transport in space."
|
||||
icon_state = "crittercrate"
|
||||
base_icon_state = "crittercrate"
|
||||
horizontal = FALSE
|
||||
allow_objects = FALSE
|
||||
breakout_time = 600
|
||||
@@ -13,9 +14,10 @@
|
||||
open_sound_volume = 25
|
||||
close_sound_volume = 50
|
||||
contents_pressure_protection = 0.8
|
||||
var/obj/item/tank/internals/emergency_oxygen/tank
|
||||
can_install_electronics = FALSE
|
||||
|
||||
var/obj/item/tank/internals/emergency_oxygen/tank
|
||||
|
||||
/obj/structure/closet/crate/critter/Initialize(mapload)
|
||||
. = ..()
|
||||
tank = new
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
name = "large crate"
|
||||
desc = "A hefty wooden crate. You'll need a crowbar to get it open."
|
||||
icon_state = "largecrate"
|
||||
base_icon_state = "largecrate"
|
||||
density = TRUE
|
||||
pass_flags_self = PASSSTRUCTURE
|
||||
material_drop = /obj/item/stack/sheet/mineral/wood
|
||||
|
||||
@@ -2,13 +2,15 @@
|
||||
desc = "A secure crate."
|
||||
name = "secure crate"
|
||||
icon_state = "securecrate"
|
||||
base_icon_state = "securecrate"
|
||||
secure = TRUE
|
||||
locked = TRUE
|
||||
max_integrity = 500
|
||||
armor_type = /datum/armor/crate_secure
|
||||
var/tamperproof = 0
|
||||
damage_deflection = 25
|
||||
|
||||
var/tamperproof = 0
|
||||
|
||||
/datum/armor/crate_secure
|
||||
melee = 30
|
||||
bullet = 50
|
||||
@@ -39,32 +41,38 @@
|
||||
desc = "A secure weapons crate."
|
||||
name = "weapons crate"
|
||||
icon_state = "weaponcrate"
|
||||
base_icon_state = "weaponcrate"
|
||||
|
||||
/obj/structure/closet/crate/secure/plasma
|
||||
desc = "A secure plasma crate."
|
||||
name = "plasma crate"
|
||||
icon_state = "plasmacrate"
|
||||
base_icon_state = "plasmacrate"
|
||||
|
||||
/obj/structure/closet/crate/secure/gear
|
||||
desc = "A secure gear crate."
|
||||
name = "gear crate"
|
||||
icon_state = "secgearcrate"
|
||||
base_icon_state = "secgearcrate"
|
||||
|
||||
/obj/structure/closet/crate/secure/hydroponics
|
||||
desc = "A crate with a lock on it, painted in the scheme of the station's botanists."
|
||||
name = "secure hydroponics crate"
|
||||
icon_state = "hydrosecurecrate"
|
||||
base_icon_state = "hydrosecurecrate"
|
||||
|
||||
/obj/structure/closet/crate/secure/freezer //for consistency with other "freezer" closets/crates
|
||||
desc = "An insulated crate with a lock on it, used to secure perishables."
|
||||
name = "secure kitchen crate"
|
||||
icon_state = "kitchen_secure_crate"
|
||||
base_icon_state = "kitchen_secure_crate"
|
||||
paint_jobs = null
|
||||
|
||||
/obj/structure/closet/crate/secure/freezer/pizza
|
||||
name = "secure pizza crate"
|
||||
desc = "An insulated crate with a lock on it, used to secure pizza."
|
||||
req_access = list(ACCESS_KITCHEN)
|
||||
tamperproof = 10
|
||||
req_access = list(ACCESS_KITCHEN)
|
||||
|
||||
/obj/structure/closet/crate/secure/freezer/pizza/PopulateContents()
|
||||
. = ..()
|
||||
@@ -74,16 +82,19 @@
|
||||
desc = "A crate with a lock on it, painted in the scheme of the station's engineers."
|
||||
name = "secure engineering crate"
|
||||
icon_state = "engi_secure_crate"
|
||||
base_icon_state = "engi_secure_crate"
|
||||
|
||||
/obj/structure/closet/crate/secure/science
|
||||
name = "secure science crate"
|
||||
desc = "A crate with a lock on it, painted in the scheme of the station's scientists."
|
||||
icon_state = "scisecurecrate"
|
||||
base_icon_state = "scisecurecrate"
|
||||
|
||||
/obj/structure/closet/crate/secure/owned
|
||||
name = "private crate"
|
||||
desc = "A crate cover designed to only open for who purchased its contents."
|
||||
icon_state = "privatecrate"
|
||||
base_icon_state = "privatecrate"
|
||||
///Account of the person buying the crate if private purchasing.
|
||||
var/datum/bank_account/buyer_account
|
||||
///Department of the person buying the crate if buying via the NIRN app.
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
name = "surplus syndicrate"
|
||||
desc = "A conspicuous crate with the Syndicate logo on it. You don't know how to open it."
|
||||
icon_state = "syndicrate"
|
||||
base_icon_state = "syndicrate"
|
||||
max_integrity = 500
|
||||
armor_type = /datum/armor/crate_syndicrate
|
||||
resistance_flags = FIRE_PROOF | ACID_PROOF
|
||||
integrity_failure = 0 //prevents bust_open from activating
|
||||
paint_jobs = null
|
||||
/// variable that only lets the crate open if opened by a key from the uplink
|
||||
var/created_items = FALSE
|
||||
/// this is what will spawn when it is opened with a syndicrate key
|
||||
@@ -18,6 +20,17 @@
|
||||
laser = 50
|
||||
energy = 100
|
||||
|
||||
/obj/structure/closet/crate/syndicrate/before_open(mob/living/user, force)
|
||||
. = ..()
|
||||
if(!.)
|
||||
return FALSE
|
||||
|
||||
if(!broken && !force && !created_items)
|
||||
balloon_alert(user, "locked!")
|
||||
return FALSE
|
||||
|
||||
return TRUE
|
||||
|
||||
/obj/structure/closet/crate/syndicrate/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1)
|
||||
if(created_items)
|
||||
return ..()
|
||||
@@ -46,13 +59,6 @@
|
||||
/obj/structure/closet/crate/syndicrate/attackby_secondary(obj/item/weapon, mob/user, params)
|
||||
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
||||
|
||||
///overwrites default opening behavior until it is unlocked via the syndicrate key
|
||||
/obj/structure/closet/crate/syndicrate/can_open(mob/living/user, force = FALSE)
|
||||
if(!created_items)
|
||||
balloon_alert(user, "locked!")
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
///syndicrate has a unique overlay for being unlocked
|
||||
/obj/structure/closet/crate/syndicrate/closet_update_overlays(list/new_overlays)
|
||||
. = new_overlays
|
||||
@@ -70,7 +76,7 @@
|
||||
. = ..()
|
||||
register_item_context()
|
||||
|
||||
/obj/item/add_item_context(obj/item/source, list/context, atom/target, mob/living/user,)
|
||||
/obj/item/syndicrate_key/add_item_context(obj/item/source, list/context, atom/target, mob/living/user)
|
||||
. = ..()
|
||||
|
||||
var/obj/structure/closet/crate/syndicrate/target_structure = target
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
material_drop = /obj/item/stack/sheet/mineral/wood
|
||||
material_drop_amount = 6
|
||||
icon_state = "wooden"
|
||||
base_icon_state = "wooden"
|
||||
open_sound = 'sound/machines/wooden_closet_open.ogg'
|
||||
close_sound = 'sound/machines/wooden_closet_close.ogg'
|
||||
open_sound_volume = 25
|
||||
close_sound_volume = 50
|
||||
paint_jobs = null
|
||||
|
||||
/obj/structure/closet/crate/wooden/toy
|
||||
name = "toy box"
|
||||
|
||||
Reference in New Issue
Block a user