From 2068ea9ab53803557b5e48cddbe57205f4c4792e Mon Sep 17 00:00:00 2001 From: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Date: Mon, 8 May 2023 23:12:54 +0530 Subject: [PATCH] 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 ![Screenshot (184)](https://user-images.githubusercontent.com/110812394/235904926-c2ea231c-eba7-45d0-a5af-e0456fdd40bc.png) - **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 ![Screenshot (174)](https://user-images.githubusercontent.com/110812394/233454364-d99a2fb6-9f26-4db3-9fac-a10689955484.png) 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. ![Screenshot (181)](https://user-images.githubusercontent.com/110812394/234202905-00946b88-2513-489d-b0a2-d618a72f3e49.png) **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 ![Screenshot (185)](https://user-images.githubusercontent.com/110812394/235905000-ba165feb-4384-4759-b46b-dba77c9e6ba3.png) - **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 :cl: 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 /:cl: --------- Co-authored-by: Tim --- ..._underground_abandoned_plasma_facility.dmm | 16 +- .../IceRuins/icemoon_underground_mailroom.dmm | 20 +- _maps/RandomRuins/SpaceRuins/bigderelict1.dmm | 24 +- .../SpaceRuins/crashedclownship.dmm | 4 +- _maps/RandomRuins/SpaceRuins/hellfactory.dmm | 4 +- .../RandomRuins/SpaceRuins/mimesvsclowns.dmm | 8 +- _maps/RandomRuins/SpaceRuins/waystation.dmm | 4 +- _maps/RandomZLevels/caves.dmm | 4 +- _maps/RandomZLevels/research.dmm | 4 +- _maps/RandomZLevels/snowdin.dmm | 49 +- .../map_files/Deltastation/DeltaStation2.dmm | 24 +- .../map_files/IceBoxStation/IceBoxStation.dmm | 16 +- _maps/map_files/MetaStation/MetaStation.dmm | 24 +- _maps/map_files/NorthStar/north_star.dmm | 24 +- .../maintenance_modules/dormenginelower_2.dmm | 4 +- _maps/map_files/tramstation/tramstation.dmm | 20 +- _maps/shuttles/emergency_luxury.dmm | 8 +- _maps/shuttles/emergency_pubby.dmm | 4 +- _maps/shuttles/hunter_russian.dmm | 4 +- _maps/shuttles/ruin_caravan_victim.dmm | 4 +- _maps/shuttles/ruin_cyborg_mothership.dmm | 4 +- _maps/shuttles/whiteship_birdshot.dmm | 4 +- _maps/shuttles/whiteship_cere.dmm | 12 +- _maps/shuttles/whiteship_delta.dmm | 8 +- _maps/shuttles/whiteship_meta.dmm | 8 +- _maps/templates/lazy_templates/wizard_den.dmm | 4 +- code/__DEFINES/dcs/signals/signals_object.dm | 6 + code/datums/components/crafting/equipment.dm | 23 +- code/datums/elements/deliver_first.dm | 2 +- code/game/machinery/suit_storage_unit.dm | 268 ++++++++- .../effects/spawners/random/structure.dm | 10 +- .../machines/machine_circuitboards.dm | 3 +- .../objects/items/implants/implant_stealth.dm | 12 +- code/game/objects/items/mail.dm | 13 +- .../structures/crates_lockers/closets.dm | 546 ++++++++++++++---- .../crates_lockers/closets/bodybag.dm | 42 +- .../crates_lockers/closets/cardboardbox.dm | 50 +- .../crates_lockers/closets/infinite.dm | 4 +- .../crates_lockers/closets/secure/bar.dm | 1 + .../crates_lockers/closets/secure/freezer.dm | 54 +- .../crates_lockers/closets/secure/personal.dm | 39 +- .../closets/secure/secure_closets.dm | 1 + .../crates_lockers/closets/secure/security.dm | 78 ++- .../crates_lockers/closets/syndicate.dm | 2 + .../structures/crates_lockers/crates.dm | 99 ++-- .../structures/crates_lockers/crates/bins.dm | 2 + .../crates_lockers/crates/cardboard.dm | 4 + .../crates_lockers/crates/critter.dm | 4 +- .../structures/crates_lockers/crates/large.dm | 1 + .../crates_lockers/crates/secure.dm | 15 +- .../crates_lockers/crates/syndicrate.dm | 22 +- .../crates_lockers/crates/wooden.dm | 2 + code/modules/cargo/supplypod.dm | 5 +- code/modules/jobs/access.dm | 13 +- .../lavalandruin_code/elephantgraveyard.dm | 45 +- code/modules/mining/abandoned_crates.dm | 3 +- .../mining/lavaland/necropolis_chests.dm | 14 +- code/modules/mining/mine_items.dm | 1 + .../hostile/megafauna/colossus.dm | 1 + code/modules/projectiles/projectile/magic.dm | 10 +- 60 files changed, 1062 insertions(+), 642 deletions(-) diff --git a/_maps/RandomRuins/IceRuins/icemoon_underground_abandoned_plasma_facility.dmm b/_maps/RandomRuins/IceRuins/icemoon_underground_abandoned_plasma_facility.dmm index eceda53ecbe..e9f6258fa24 100644 --- a/_maps/RandomRuins/IceRuins/icemoon_underground_abandoned_plasma_facility.dmm +++ b/_maps/RandomRuins/IceRuins/icemoon_underground_abandoned_plasma_facility.dmm @@ -661,9 +661,7 @@ }, /area/ruin/plasma_facility/commons) "kA" = ( -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/item/stack/ore/plasma, /obj/item/stack/ore/plasma, /obj/item/stack/ore/plasma, @@ -1129,9 +1127,7 @@ /area/ruin/plasma_facility/commons) "rS" = ( /obj/effect/turf_decal/bot/left, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/item/stack/sheet/mineral/plasma/thirty, /turf/open/floor/iron/smooth_half{ initial_gas_mix = "ICEMOON_ATMOS" @@ -1148,9 +1144,7 @@ /obj/structure/railing{ dir = 5 }, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/item/stack/sheet/mineral/silver, /obj/item/stack/sheet/mineral/silver, /obj/item/stack/sheet/mineral/silver, @@ -1760,9 +1754,7 @@ "FD" = ( /obj/structure/lattice/catwalk, /obj/structure/railing/corner, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/item/stack/sheet/mineral/uranium/five, /obj/item/stack/sheet/mineral/uranium/five, /obj/item/stack/sheet/mineral/uranium/five, diff --git a/_maps/RandomRuins/IceRuins/icemoon_underground_mailroom.dmm b/_maps/RandomRuins/IceRuins/icemoon_underground_mailroom.dmm index 64c6856d76c..6211bd0ef6d 100644 --- a/_maps/RandomRuins/IceRuins/icemoon_underground_mailroom.dmm +++ b/_maps/RandomRuins/IceRuins/icemoon_underground_mailroom.dmm @@ -104,9 +104,7 @@ /turf/open/floor/iron/smooth_large, /area/ruin/powered/mailroom) "jm" = ( -/obj/structure/closet/crate/mail{ - icon_state = "mailopen" - }, +/obj/structure/closet/crate/mail/preopen, /obj/item/mail/junkmail, /obj/item/mail/junkmail, /obj/item/mail/junkmail, @@ -165,9 +163,7 @@ /turf/open/floor/plating/snowed/smoothed/icemoon, /area/ruin/powered/mailroom) "oU" = ( -/obj/structure/closet/crate/mail{ - icon_state = "mailopen" - }, +/obj/structure/closet/crate/mail/preopen, /obj/item/mail/junkmail, /obj/item/mail/junkmail, /turf/open/floor/plating/snowed/smoothed/icemoon, @@ -317,9 +313,7 @@ }, /area/ruin/powered/mailroom) "Jd" = ( -/obj/structure/closet/crate/mail{ - icon_state = "mailopen" - }, +/obj/structure/closet/crate/mail/preopen, /obj/effect/turf_decal/siding/yellow, /obj/item/mail/junkmail, /obj/item/mail/junkmail, @@ -413,9 +407,7 @@ /turf/open/misc/grass, /area/ruin/powered/mailroom) "Qb" = ( -/obj/structure/closet/crate/mail{ - icon_state = "mailopen" - }, +/obj/structure/closet/crate/mail/preopen, /obj/effect/turf_decal/stripes{ dir = 8 }, @@ -494,9 +486,7 @@ /turf/open/floor/iron/white, /area/ruin/powered/mailroom) "Wr" = ( -/obj/structure/closet/crate/mail{ - icon_state = "mailopen" - }, +/obj/structure/closet/crate/mail/preopen, /obj/effect/turf_decal/siding/yellow, /obj/item/mail/junkmail, /obj/item/mail/junkmail, diff --git a/_maps/RandomRuins/SpaceRuins/bigderelict1.dmm b/_maps/RandomRuins/SpaceRuins/bigderelict1.dmm index 315eb923063..b750d66535a 100644 --- a/_maps/RandomRuins/SpaceRuins/bigderelict1.dmm +++ b/_maps/RandomRuins/SpaceRuins/bigderelict1.dmm @@ -165,9 +165,7 @@ /turf/open/floor/plating, /area/ruin/space/has_grav/derelictoutpost/powerstorage) "aN" = ( -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/effect/turf_decal/delivery, /turf/open/floor/iron, /area/ruin/space/has_grav/derelictoutpost/cargobay) @@ -636,9 +634,7 @@ /turf/open/floor/iron, /area/ruin/space/has_grav/derelictoutpost/cargobay) "cH" = ( -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/structure/cable, /turf/open/floor/iron, /area/ruin/space/has_grav/derelictoutpost/cargobay) @@ -965,9 +961,7 @@ /turf/open/floor/iron, /area/ruin/space/has_grav/derelictoutpost/cargostorage) "dY" = ( -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/item/stack/sheet/plasteel/twenty, /obj/effect/turf_decal/delivery, /turf/open/floor/iron, @@ -1020,9 +1014,7 @@ /turf/open/floor/iron, /area/ruin/space/has_grav/derelictoutpost/cargostorage) "ek" = ( -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/item/stack/sheet/cardboard/fifty, /obj/effect/turf_decal/delivery, /turf/open/floor/iron, @@ -1048,9 +1040,7 @@ /turf/open/floor/iron, /area/ruin/space/has_grav/derelictoutpost/cargostorage) "eq" = ( -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/effect/spawner/random/exotic/tool, /turf/open/floor/iron, /area/ruin/space/has_grav/derelictoutpost/cargostorage) @@ -1106,9 +1096,7 @@ /turf/open/floor/iron, /area/ruin/space/has_grav/derelictoutpost/cargostorage) "eB" = ( -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/machinery/light/directional/south, /obj/effect/turf_decal/delivery, /obj/effect/spawner/random/exotic/technology, diff --git a/_maps/RandomRuins/SpaceRuins/crashedclownship.dmm b/_maps/RandomRuins/SpaceRuins/crashedclownship.dmm index f2a0595751b..128deda9e35 100644 --- a/_maps/RandomRuins/SpaceRuins/crashedclownship.dmm +++ b/_maps/RandomRuins/SpaceRuins/crashedclownship.dmm @@ -35,9 +35,7 @@ /turf/open/floor/mineral/bananium/airless, /area/ruin/space/has_grav) "j" = ( -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/item/stack/ore/bananium, /turf/open/floor/mineral/bananium/airless, /area/ruin/space/has_grav) diff --git a/_maps/RandomRuins/SpaceRuins/hellfactory.dmm b/_maps/RandomRuins/SpaceRuins/hellfactory.dmm index 438e36acb59..511614db103 100644 --- a/_maps/RandomRuins/SpaceRuins/hellfactory.dmm +++ b/_maps/RandomRuins/SpaceRuins/hellfactory.dmm @@ -103,9 +103,7 @@ /turf/open/floor/iron, /area/ruin/space/has_grav/hellfactory) "at" = ( -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/item/reagent_containers/cup/beaker/large, /obj/item/reagent_containers/cup/beaker/large, /turf/open/floor/plating, diff --git a/_maps/RandomRuins/SpaceRuins/mimesvsclowns.dmm b/_maps/RandomRuins/SpaceRuins/mimesvsclowns.dmm index fd4bf0a5ab1..f0ea8b833d9 100644 --- a/_maps/RandomRuins/SpaceRuins/mimesvsclowns.dmm +++ b/_maps/RandomRuins/SpaceRuins/mimesvsclowns.dmm @@ -25,9 +25,7 @@ /area/ruin) "hG" = ( /obj/effect/mob_spawn/corpse/human/clown, -/obj/structure/closet/secure_closet/freezer/fridge/open{ - opened = 1 - }, +/obj/structure/closet/secure_closet/freezer/fridge/preopen, /obj/item/food/burger/mime, /obj/item/food/burger/mime, /obj/item/food/pie/mimetart, @@ -61,9 +59,7 @@ /area/ruin) "ox" = ( /obj/machinery/light/small/broken/directional/east, -/obj/structure/closet{ - opened = 1 - }, +/obj/structure/closet/preopen, /obj/item/clothing/mask/gas/mime, /obj/item/clothing/mask/gas/mime, /obj/item/clothing/under/rank/civilian/mime, diff --git a/_maps/RandomRuins/SpaceRuins/waystation.dmm b/_maps/RandomRuins/SpaceRuins/waystation.dmm index a6d83df4974..8e0dde4e171 100644 --- a/_maps/RandomRuins/SpaceRuins/waystation.dmm +++ b/_maps/RandomRuins/SpaceRuins/waystation.dmm @@ -431,9 +431,7 @@ /area/ruin/space/has_grav/waystation/cargobay) "ib" = ( /obj/effect/turf_decal/delivery, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /turf/open/floor/iron, /area/ruin/space/has_grav/waystation/cargobay) "ic" = ( diff --git a/_maps/RandomZLevels/caves.dmm b/_maps/RandomZLevels/caves.dmm index e777584ee9b..7f0c4a2e386 100644 --- a/_maps/RandomZLevels/caves.dmm +++ b/_maps/RandomZLevels/caves.dmm @@ -1258,9 +1258,7 @@ }, /area/awaymission/caves/bmp_asteroid/level_two) "ki" = ( -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/item/paper/fluff/awaymissions/caves/shipment_receipt, /obj/item/organ/internal/eyes/robotic/thermals, /obj/item/gun/energy/laser/captain/scattershot, diff --git a/_maps/RandomZLevels/research.dmm b/_maps/RandomZLevels/research.dmm index bc6878f0953..d1806afb8ee 100644 --- a/_maps/RandomZLevels/research.dmm +++ b/_maps/RandomZLevels/research.dmm @@ -3866,9 +3866,7 @@ /turf/open/floor/iron/white, /area/awaymission/research/interior/security) "Re" = ( -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/effect/spawner/random/maintenance, /turf/open/floor/plating, /area/awaymission/research/interior/maint) diff --git a/_maps/RandomZLevels/snowdin.dmm b/_maps/RandomZLevels/snowdin.dmm index 8eaedce940f..5363f08f0d2 100644 --- a/_maps/RandomZLevels/snowdin.dmm +++ b/_maps/RandomZLevels/snowdin.dmm @@ -623,9 +623,7 @@ "ce" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/light/directional/north, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /turf/open/floor/iron, /area/awaymission/snowdin/post/kitchen) "ch" = ( @@ -785,9 +783,7 @@ /turf/open/floor/plating, /area/awaymission/snowdin/post/research) "cD" = ( -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron, /area/awaymission/snowdin/post/mining_dock) @@ -1203,8 +1199,7 @@ /area/awaymission/snowdin/cave) "dy" = ( /obj/effect/turf_decal/weather/snow, -/obj/structure/closet/crate{ - icon_state = "crateopen"; +/obj/structure/closet/crate/preopen{ name = "explosives ordinance" }, /turf/open/floor/iron/dark/snowdin, @@ -1967,9 +1962,7 @@ /area/awaymission/snowdin/cave) "gk" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/item/crowbar, /obj/item/crowbar, /obj/item/pickaxe/mini, @@ -2289,9 +2282,7 @@ pixel_x = 5; pixel_y = 5 }, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/item/clothing/shoes/winterboots, /obj/item/clothing/shoes/winterboots, /turf/open/floor/plating, @@ -3492,9 +3483,7 @@ /obj/structure/sign/poster/contraband/tools{ pixel_x = 32 }, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/item/tank/internals/plasma, /obj/item/tank/internals/plasma, /turf/open/floor/plating, @@ -8253,8 +8242,7 @@ /area/awaymission/snowdin/cave) "Ca" = ( /obj/effect/turf_decal/bot, -/obj/structure/closet/crate{ - icon_state = "crateopen"; +/obj/structure/closet/crate/preopen{ name = "explosives ordinance" }, /turf/open/floor/plating/snowed, @@ -9721,9 +9709,7 @@ /turf/open/floor/iron, /area/awaymission/snowdin/post/mining_main) "IX" = ( -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/item/stack/sheet/mineral/plasma{ amount = 10 }, @@ -9815,9 +9801,7 @@ /turf/open/floor/plating, /area/awaymission/snowdin/post/mining_dock) "Jp" = ( -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/item/storage/toolbox/emergency, /obj/item/clothing/suit/hooded/wintercoat, /obj/item/clothing/suit/hooded/wintercoat, @@ -9830,9 +9814,7 @@ /turf/open/floor/plating/snowed/cavern, /area/awaymission/snowdin/cave/cavern) "Jt" = ( -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/item/storage/toolbox/emergency, /turf/open/floor/plating, /area/awaymission/snowdin/post/mining_main) @@ -9904,9 +9886,7 @@ /turf/open/floor/iron, /area/awaymission/snowdin/post/mining_dock) "JE" = ( -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/item/storage/toolbox/emergency, /obj/item/clothing/suit/hooded/wintercoat, /turf/open/floor/plating, @@ -9958,9 +9938,7 @@ /turf/open/floor/iron, /area/awaymission/snowdin/post/mining_main) "JN" = ( -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/item/clothing/suit/hooded/wintercoat, /obj/item/clothing/suit/hooded/wintercoat, /obj/item/clothing/suit/hooded/wintercoat, @@ -12674,8 +12652,7 @@ /area/awaymission/snowdin/post/research) "YR" = ( /obj/effect/turf_decal/weather/snow, -/obj/structure/closet/crate{ - icon_state = "crateopen"; +/obj/structure/closet/crate/preopen{ name = "explosives ordinance" }, /obj/machinery/light/small/directional/east, diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index 4d7fe494a2b..c850f6f24f5 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -2503,9 +2503,7 @@ /area/station/cargo/storage) "aDg" = ( /obj/effect/turf_decal/delivery, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /turf/open/floor/iron, /area/station/cargo/storage) "aDt" = ( @@ -17227,9 +17225,7 @@ /obj/effect/turf_decal/stripes/line{ dir = 6 }, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/item/clothing/head/cone, /obj/item/clothing/head/cone, /obj/item/clothing/head/cone, @@ -17726,9 +17722,7 @@ "etg" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/decal/cleanable/dirt, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/effect/spawner/random/maintenance/two, /obj/effect/turf_decal/bot, /turf/open/floor/iron, @@ -23913,9 +23907,7 @@ /area/station/command/heads_quarters/hos) "fXt" = ( /obj/effect/decal/cleanable/dirt, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/effect/turf_decal/delivery, /turf/open/floor/iron, /area/station/cargo/storage) @@ -59945,9 +59937,7 @@ /turf/open/floor/iron, /area/station/cargo/storage) "pdF" = ( -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/structure/sign/nanotrasen{ pixel_x = 32 }, @@ -72660,9 +72650,7 @@ /turf/open/floor/plating/airless, /area/space/nearstation) "sji" = ( -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/effect/spawner/random/maintenance, /obj/effect/turf_decal/bot, /obj/item/electronics/apc, diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index 67fab5b0c47..0502955ffb3 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -35594,9 +35594,7 @@ }, /area/station/service/chapel) "lnx" = ( -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /turf/open/floor/plating/snowed/icemoon, /area/icemoon/underground/explored) "lnC" = ( @@ -55811,9 +55809,7 @@ }, /obj/machinery/light/directional/west, /obj/structure/cable, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/item/stack/sheet/mineral/plasma/five, /obj/effect/turf_decal/tile/dark/half/contrasted{ dir = 8 @@ -68273,9 +68269,7 @@ /area/icemoon/underground/explored) "vNT" = ( /obj/effect/turf_decal/bot, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/machinery/light/small/directional/north, /obj/structure/extinguisher_cabinet/directional/north, /turf/open/floor/iron, @@ -73804,9 +73798,7 @@ /obj/machinery/power/terminal{ dir = 8 }, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/machinery/light/directional/south, /obj/item/stack/sheet/mineral/plasma/thirty, /turf/open/floor/iron/smooth, diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index f3517537536..4facd02335f 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -2158,9 +2158,7 @@ /turf/open/floor/iron/white, /area/station/medical/treatment_center) "aPk" = ( -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /turf/open/floor/plating, /area/station/maintenance/port/fore) "aPm" = ( @@ -2405,9 +2403,7 @@ /turf/closed/wall/r_wall, /area/station/ai_monitored/turret_protected/ai) "aUj" = ( -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/item/stack/package_wrap, /obj/item/stack/package_wrap{ pixel_y = 2 @@ -5692,9 +5688,7 @@ /area/station/medical/morgue) "cfv" = ( /obj/effect/decal/cleanable/dirt, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/structure/disposalpipe/segment, /turf/open/floor/iron, /area/station/cargo/warehouse) @@ -17078,9 +17072,7 @@ /obj/item/storage/toolbox/mechanical, /obj/item/clothing/mask/gas, /obj/item/clothing/mask/gas, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/item/wrench, /obj/machinery/atmospherics/pipe/smart/manifold4w/general/visible, /obj/effect/turf_decal/tile/neutral/fourcorners, @@ -44353,9 +44345,7 @@ "pVi" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/light_switch/directional/north, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /turf/open/floor/iron, /area/station/cargo/warehouse) "pVM" = ( @@ -58010,9 +58000,7 @@ /turf/open/floor/plating, /area/station/maintenance/starboard/aft) "uHa" = ( -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/item/stack/sheet/rglass{ amount = 50 }, diff --git a/_maps/map_files/NorthStar/north_star.dmm b/_maps/map_files/NorthStar/north_star.dmm index b738e49895c..cc78fbc71e7 100644 --- a/_maps/map_files/NorthStar/north_star.dmm +++ b/_maps/map_files/NorthStar/north_star.dmm @@ -31128,9 +31128,7 @@ /area/station/maintenance/floor1/port/aft) "ioM" = ( /obj/effect/spawner/random/maintenance/two, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/effect/decal/cleanable/dirt/dust, /turf/open/floor/pod/light, /area/station/maintenance/floor4/starboard/fore) @@ -34626,9 +34624,7 @@ /turf/open/floor/iron/kitchen/herringbone, /area/station/service/kitchen/diner) "jnv" = ( -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/effect/spawner/random/maintenance/two, /obj/effect/decal/cleanable/dirt/dust, /turf/open/floor/pod/light, @@ -44792,9 +44788,7 @@ /area/station/commons/fitness/recreation) "lRc" = ( /obj/item/reagent_containers/dropper, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/effect/decal/cleanable/dirt/dust, /turf/open/floor/pod/light, /area/station/maintenance/floor4/starboard/fore) @@ -66779,9 +66773,7 @@ "rBB" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/spawner/random/entertainment/drugs, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /turf/open/floor/plating, /area/station/maintenance/floor1/port/fore) "rBC" = ( @@ -74980,9 +74972,7 @@ /area/station/science/cytology) "tSf" = ( /obj/effect/spawner/random/maintenance/two, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/item/mop, /obj/effect/spawner/random/engineering/flashlight, /obj/effect/decal/cleanable/dirt/dust, @@ -83030,9 +83020,7 @@ /turf/open/floor/iron/dark, /area/station/commons/storage/tools) "wcR" = ( -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/effect/spawner/random/engineering/material_cheap, /obj/effect/spawner/random/engineering/flashlight, /obj/effect/spawner/random/engineering/tool, diff --git a/_maps/map_files/tramstation/maintenance_modules/dormenginelower_2.dmm b/_maps/map_files/tramstation/maintenance_modules/dormenginelower_2.dmm index e2845b4169b..ebfe88aed6b 100644 --- a/_maps/map_files/tramstation/maintenance_modules/dormenginelower_2.dmm +++ b/_maps/map_files/tramstation/maintenance_modules/dormenginelower_2.dmm @@ -49,9 +49,7 @@ "cZ" = ( /obj/effect/turf_decal/sand/plating, /obj/effect/mapping_helpers/broken_floor, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/effect/spawner/random/maintenance/two, /turf/open/floor/plating/airless, /area/station/maintenance/department/crew_quarters/dorms) diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm index e1d6c55cc0b..4128880f615 100644 --- a/_maps/map_files/tramstation/tramstation.dmm +++ b/_maps/map_files/tramstation/tramstation.dmm @@ -4468,9 +4468,7 @@ /area/station/cargo/storage) "axI" = ( /obj/effect/turf_decal/bot, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /turf/open/floor/iron, /area/station/cargo/storage) "axJ" = ( @@ -4561,9 +4559,7 @@ "ayG" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/bot, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/item/stack/sheet/cardboard{ amount = 23 }, @@ -25125,9 +25121,7 @@ dir = 4 }, /obj/effect/turf_decal/bot, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/item/stock_parts/cell/empty, /obj/effect/spawner/random/engineering/flashlight, /turf/open/floor/iron, @@ -29475,9 +29469,7 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/bot, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/effect/spawner/random/maintenance/two, /obj/effect/spawner/random/engineering/flashlight, /turf/open/floor/iron, @@ -50976,9 +50968,7 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/bot, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/item/stack/package_wrap, /obj/item/stack/package_wrap, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, diff --git a/_maps/shuttles/emergency_luxury.dmm b/_maps/shuttles/emergency_luxury.dmm index e13338b4c59..eeb25b19cca 100644 --- a/_maps/shuttles/emergency_luxury.dmm +++ b/_maps/shuttles/emergency_luxury.dmm @@ -616,9 +616,7 @@ /area/shuttle/escape/luxury) "Av" = ( /obj/effect/spawner/random/maintenance/eight, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/effect/turf_decal/delivery, /obj/effect/decal/cleanable/dirt/dust, /obj/effect/decal/cleanable/vomit/old, @@ -832,9 +830,7 @@ /area/shuttle/escape/luxury) "In" = ( /obj/effect/spawner/random/maintenance/eight, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/effect/decal/cleanable/robot_debris, /obj/effect/turf_decal/delivery, /obj/effect/decal/cleanable/oil, diff --git a/_maps/shuttles/emergency_pubby.dmm b/_maps/shuttles/emergency_pubby.dmm index 919d07003ef..7fefead21ed 100644 --- a/_maps/shuttles/emergency_pubby.dmm +++ b/_maps/shuttles/emergency_pubby.dmm @@ -424,9 +424,7 @@ /turf/open/floor/plating, /area/shuttle/escape) "bn" = ( -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/machinery/light/directional/south, /obj/item/storage/toolbox/mechanical, /turf/open/floor/plating, diff --git a/_maps/shuttles/hunter_russian.dmm b/_maps/shuttles/hunter_russian.dmm index ed48ece46eb..10100224aed 100644 --- a/_maps/shuttles/hunter_russian.dmm +++ b/_maps/shuttles/hunter_russian.dmm @@ -433,9 +433,7 @@ /obj/effect/turf_decal/stripes/line, /obj/effect/decal/cleanable/dirt, /obj/machinery/firealarm/directional/south, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /turf/open/floor/mineral/plastitanium, /area/shuttle/hunter/russian) "Gh" = ( diff --git a/_maps/shuttles/ruin_caravan_victim.dmm b/_maps/shuttles/ruin_caravan_victim.dmm index 90344acccd1..868c62c7b9c 100644 --- a/_maps/shuttles/ruin_caravan_victim.dmm +++ b/_maps/shuttles/ruin_caravan_victim.dmm @@ -146,9 +146,7 @@ /turf/open/floor/plating/airless, /area/shuttle/ruin/caravan/freighter1) "lD" = ( -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/item/stack/sheet/iron/fifty, /turf/open/floor/iron/dark/airless, /area/shuttle/ruin/caravan/freighter1) diff --git a/_maps/shuttles/ruin_cyborg_mothership.dmm b/_maps/shuttles/ruin_cyborg_mothership.dmm index 15b35e6de97..9cbca717c44 100644 --- a/_maps/shuttles/ruin_cyborg_mothership.dmm +++ b/_maps/shuttles/ruin_cyborg_mothership.dmm @@ -242,9 +242,7 @@ /obj/structure/window/reinforced/spawner/directional/north{ layer = 2.9 }, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/effect/turf_decal/stripes/asteroid/line{ dir = 8 }, diff --git a/_maps/shuttles/whiteship_birdshot.dmm b/_maps/shuttles/whiteship_birdshot.dmm index aa5daf0e34a..2b4929d0101 100644 --- a/_maps/shuttles/whiteship_birdshot.dmm +++ b/_maps/shuttles/whiteship_birdshot.dmm @@ -43,9 +43,7 @@ "bo" = ( /obj/effect/turf_decal/box/white/corners, /obj/effect/decal/cleanable/dirt/dust, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/effect/spawner/random/maintenance/three, /turf/open/floor/iron/dark/textured_large, /area/shuttle/abandoned/cargo) diff --git a/_maps/shuttles/whiteship_cere.dmm b/_maps/shuttles/whiteship_cere.dmm index 884478f50c2..acb3270965f 100644 --- a/_maps/shuttles/whiteship_cere.dmm +++ b/_maps/shuttles/whiteship_cere.dmm @@ -138,8 +138,7 @@ dir = 1 }, /obj/effect/decal/cleanable/dirt/dust, -/obj/structure/closet/crate{ - icon_state = "crateopen"; +/obj/structure/closet/crate/preopen{ name = "spare equipment crate" }, /turf/open/floor/mineral/titanium/yellow, @@ -156,8 +155,7 @@ /obj/effect/turf_decal/delivery{ dir = 1 }, -/obj/structure/closet/crate{ - icon_state = "crateopen"; +/obj/structure/closet/crate/preopen{ name = "spare equipment crate" }, /obj/item/pickaxe, @@ -192,8 +190,7 @@ /obj/effect/turf_decal/delivery{ dir = 1 }, -/obj/structure/closet/crate{ - icon_state = "crateopen"; +/obj/structure/closet/crate/preopen{ name = "spare equipment crate" }, /obj/item/storage/bag/ore, @@ -270,8 +267,7 @@ }, /obj/effect/decal/cleanable/dirt/dust, /obj/effect/decal/cleanable/dirt/dust, -/obj/structure/closet/crate{ - icon_state = "crateopen"; +/obj/structure/closet/crate/preopen{ name = "spare equipment crate" }, /obj/machinery/light/directional/south, diff --git a/_maps/shuttles/whiteship_delta.dmm b/_maps/shuttles/whiteship_delta.dmm index 5280dd4f226..e3b7925447c 100644 --- a/_maps/shuttles/whiteship_delta.dmm +++ b/_maps/shuttles/whiteship_delta.dmm @@ -1917,9 +1917,7 @@ /area/shuttle/abandoned/cargo) "Ps" = ( /obj/effect/decal/cleanable/dirt/dust, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/effect/spawner/random/maintenance/three, /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, @@ -1927,9 +1925,7 @@ "Pt" = ( /obj/effect/decal/cleanable/dirt/dust, /obj/effect/turf_decal/box/white/corners, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/effect/spawner/random/maintenance/three, /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, diff --git a/_maps/shuttles/whiteship_meta.dmm b/_maps/shuttles/whiteship_meta.dmm index cb58a85b76f..f2c1c0bdbbc 100644 --- a/_maps/shuttles/whiteship_meta.dmm +++ b/_maps/shuttles/whiteship_meta.dmm @@ -2026,18 +2026,14 @@ }, /obj/effect/decal/cleanable/dirt/dust, /obj/effect/decal/cleanable/dirt/dust, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/effect/spawner/random/maintenance/three, /turf/open/floor/iron/dark, /area/shuttle/abandoned/cargo) "Sm" = ( /obj/effect/decal/cleanable/dirt/dust, /obj/effect/decal/cleanable/dirt/dust, -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/effect/spawner/random/maintenance/three, /turf/open/floor/iron/dark, /area/shuttle/abandoned/cargo) diff --git a/_maps/templates/lazy_templates/wizard_den.dmm b/_maps/templates/lazy_templates/wizard_den.dmm index 025f9e8cdd0..efe2d455c23 100644 --- a/_maps/templates/lazy_templates/wizard_den.dmm +++ b/_maps/templates/lazy_templates/wizard_den.dmm @@ -455,9 +455,7 @@ /turf/open/floor/iron/white, /area/centcom/wizard_station) "Uu" = ( -/obj/structure/closet/crate{ - icon_state = "crateopen" - }, +/obj/structure/closet/crate/preopen, /obj/item/clothing/suit/wizrobe/red, /obj/item/clothing/head/wizard/red, /obj/item/staff, diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm index 9f6d20023f5..b278dfb6e0e 100644 --- a/code/__DEFINES/dcs/signals/signals_object.dm +++ b/code/__DEFINES/dcs/signals/signals_object.dm @@ -187,6 +187,12 @@ ///From open: (forced) #define COMSIG_CLOSET_POST_OPEN "closet_post_open" +///From close +#define COMSIG_CLOSET_PRE_CLOSE "closet_pre_close" + #define BLOCK_CLOSE (1<<1) +///From close +#define COMSIG_CLOSET_POST_CLOSE "closet_post_close" + ///a deliver_first element closet was successfully delivered #define COMSIG_CLOSET_DELIVERED "crate_delivered" diff --git a/code/datums/components/crafting/equipment.dm b/code/datums/components/crafting/equipment.dm index 9724e07da49..e5c66b2ac56 100644 --- a/code/datums/components/crafting/equipment.dm +++ b/code/datums/components/crafting/equipment.dm @@ -57,12 +57,29 @@ time = 20 SECONDS category = CAT_EQUIPMENT -/datum/crafting_recipe/freezer_cabinat - name = "Freezer Cabinet" +/datum/crafting_recipe/secured_freezer_cabinet + name = "Secure Freezer Cabinet" result = /obj/structure/closet/secure_closet/freezer/empty reqs = list( - /obj/item/stack/sheet/iron = 2, + /obj/item/stack/sheet/iron = 5, /obj/item/assembly/igniter/condenser = 1, + /obj/item/electronics/airlock = 1, + ) + parts = list( + /obj/item/electronics/airlock = 1, + ) + time = 5 SECONDS + category = CAT_EQUIPMENT + +/datum/crafting_recipe/secure_closet + name = "Secure Closet" + result = /obj/structure/closet/secure_closet + reqs = list( + /obj/item/stack/sheet/iron = 5, + /obj/item/electronics/airlock = 1, + ) + parts = list( + /obj/item/electronics/airlock = 1, ) time = 5 SECONDS category = CAT_EQUIPMENT diff --git a/code/datums/elements/deliver_first.dm b/code/datums/elements/deliver_first.dm index 7c674bf9c71..9633a376107 100644 --- a/code/datums/elements/deliver_first.dm +++ b/code/datums/elements/deliver_first.dm @@ -85,7 +85,7 @@ return BLOCK_OPEN ///signal called by successfully opening target -/datum/element/deliver_first/proc/on_post_open(obj/structure/closet/target, force) +/datum/element/deliver_first/proc/on_post_open(obj/structure/closet/target, mob/living/user, force) SIGNAL_HANDLER if(area_check(target)) //noice, delivered! diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm index 9179d0fdd6a..47d4aa17154 100644 --- a/code/game/machinery/suit_storage_unit.dm +++ b/code/game/machinery/suit_storage_unit.dm @@ -9,6 +9,9 @@ density = TRUE obj_flags = BLOCKS_CONSTRUCTION // Becomes undense when the unit is open max_integrity = 250 + req_access = list() + state_open = FALSE + panel_open = FALSE circuit = /obj/item/circuitboard/machine/suit_storage_unit var/obj/item/clothing/suit/space/suit = null @@ -29,10 +32,10 @@ /// What type of additional item the unit starts with when spawned. var/storage_type = null - state_open = FALSE + /// If the SSU's doors are locked closed. Can be toggled manually via the UI, but is also locked automatically when the UV decontamination sequence is running. var/locked = FALSE - panel_open = FALSE + /// If the safety wire is cut/pulsed, the SSU can run the decontamination sequence while occupied by a mob. The mob will be burned during every cycle of cook(). var/safeties = TRUE @@ -53,9 +56,14 @@ var/breakout_time = 300 /// Power contributed by this machine to charge the mod suits cell without any capacitors var/base_charge_rate = 200 - // Final charge rate which is base_charge_rate + contribution by capacitors + /// Final charge rate which is base_charge_rate + contribution by capacitors var/final_charge_rate = 250 - + /// is the card reader installed in this machine + var/card_reader_installed = FALSE + /// physical reference of the players id card to check for PERSONAL access level + var/datum/weakref/id_card = null + /// should we prevent furthur access change + var/access_locked = FALSE /obj/machinery/suit_storage_unit/standard_unit suit_type = /obj/item/clothing/suit/space/eva @@ -158,6 +166,8 @@ /obj/machinery/suit_storage_unit/Initialize(mapload) . = ..() + + set_access() wires = new /datum/wires/suit_storage_unit(src) if(suit_type) suit = new suit_type(src) @@ -171,14 +181,39 @@ storage = new storage_type(src) update_appearance() + register_context() + /obj/machinery/suit_storage_unit/Destroy() QDEL_NULL(suit) QDEL_NULL(helmet) QDEL_NULL(mask) QDEL_NULL(mod) QDEL_NULL(storage) + id_card = null return ..() +/obj/machinery/suit_storage_unit/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = ..() + + if(isnull(held_item)) + return NONE + + var/screentip_change = FALSE + if(istype(held_item, /obj/item/stock_parts/card_reader) && !locked && can_install_card_reader(user)) + context[SCREENTIP_CONTEXT_LMB] ="Install Reader" + screentip_change = TRUE + + if(held_item.tool_behaviour == TOOL_MULTITOOL && !locked && !panel_open && !state_open && card_reader_installed) + context[SCREENTIP_CONTEXT_LMB] ="[access_locked ? "Unlock" : "Lock"] Access Panel" + screentip_change = TRUE + + if(!state_open && is_operational && card_reader_installed && !isnull((held_item.GetID()))) + context[SCREENTIP_CONTEXT_LMB] ="Change Access" + screentip_change = TRUE + + return screentip_change ? CONTEXTUAL_SCREENTIP_SET : NONE + + /obj/machinery/suit_storage_unit/update_overlays() . = ..() //if things arent powered, these show anyways @@ -213,11 +248,37 @@ else . += "[base_icon_state]_ready" +/obj/machinery/suit_storage_unit/examine(mob/user) + . = ..() + if(card_reader_installed) + . += span_notice("Swipe your ID to change access levels.") + . += span_notice("Use a multitool to [access_locked ? "unlock" : "lock"] access panel after opening panel.") + else + . += span_notice("A card reader can be installed for further control access after opening its panel.") + +/// copy over access of electronics +/obj/machinery/suit_storage_unit/proc/set_access(list/accesses) + var/obj/item/electronics/airlock/electronics = locate() in component_parts + if(QDELETED(electronics)) + return + + if(!isnull(accesses)) + electronics.accesses = accesses + if(electronics.one_access) + req_one_access = electronics.accesses + req_access = null + else + req_access = electronics.accesses + req_one_access = null + /obj/machinery/suit_storage_unit/RefreshParts() . = ..() + for(var/datum/stock_part/capacitor/capacitor in component_parts) final_charge_rate = base_charge_rate + (capacitor.tier * 50) + set_access() + /obj/machinery/suit_storage_unit/power_change() . = ..() if(!is_operational && state_open) @@ -238,8 +299,31 @@ if(!(flags_1 & NODECONSTRUCT_1)) open_machine() dump_inventory_contents() + if(card_reader_installed) + new /obj/item/stock_parts/card_reader(loc) return ..() +/obj/machinery/suit_storage_unit/proc/access_check(mob/living/user) + if(!isnull(id_card)) + var/obj/item/card/id/id = id_card?.resolve() + if(!id) // reset to defaults + name = initial(name) + desc = initial(desc) + id_card = null + req_access = list() + req_one_access = null + set_access(list()) + return TRUE + if(user.get_idcard() != id) + balloon_alert(user, "not your unit!") + return FALSE + + if(!allowed(user)) + balloon_alert(user, "access denied!") + return FALSE + + return TRUE + /obj/machinery/suit_storage_unit/interact(mob/living/user) var/static/list/items @@ -292,6 +376,8 @@ switch (choice) if ("open") if (!state_open) + if(!access_check(user)) + return open_machine(drop = FALSE) if (occupant) dump_inventory_contents() @@ -299,6 +385,8 @@ if (state_open) close_machine() if ("disinfect") + if(!access_check(user)) + return if (occupant && safeties) say("Alert: safeties triggered, occupant detected!") return @@ -311,6 +399,8 @@ to_chat(mob_occupant, span_userdanger("[src]'s confines grow warm, then hot, then scorching. You're being burned [!mob_occupant.stat ? "alive" : "away"]!")) cook() if ("lock", "unlock") + if(locked && !access_check(user)) + return if (!state_open) locked = !locked update_icon() @@ -516,60 +606,171 @@ span_notice("You escape the cramped confines of [src]!")) open_machine() -/obj/machinery/suit_storage_unit/attackby(obj/item/I, mob/user, params) +/obj/machinery/suit_storage_unit/multitool_act(mob/living/user, obj/item/tool) + if(!card_reader_installed || state_open) + return + + if(locked) + balloon_alert(user, "unlock first!") + return + + access_locked = !access_locked + balloon_alert(user, "access panel [access_locked ? "locked" : "unlocked"]") + return TRUE + +/obj/machinery/suit_storage_unit/proc/can_install_card_reader(mob/user) + if(card_reader_installed || !panel_open || state_open || !is_operational) + return FALSE + + if(locked) + balloon_alert(user, "unlock first!") + return FALSE + + return TRUE + +/obj/machinery/suit_storage_unit/attackby(obj/item/weapon, mob/user, params) + . = TRUE + var/obj/item/card/id/id = null + 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(!state_open && is_operational && card_reader_installed && !isnull((id = weapon.GetID()))) + if(panel_open) + balloon_alert(user, "close panel!") + return + + if(locked) + balloon_alert(user, "unlock first!") + return + + if(access_locked) + balloon_alert(user, "access panel locked!") + return + + //change the access type + var/static/list/choices = list( + "Personal", + "Departmental", + "None" + ) + var/choice = tgui_input_list(user, "Set Access Type", "Access Type", choices) + if(isnull(choice)) + return + + id_card = null + switch(choice) + if("Personal") //only the player who swiped their id has access. + id_card = WEAKREF(id) + name = "[id.registered_name] Suit Storage Unit" + desc = "Owned by [id.registered_name]. [initial(desc)]" + if("Departmental") //anyone who has the same access permissions as this id has access + name = "[id.assignment] Suit Storage Unit" + desc = "Its a [id.assignment] Suit Storage Unit. [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(!state_open && 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 Unit Name", "Unit Name") + if(!isnull(str)) + name = str + name_set = TRUE + + str = tgui_input_text(user, "Personal Unit Description", "Unit 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) + if(state_open && is_operational) - if(istype(I, /obj/item/clothing/suit)) + if(istype(weapon, /obj/item/clothing/suit)) if(suit) to_chat(user, span_warning("The unit already contains a suit!.")) return - if(!user.transferItemToLoc(I, src)) + if(!user.transferItemToLoc(weapon, src)) return - suit = I - else if(istype(I, /obj/item/clothing/head)) + suit = weapon + else if(istype(weapon, /obj/item/clothing/head)) if(helmet) to_chat(user, span_warning("The unit already contains a helmet!")) return - if(!user.transferItemToLoc(I, src)) + if(!user.transferItemToLoc(weapon, src)) return - helmet = I - else if(istype(I, /obj/item/clothing/mask)) + helmet = weapon + else if(istype(weapon, /obj/item/clothing/mask)) if(mask) to_chat(user, span_warning("The unit already contains a mask!")) return - if(!user.transferItemToLoc(I, src)) + if(!user.transferItemToLoc(weapon, src)) return - mask = I - else if(istype(I, /obj/item/mod/control)) + mask = weapon + else if(istype(weapon, /obj/item/mod/control)) if(mod) to_chat(user, span_warning("The unit already contains a MOD!")) return - if(!user.transferItemToLoc(I, src)) + if(!user.transferItemToLoc(weapon, src)) return - mod = I + mod = weapon else if(storage) to_chat(user, span_warning("The auxiliary storage compartment is full!")) return - if(!user.transferItemToLoc(I, src)) + if(!user.transferItemToLoc(weapon, src)) return - storage = I + storage = weapon - visible_message(span_notice("[user] inserts [I] into [src]"), span_notice("You load [I] into [src].")) + visible_message(span_notice("[user] inserts [weapon] into [src]"), span_notice("You load [weapon] into [src].")) update_appearance() return if(panel_open) - if(is_wire_tool(I)) + if(is_wire_tool(weapon)) wires.interact(user) return - else if(I.tool_behaviour == TOOL_CROWBAR) - default_deconstruction_crowbar(I) + else if(weapon.tool_behaviour == TOOL_CROWBAR) + default_deconstruction_crowbar(weapon) return if(!state_open) - if(default_deconstruction_screwdriver(user, "[base_icon_state]", "[base_icon_state]", I)) //Set to base_icon_state because the panels for this are overlays + if(default_deconstruction_screwdriver(user, "[base_icon_state]", "[base_icon_state]", weapon)) //Set to base_icon_state because the panels for this are overlays update_appearance() return - if(default_pry_open(I)) + if(default_pry_open(weapon)) dump_inventory_contents() return @@ -579,16 +780,21 @@ screwdriving it open while it's running a decontamination sequence without closing the panel prior to finish causes the SSU to break due to state_open being set to TRUE at the end, and the panel becoming inaccessible. */ -/obj/machinery/suit_storage_unit/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/I) - if(!(flags_1 & NODECONSTRUCT_1) && I.tool_behaviour == TOOL_SCREWDRIVER && uv) - to_chat(user, span_warning("It might not be wise to fiddle with [src] while it's running...")) +/obj/machinery/suit_storage_unit/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/screwdriver) + if(!(flags_1 & NODECONSTRUCT_1) && screwdriver.tool_behaviour == TOOL_SCREWDRIVER && (uv || locked)) + to_chat(user, span_warning("You cant open the panel while its [locked ? "locked" : "decontaminating"]")) return TRUE return ..() -/obj/machinery/suit_storage_unit/default_pry_open(obj/item/I)//needs to check if the storage is locked. - . = !(state_open || panel_open || is_operational || locked || (flags_1 & NODECONSTRUCT_1)) && I.tool_behaviour == TOOL_CROWBAR +/obj/machinery/suit_storage_unit/default_pry_open(obj/item/crowbar)//needs to check if the storage is locked. + . = !(state_open || panel_open || is_operational || locked || (flags_1 & NODECONSTRUCT_1)) && crowbar.tool_behaviour == TOOL_CROWBAR if(.) - I.play_tool_sound(src, 50) + crowbar.play_tool_sound(src, 50) visible_message(span_notice("[usr] pries open \the [src]."), span_notice("You pry open \the [src].")) open_machine() + +/obj/machinery/suit_storage_unit/default_deconstruction_crowbar(obj/item/crowbar, ignore_panel, custom_deconstruct) + . = (!locked && panel_open && !(flags_1 & NODECONSTRUCT_1) && crowbar.tool_behaviour == TOOL_CROWBAR) + if(.) + return ..() diff --git a/code/game/objects/effects/spawners/random/structure.dm b/code/game/objects/effects/spawners/random/structure.dm index 2d65d944dfc..580f7ff1b9b 100644 --- a/code/game/objects/effects/spawners/random/structure.dm +++ b/code/game/objects/effects/spawners/random/structure.dm @@ -93,9 +93,8 @@ /obj/effect/spawner/random/structure/crate_empty/make_item(spawn_loc, type_path_to_make) var/obj/structure/closet/crate/peek_a_boo = ..() - if(istype(peek_a_boo)) - peek_a_boo.opened = prob(50) - peek_a_boo.update_appearance() + if(istype(peek_a_boo) && prob(50)) + peek_a_boo.open(special_effects = FALSE) //the crate appears immediatly out of thin air so no need to animate anything return peek_a_boo @@ -127,9 +126,8 @@ /obj/effect/spawner/random/structure/closet_empty/make_item(spawn_loc, type_path_to_make) var/obj/structure/closet/peek_a_boo = ..() - if(istype(peek_a_boo)) - peek_a_boo.opened = prob(50) - peek_a_boo.update_appearance() + if(istype(peek_a_boo) && prob(50)) + peek_a_boo.open(special_effects = FALSE) //the crate appears immediatly out of thin air so no need to animate anything return peek_a_boo diff --git a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm index db1c9612f99..b71c3aff611 100644 --- a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm +++ b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm @@ -53,7 +53,8 @@ req_components = list( /obj/item/stack/sheet/glass = 2, /obj/item/stack/cable_coil = 5, - /datum/stock_part/capacitor = 1) + /datum/stock_part/capacitor = 1, + /obj/item/electronics/airlock = 1) /obj/item/circuitboard/machine/autolathe name = "Autolathe" diff --git a/code/game/objects/items/implants/implant_stealth.dm b/code/game/objects/items/implants/implant_stealth.dm index 00751d5f945..9a5a1f1c87a 100644 --- a/code/game/objects/items/implants/implant_stealth.dm +++ b/code/game/objects/items/implants/implant_stealth.dm @@ -17,19 +17,15 @@ move_speed_multiplier = 0.5 enable_door_overlay = FALSE -/obj/structure/closet/cardboard/agent/proc/go_invisible() - animate(src, , alpha = 0, time = 20) - /obj/structure/closet/cardboard/agent/Initialize(mapload) . = ..() go_invisible() -/obj/structure/closet/cardboard/agent/open(mob/living/user, force = FALSE) +/obj/structure/closet/cardboard/agent/proc/go_invisible() + animate(src, alpha = 0, time = 20) + +/obj/structure/closet/cardboard/agent/after_open(mob/living/user) . = ..() - - if(!.) - return - qdel(src) /obj/structure/closet/cardboard/agent/process() diff --git a/code/game/objects/items/mail.dm b/code/game/objects/items/mail.dm index 8d4ef47c0ec..149e4968402 100644 --- a/code/game/objects/items/mail.dm +++ b/code/game/objects/items/mail.dm @@ -215,19 +215,21 @@ name = "mail crate" desc = "A certified post crate from CentCom." icon_state = "mail" + base_icon_state = "mail" can_install_electronics = FALSE lid_icon_state = "maillid" lid_x = -26 lid_y = 2 + paint_jobs = null /obj/structure/closet/crate/mail/update_icon_state() . = ..() if(opened) - icon_state = "[initial(icon_state)]open" + icon_state = "[base_icon_state]open" if(locate(/obj/item/mail) in src) - icon_state = initial(icon_state) + icon_state = base_icon_state else - icon_state = "[initial(icon_state)]sealed" + icon_state = "[base_icon_state]sealed" /// Fills this mail crate with N pieces of mail, where N is the lower of the amount var passed, and the maximum capacity of this crate. If N is larger than the number of alive human players, the excess will be junkmail. /obj/structure/closet/crate/mail/proc/populate(amount) @@ -275,6 +277,11 @@ populate(INFINITY) +/// Opened mail crate +/obj/structure/closet/crate/mail/preopen + opened = TRUE + icon_state = "mailopen" + /// Mailbag. /obj/item/storage/bag/mail name = "mail bag" diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 2fada65d116..93460ba0f64 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -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 diff --git a/code/game/objects/structures/crates_lockers/closets/bodybag.dm b/code/game/objects/structures/crates_lockers/closets/bodybag.dm index 5e5cee3d276..50cd91fc56b 100644 --- a/code/game/objects/structures/crates_lockers/closets/bodybag.dm +++ b/code/game/objects/structures/crates_lockers/closets/bodybag.dm @@ -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) diff --git a/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm b/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm index c25b4b27cf0..e2b16478bb0 100644 --- a/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm +++ b/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm @@ -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() diff --git a/code/game/objects/structures/crates_lockers/closets/infinite.dm b/code/game/objects/structures/crates_lockers/closets/infinite.dm index 9afab3ddd20..7bd25e54b46 100644 --- a/code/game/objects/structures/crates_lockers/closets/infinite.dm +++ b/code/game/objects/structures/crates_lockers/closets/infinite.dm @@ -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() diff --git a/code/game/objects/structures/crates_lockers/closets/secure/bar.dm b/code/game/objects/structures/crates_lockers/closets/secure/bar.dm index eabfae7ab15..cb5a70e8440 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/bar.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/bar.dm @@ -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() ..() diff --git a/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm b/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm index ae076da40cd..5091c01eacc 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm @@ -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." diff --git a/code/game/objects/structures/crates_lockers/closets/secure/personal.dm b/code/game/objects/structures/crates_lockers/closets/secure/personal.dm index d85f5f26d37..93fea8a2343 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/personal.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/personal.dm @@ -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 diff --git a/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm b/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm index 87058f0b5d7..1fad4a1c902 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm @@ -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 diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm index 9657de5cf24..86be18f5357 100755 --- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm @@ -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("Right-click 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() ..() diff --git a/code/game/objects/structures/crates_lockers/closets/syndicate.dm b/code/game/objects/structures/crates_lockers/closets/syndicate.dm index 9ee9f0e1473..eae92151cab 100644 --- a/code/game/objects/structures/crates_lockers/closets/syndicate.dm +++ b/code/game/objects/structures/crates_lockers/closets/syndicate.dm @@ -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 diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm index c46c9d06fbe..cd7c701baef 100644 --- a/code/game/objects/structures/crates_lockers/crates.dm +++ b/code/game/objects/structures/crates_lockers/crates.dm @@ -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() . = ..() diff --git a/code/game/objects/structures/crates_lockers/crates/bins.dm b/code/game/objects/structures/crates_lockers/crates/bins.dm index 867ede6d88d..e13c671e1a3 100644 --- a/code/game/objects/structures/crates_lockers/crates/bins.dm +++ b/code/game/objects/structures/crates_lockers/crates/bins.dm @@ -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) . = ..() diff --git a/code/game/objects/structures/crates_lockers/crates/cardboard.dm b/code/game/objects/structures/crates_lockers/crates/cardboard.dm index b29b8f9138e..b4d14751a65 100644 --- a/code/game/objects/structures/crates_lockers/crates/cardboard.dm +++ b/code/game/objects/structures/crates_lockers/crates/cardboard.dm @@ -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" diff --git a/code/game/objects/structures/crates_lockers/crates/critter.dm b/code/game/objects/structures/crates_lockers/crates/critter.dm index 6f27595b8d8..a89d82ea0ea 100644 --- a/code/game/objects/structures/crates_lockers/crates/critter.dm +++ b/code/game/objects/structures/crates_lockers/crates/critter.dm @@ -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 diff --git a/code/game/objects/structures/crates_lockers/crates/large.dm b/code/game/objects/structures/crates_lockers/crates/large.dm index 22340400b3b..ef6e25d343c 100644 --- a/code/game/objects/structures/crates_lockers/crates/large.dm +++ b/code/game/objects/structures/crates_lockers/crates/large.dm @@ -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 diff --git a/code/game/objects/structures/crates_lockers/crates/secure.dm b/code/game/objects/structures/crates_lockers/crates/secure.dm index 4698c8469d2..aa6284e298e 100644 --- a/code/game/objects/structures/crates_lockers/crates/secure.dm +++ b/code/game/objects/structures/crates_lockers/crates/secure.dm @@ -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. diff --git a/code/game/objects/structures/crates_lockers/crates/syndicrate.dm b/code/game/objects/structures/crates_lockers/crates/syndicrate.dm index b18321338c4..b58686cc343 100644 --- a/code/game/objects/structures/crates_lockers/crates/syndicrate.dm +++ b/code/game/objects/structures/crates_lockers/crates/syndicrate.dm @@ -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 diff --git a/code/game/objects/structures/crates_lockers/crates/wooden.dm b/code/game/objects/structures/crates_lockers/crates/wooden.dm index 544662f9cc1..a5e0b78cadb 100644 --- a/code/game/objects/structures/crates_lockers/crates/wooden.dm +++ b/code/game/objects/structures/crates_lockers/crates/wooden.dm @@ -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" diff --git a/code/modules/cargo/supplypod.dm b/code/modules/cargo/supplypod.dm index c76a10ee9ae..e2df91c342a 100644 --- a/code/modules/cargo/supplypod.dm +++ b/code/modules/cargo/supplypod.dm @@ -210,7 +210,7 @@ /obj/structure/closet/supplypod/toggle(mob/living/user) return -/obj/structure/closet/supplypod/open(mob/living/user, force = FALSE) +/obj/structure/closet/supplypod/open(mob/living/user, force = FALSE, special_effects = TRUE) return /obj/structure/closet/supplypod/proc/handleReturnAfterDeparting(atom/movable/holder = src) @@ -434,16 +434,19 @@ opened = TRUE set_density(FALSE) update_appearance() + after_open(null, FALSE) /obj/structure/closet/supplypod/extractionpod/setOpened() opened = TRUE set_density(TRUE) update_appearance() + after_open(null, FALSE) /obj/structure/closet/supplypod/setClosed() //Ditto opened = FALSE set_density(TRUE) update_appearance() + after_close(null, FALSE) /obj/structure/closet/supplypod/proc/tryMakeRubble(turf/T) //Ditto if (rubble_type == RUBBLE_NONE) diff --git a/code/modules/jobs/access.dm b/code/modules/jobs/access.dm index 8b29d83c941..021e5812d1e 100644 --- a/code/modules/jobs/access.dm +++ b/code/modules/jobs/access.dm @@ -29,15 +29,10 @@ //If the mob is holding a valid ID, we let them in. get_active_held_item() is on the mob level, so no need to copypasta everywhere. else if(check_access(accessor.get_active_held_item())) return TRUE - //if they are wearing a card that has access, that works - else if(ishuman(accessor)) - var/mob/living/carbon/human/human_accessor = accessor - if(check_access(human_accessor.wear_id)) - return TRUE - //if they have a hacky abstract animal ID with the required access, let them in i guess... - else if(isanimal(accessor)) - var/mob/living/simple_animal/animal = accessor - if(check_access(animal.access_card)) + //if they are carying a card that has access, that works + else if(isliving(accessor)) + var/mob/living/being = accessor + if(check_access(being.get_idcard(TRUE))) return TRUE else if(isbrain(accessor) && istype(accessor.loc, /obj/item/mmi)) var/obj/item/mmi/brain_mmi = accessor.loc diff --git a/code/modules/mapfluff/ruins/lavalandruin_code/elephantgraveyard.dm b/code/modules/mapfluff/ruins/lavalandruin_code/elephantgraveyard.dm index b9668c1f83b..fc52a488b87 100644 --- a/code/modules/mapfluff/ruins/lavalandruin_code/elephantgraveyard.dm +++ b/code/modules/mapfluff/ruins/lavalandruin_code/elephantgraveyard.dm @@ -128,20 +128,42 @@ desc = "A marked patch of soil, showing signs of a burial long ago. You wouldn't disturb a grave... right?" icon = 'icons/obj/storage/crates.dmi' icon_state = "grave" + base_icon_state = "grave" dense_when_open = TRUE material_drop = /obj/item/stack/ore/glass/basalt material_drop_amount = 5 anchorable = FALSE anchored = TRUE - locked = TRUE divable = FALSE //As funny as it may be, it would make little sense how you got yourself inside it in first place. breakout_time = 90 SECONDS open_sound = 'sound/effects/shovel_dig.ogg' close_sound = 'sound/effects/shovel_dig.ogg' cutting_tool = /obj/item/shovel + can_install_electronics = FALSE + paint_jobs = null + var/lead_tomb = FALSE var/first_open = FALSE - can_install_electronics = FALSE + var/grave_dug_open = FALSE + +/obj/structure/closet/crate/grave/before_open(mob/living/user, force) + . = ..() + if(!.) + return FALSE + + if(!force && !grave_dug_open) + balloon_alert(user, "use a shovel!") + return FALSE + + return TRUE + +/obj/structure/closet/crate/grave/before_close(mob/living/user) + . = ..() + if(!.) + return FALSE + + balloon_alert(user, "already open!") + return FALSE /obj/structure/closet/crate/grave/filled/PopulateContents() //GRAVEROBBING IS NOW A FEATURE ..() @@ -172,12 +194,6 @@ //empty grave return -/obj/structure/closet/crate/grave/open(mob/living/user, obj/item/S, force = FALSE) - if(!opened) - to_chat(user, span_notice("The ground here is too hard to dig up with your bare hands. You'll need a shovel.")) - else - to_chat(user, span_notice("The grave has already been dug up.")) - /obj/structure/closet/crate/grave/closet_update_overlays(list/new_overlays) return @@ -187,10 +203,8 @@ if(istype(S,cutting_tool) && S.tool_behaviour == TOOL_SHOVEL) to_chat(user, span_notice("You start start to dig open \the [src] with \the [S]...")) if (do_after(user,20, target = src)) - opened = TRUE - locked = TRUE - dump_contents() - update_appearance() + grave_dug_open = TRUE + open(user, force = TRUE) user.add_mood_event("graverobbing", /datum/mood_event/graverobbing) if(lead_tomb == TRUE && first_open == TRUE) user.gain_trauma(/datum/brain_trauma/magic/stalker) @@ -215,13 +229,6 @@ return 1 return -/obj/structure/closet/crate/grave/bust_open() - ..() - opened = TRUE - update_appearance() - dump_contents() - return - /obj/structure/closet/crate/grave/filled/lead_researcher name = "ominous burial mound" desc = "Even in a place filled to the brim with graves, this one shows a level of preperation and planning that fills you with dread." diff --git a/code/modules/mining/abandoned_crates.dm b/code/modules/mining/abandoned_crates.dm index 99ed31e5c40..f0f95b4d64e 100644 --- a/code/modules/mining/abandoned_crates.dm +++ b/code/modules/mining/abandoned_crates.dm @@ -4,6 +4,7 @@ name = "abandoned crate" desc = "What could be inside?" icon_state = "securecrate" + base_icon_state = "securecrate" integrity_failure = 0 //no breaking open the crate var/code = null var/lastattempt = null @@ -124,7 +125,7 @@ return return ..() -/obj/structure/closet/crate/secure/loot/open(mob/living/user, force = FALSE) +/obj/structure/closet/crate/secure/loot/after_open(mob/living/user, force) . = ..() if(qdel_on_open) qdel(src) diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm index de4a7e924f6..6d422157a24 100644 --- a/code/modules/mining/lavaland/necropolis_chests.dm +++ b/code/modules/mining/lavaland/necropolis_chests.dm @@ -4,8 +4,10 @@ name = "necropolis chest" desc = "It's watching you closely." icon_state = "necrocrate" + base_icon_state = "necrocrate" resistance_flags = LAVA_PROOF | FIRE_PROOF | ACID_PROOF can_install_electronics = FALSE + paint_jobs = null /obj/structure/closet/crate/necropolis/tendril desc = "It's watching you suspiciously. You need a skeleton key to open it." @@ -76,10 +78,16 @@ qdel(item) to_chat(user, span_notice("You disable the magic lock, revealing the loot.")) -/obj/structure/closet/crate/necropolis/tendril/can_open(mob/living/user, force = FALSE) - if(!spawned_loot) +/obj/structure/closet/crate/necropolis/tendril/before_open(mob/living/user, force) + . = ..() + if(!.) return FALSE - return ..() + + if(!broken && !force && !spawned_loot) + balloon_alert(user, "its locked!") + return FALSE + + return TRUE //Megafauna chests diff --git a/code/modules/mining/mine_items.dm b/code/modules/mining/mine_items.dm index 411d8ac238a..e115bd9af01 100644 --- a/code/modules/mining/mine_items.dm +++ b/code/modules/mining/mine_items.dm @@ -129,3 +129,4 @@ desc = "A mining car. This one doesn't work on rails, but has to be dragged." name = "Mining car (not for rails)" icon_state = "miningcar" + base_icon_state = "miningcar" diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm index bbea6b6fe00..fcf792da957 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm @@ -580,6 +580,7 @@ density = TRUE anchored = TRUE resistance_flags = FIRE_PROOF | ACID_PROOF | INDESTRUCTIBLE + paint_jobs = null var/mob/living/simple_animal/holder_animal /obj/structure/closet/stasis/process() diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm index 9957c802c79..f3e45dd8f44 100644 --- a/code/modules/projectiles/projectile/magic.dm +++ b/code/modules/projectiles/projectile/magic.dm @@ -276,6 +276,7 @@ breakout_time = 600 icon_welded = null icon_state = "cursed" + paint_jobs = null var/weakened_icon = "decursed" var/auto_destroy = TRUE @@ -284,15 +285,14 @@ if(auto_destroy) addtimer(CALLBACK(src, PROC_REF(bust_open)), 5 MINUTES) +/obj/structure/closet/decay/after_open(mob/living/user, force) + . = ..() + unmagify() + /obj/structure/closet/decay/after_weld(weld_state) if(weld_state) unmagify() -/obj/structure/closet/decay/open(mob/living/user, force = FALSE) - . = ..() - if(.) - unmagify() - ///Give it the lesser magic icon and tell it to delete itself /obj/structure/closet/decay/proc/unmagify() icon_state = weakened_icon