diff --git a/code/game/objects/effects/overlays.dm b/code/game/objects/effects/overlays.dm index 855f5987692..5165c109120 100644 --- a/code/game/objects/effects/overlays.dm +++ b/code/game/objects/effects/overlays.dm @@ -65,3 +65,11 @@ mouse_opacity = MOUSE_OPACITY_TRANSPARENT plane = ATMOS_GROUP_PLANE + +/// Door overlay for animating closets +/obj/effect/overlay/closet_door + anchored = TRUE + plane = FLOAT_PLANE + layer = FLOAT_LAYER + vis_flags = VIS_INHERIT_ID + appearance_flags = KEEP_TOGETHER | LONG_GLIDE | PIXEL_SCALE diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 0c553a087e8..79328a94c78 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -12,12 +12,24 @@ armor = list(MELEE = 20, BULLET = 10, LASER = 10, ENERGY = 0, BOMB = 10, BIO = 0, RAD = 0, FIRE = 70, ACID = 60) blocks_emissive = EMISSIVE_BLOCK_GENERIC + /// The overlay for the closet's door + var/obj/effect/overlay/closet_door/door_obj + /// Whether or not this door is being animated + var/is_animating_door = FALSE + /// Vertical squish of the door + var/door_anim_squish = 0.12 + /// The maximum angle the door will be drawn at + var/door_anim_angle = 136 + /// X position of the closet door hinge + 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 + /// 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/icon_door_override = FALSE //override to have open overlay use icon different to its base's 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 @@ -66,6 +78,7 @@ /obj/structure/closet/Destroy() dump_contents() + QDEL_NULL(door_obj) return ..() /obj/structure/closet/update_appearance(updates=ALL) @@ -88,9 +101,9 @@ /obj/structure/closet/proc/closet_update_overlays(list/new_overlays) . = new_overlays - if(enable_door_overlay) + if(enable_door_overlay && !is_animating_door) if(opened && has_opened_overlay) - var/mutable_appearance/door_overlay = mutable_appearance(icon, "[icon_door_override ? icon_door : icon_state]_open", alpha = src.alpha) + var/mutable_appearance/door_overlay = mutable_appearance(icon, "[icon_state]_open", alpha = src.alpha) . += door_overlay door_overlay.overlays += emissive_blocker(door_overlay.icon, door_overlay.icon_state, 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) @@ -108,6 +121,56 @@ . += emissive_appearance(icon, "locked", alpha = src.alpha) . += locked ? "locked" : "unlocked" +/// Animates the closet door opening and closing +/obj/structure/closet/proc/animate_door(closing = FALSE) + if(!door_anim_time) + return + if(!door_obj) + door_obj = new + var/default_door_icon = "[icon_door || icon_state]_door" + vis_contents += door_obj + door_obj.icon = icon + door_obj.icon_state = default_door_icon + is_animating_door = TRUE + var/num_steps = door_anim_time / world.tick_lag + + 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 + + if (angle >= 90) + door_state = "[icon_state]_back" + door_layer = FLOAT_LAYER + else + door_state = default_door_icon + door_layer = ABOVE_MOB_LAYER + + if(step == 0) + door_obj.transform = door_transform + door_obj.icon_state = door_state + door_obj.layer = door_layer + else if(step == 1) + animate(door_obj, transform = door_transform, icon_state = door_state, layer = door_layer, time = world.tick_lag, flags = ANIMATION_END_NOW) + else + animate(transform = door_transform, icon_state = door_state, layer = door_layer, time = world.tick_lag) + addtimer(CALLBACK(src, .proc/end_door_animation), door_anim_time, TIMER_UNIQUE|TIMER_OVERRIDE|TIMER_CLIENT_TIME) + +/// Ends the door animation and removes the animated overlay +/obj/structure/closet/proc/end_door_animation() + is_animating_door = FALSE + vis_contents -= door_obj + update_icon() + +/// Calculates the matrix to be applied to the animated door overlay +/obj/structure/closet/proc/get_door_transform(angle) + var/matrix/door_matrix = matrix() + door_matrix.Translate(-door_hinge_x, 0) + door_matrix.Multiply(matrix(cos(angle), 0, 0, -sin(angle) * door_anim_squish, 1, 0)) + door_matrix.Translate(door_hinge_x, 0) + return door_matrix + /obj/structure/closet/examine(mob/user) . = ..() if(welded) @@ -187,6 +250,7 @@ if(!dense_when_open) set_density(FALSE) dump_contents() + animate_door(FALSE) update_appearance() after_open(user, force) return TRUE @@ -244,6 +308,7 @@ playsound(loc, close_sound, close_sound_volume, TRUE, -3) opened = FALSE set_density(TRUE) + animate_door(TRUE) update_appearance() after_close(user) return TRUE diff --git a/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm b/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm index b77b6f76ac8..6433c13536b 100644 --- a/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm +++ b/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm @@ -17,6 +17,7 @@ open_sound_volume = 35 close_sound_volume = 35 has_closed_overlay = FALSE + door_anim_time = 0 // no animation var/move_speed_multiplier = 1 var/move_delay = FALSE var/egged = 0 diff --git a/code/game/objects/structures/crates_lockers/closets/gimmick.dm b/code/game/objects/structures/crates_lockers/closets/gimmick.dm index 75034bf7d15..0f89b5ffd39 100644 --- a/code/game/objects/structures/crates_lockers/closets/gimmick.dm +++ b/code/game/objects/structures/crates_lockers/closets/gimmick.dm @@ -8,6 +8,7 @@ open_sound_volume = 25 close_sound_volume = 50 max_integrity = 70 + door_anim_time = 0 // no animation /obj/structure/closet/acloset name = "strange closet" 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 0ae99bc8429..0dc35bba837 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/bar.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/bar.dm @@ -8,6 +8,7 @@ close_sound = 'sound/machines/wooden_closet_close.ogg' open_sound_volume = 25 close_sound_volume = 50 + door_anim_time = 0 // no animation /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 a497f03780b..11255b24bd5 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/freezer.dm @@ -1,6 +1,9 @@ /obj/structure/closet/secure_closet/freezer icon_state = "freezer" flags_1 = PREVENT_CONTENTS_EXPLOSION_1 + door_anim_squish = 0.22 + door_anim_angle = 123 + door_anim_time = 4 var/jones = FALSE /obj/structure/closet/secure_closet/freezer/Destroy() 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 4cb6b9735a7..203b35ceb59 100755 --- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm @@ -179,6 +179,7 @@ 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' diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm index 9bc8e456c0d..437af93a01c 100644 --- a/code/game/objects/structures/crates_lockers/crates.dm +++ b/code/game/objects/structures/crates_lockers/crates.dm @@ -15,6 +15,7 @@ open_sound_volume = 35 close_sound_volume = 50 drag_slowdown = 0 + door_anim_time = 0 // no animation var/crate_climb_time = 20 var/obj/item/paper/fluff/jobs/cargo/manifest/manifest diff --git a/code/modules/antagonists/abductor/equipment/abduction_gear.dm b/code/modules/antagonists/abductor/equipment/abduction_gear.dm index 2f62af27284..451e83d124a 100644 --- a/code/modules/antagonists/abductor/equipment/abduction_gear.dm +++ b/code/modules/antagonists/abductor/equipment/abduction_gear.dm @@ -847,6 +847,7 @@ Congratulations! You are now trained for invasive xenobiology research!"} icon_state = "abductor" icon_door = "abductor" can_weld_shut = FALSE + door_anim_time = 0 material_drop = /obj/item/stack/sheet/mineral/abductor /obj/structure/door_assembly/door_assembly_abductor diff --git a/icons/obj/closet.dmi b/icons/obj/closet.dmi index 9b55964d9c2..154e18c6d71 100644 Binary files a/icons/obj/closet.dmi and b/icons/obj/closet.dmi differ