mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-07-21 12:56:10 +01:00
Cargo elevator overhaul (#21430)
## About PR Implements an animation logic heavily inspired from CM-SS13 elevators. Elevator hatch and shaft sprites are courtesy of @KingOfThePing! Currently if something is standing on the hatches when the elevator is arriving, they'll be sent to CC level, fall, get paralyzed and severely injured enough to have broken bones/arterial bleeding. This PR also fixes cargo announcement screens not displaying elevator ETA. ## Images <details><summary>Elevator arriving</summary> <p> https://github.com/user-attachments/assets/34879994-d10b-4cb6-959e-314ec20411b8 </p> </details> <details><summary>Elevator departing</summary> <p> https://github.com/user-attachments/assets/c345fd3b-07eb-4922-9b28-31cf40842da1 </p> </details> <details><summary>Unfortunate victims falling to the pit</summary> <p> https://github.com/user-attachments/assets/98feac04-5d65-4383-8abc-363ce51a028a </p> </details> ### Asset Licenses The following assets that **have not** been created by myself are included in this PR: | Path | Original Author | License | | --- | --- | --- | | icons/effect/224x192.dmi | KingOfThePing | CC BY-SA 3.0 | | icons/obj/doors/retractable_railing.dmi | CM-SS13 | CC BY-SA 3.0 | | sound/machines/industrial_lift_raising.ogg | CM-SS13 | CC BY-SA 3.0 | | sound/machines/industrial_lift_lowering.ogg | CM-SS13 | CC BY-SA 3.0 | | sound/machines/warning-buzzer-2.ogg | Unknown - https://pixabay.com/sound-effects/incorrect-buzzer-sound-147336/ | Pixabay Licence |
This commit is contained in:
@@ -351,6 +351,7 @@
|
||||
icon_state = "stairs_railing"
|
||||
anchored = TRUE
|
||||
density = TRUE
|
||||
layer = ABOVE_ABOVE_HUMAN_LAYER
|
||||
|
||||
/obj/structure/stairs_railing/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
|
||||
if(mover?.movement_type & PHASING)
|
||||
|
||||
@@ -1,12 +1,84 @@
|
||||
/// Used for placing '/obj/effect/elevator' to the northern corners of the shaft.
|
||||
#define SHAFT_WIDTH 6
|
||||
/// Used for locating center of the shaft.
|
||||
#define SHAFT_CENTER_OFFSET 3
|
||||
#define ELEVATOR_DEPARTING_X 224
|
||||
#define ELEVATOR_DEPARTING_Y -96
|
||||
|
||||
/datum/shuttle/autodock/ferry/supply
|
||||
category = /datum/shuttle/autodock/ferry/supply
|
||||
var/away_location = 1 //the location to hide at while pretending to be in-transit
|
||||
/// The location to hide at while pretending to be in-transit.
|
||||
var/away_location = 1
|
||||
var/late_chance = 80
|
||||
var/max_late_time = 300
|
||||
|
||||
/// A list for step_triggers, used for toggling fall functionality. Making the elevator shaft tiles safe to stand or not depening on where the elevator is.
|
||||
var/list/step_trigger_group = list()
|
||||
|
||||
/// Elevator effects for each northern corners of the shaft. This way the entire elevator won't disappear if there's an opaque obstacle in the sight line of original turf.
|
||||
/// Later on hardcoded to have their icons positioned on top of each other.
|
||||
/// These contain elevator shaft sprite. '/obj/effect/elevator/animation_overlay/elevator_animation' is used as a masked layer onto this.
|
||||
var/obj/effect/elevator/NW
|
||||
var/obj/effect/elevator/NE
|
||||
|
||||
/// This effect will contain an image, copy of the turfs at CC supply shuttle zone. Added onto the elevator shaft effect as an off-centered overlay.
|
||||
var/obj/effect/elevator/animation_overlay/elevator_animation
|
||||
|
||||
/// Hatch layers. Works similar to 'elevator_animation'.
|
||||
var/obj/effect/elevator/animation_overlay/hatch/left/hatch_left
|
||||
var/obj/effect/elevator/animation_overlay/hatch/right/hatch_right
|
||||
|
||||
/// Locations caches for Horizon elevator bay.
|
||||
var/target_dest_x
|
||||
var/target_dest_y
|
||||
var/target_dest_z
|
||||
|
||||
/// Area cache of Horizon elevator bay.
|
||||
var/area/horizon_elevator_area
|
||||
|
||||
/datum/shuttle/autodock/ferry/supply/New(var/_name, var/obj/effect/shuttle_landmark/start_waypoint)
|
||||
..(_name, start_waypoint)
|
||||
SScargo.shuttle = src
|
||||
addtimer(CALLBACK(src, PROC_REF(prepare_elevator)), 1 MINUTE) // pseudo initialize. We give mapload some time before initializing rest of the properties
|
||||
|
||||
/datum/shuttle/autodock/ferry/supply/proc/prepare_elevator()
|
||||
var/obj/dest_helper = locate(/obj/effect/landmark/destination_helper/cargo_elevator)
|
||||
target_dest_x = dest_helper.x
|
||||
target_dest_y = dest_helper.y
|
||||
target_dest_z = dest_helper.z
|
||||
horizon_elevator_area = get_area(dest_helper)
|
||||
|
||||
var/center_dest_x = target_dest_x + SHAFT_CENTER_OFFSET
|
||||
var/group_number
|
||||
for(var/obj/effect/step_trigger/cargo_elevator/ST in horizon_elevator_area) // sorts step triggers by their distance to the shaft center
|
||||
group_number = "distance_[abs(ST.x - center_dest_x)]"
|
||||
LAZYADDASSOCLIST(step_trigger_group, group_number, ST)
|
||||
|
||||
elevator_animation = new /obj/effect/elevator/animation_overlay()
|
||||
elevator_animation.pixel_x = ELEVATOR_DEPARTING_X // 7 tiles
|
||||
elevator_animation.pixel_y = ELEVATOR_DEPARTING_Y // 3 tiles
|
||||
|
||||
hatch_left = new /obj/effect/elevator/animation_overlay/hatch/left()
|
||||
hatch_right = new /obj/effect/elevator/animation_overlay/hatch/right()
|
||||
|
||||
// North-West corner
|
||||
NW = new /obj/effect/elevator(get_turf(src))
|
||||
NW.pixel_y = -192 // 6 tiles
|
||||
NW.vis_contents += elevator_animation
|
||||
NW.vis_contents += hatch_left
|
||||
NW.vis_contents += hatch_right
|
||||
|
||||
// North-East corner
|
||||
NE = new /obj/effect/elevator(get_turf(src))
|
||||
NE.pixel_x = -192
|
||||
NE.pixel_y = -192
|
||||
NE.vis_contents += elevator_animation
|
||||
NE.vis_contents += hatch_left
|
||||
NE.vis_contents += hatch_right
|
||||
|
||||
// We position the shaft beforehand
|
||||
NW.forceMove(locate(target_dest_x, target_dest_y, target_dest_z))
|
||||
NE.forceMove(locate(target_dest_x + SHAFT_WIDTH, target_dest_y, target_dest_z))
|
||||
|
||||
/datum/shuttle/autodock/ferry/supply/short_jump(var/area/destination)
|
||||
if(moving_status != SHUTTLE_IDLE)
|
||||
@@ -26,9 +98,13 @@
|
||||
moving_status = SHUTTLE_IDLE
|
||||
return
|
||||
|
||||
if (!at_station()) //at centcom
|
||||
if (!at_station()) //at centcom
|
||||
if(!SScargo.buy()) //Check if the shuttle can be sent
|
||||
moving_status = SHUTTLE_IDLE //Dont move the shuttle
|
||||
return
|
||||
|
||||
flip_rotating_alarms() // elevator is coming up, prepare the lights
|
||||
playsound(locate(target_dest_x + SHAFT_CENTER_OFFSET, target_dest_y - SHAFT_CENTER_OFFSET, target_dest_z), 'sound/machines/warning-buzzer-2.ogg', 60, FALSE)
|
||||
|
||||
//We pretend it's a long_jump by making the shuttle stay at centcom for the "in-transit" period.
|
||||
var/obj/effect/shuttle_landmark/away_waypoint = get_location_waypoint(away_location)
|
||||
@@ -37,6 +113,7 @@
|
||||
//If we are at the away_landmark then we are just pretending to move, otherwise actually do the move
|
||||
if (next_location == away_waypoint)
|
||||
attempt_move(away_waypoint)
|
||||
play_elevator_animation(TRUE) // returning to CC, play the animation after elevator physically leaves
|
||||
|
||||
//wait ETA here.
|
||||
arrive_time = world.time + SScargo.movetime
|
||||
@@ -48,6 +125,7 @@
|
||||
if (prob(late_chance))
|
||||
sleep(rand(0,max_late_time))
|
||||
|
||||
play_elevator_animation() // coming from CC, play the animation before elevator physically arrives, delay the process
|
||||
attempt_move(destination)
|
||||
|
||||
moving_status = SHUTTLE_IDLE
|
||||
@@ -75,3 +153,162 @@
|
||||
/datum/shuttle/autodock/ferry/supply/proc/eta_minutes()
|
||||
var/ticksleft = arrive_time - world.time
|
||||
return round(ticksleft/600,1)
|
||||
|
||||
/**************************
|
||||
Elevator Animations
|
||||
***************************/
|
||||
|
||||
/datum/shuttle/autodock/ferry/supply/proc/play_elevator_animation(returning_to_CC = FALSE)
|
||||
// Positioning the shafts
|
||||
NW.forceMove(locate(target_dest_x, target_dest_y, target_dest_z))
|
||||
NE.forceMove(locate(target_dest_x + SHAFT_WIDTH, target_dest_y, target_dest_z))
|
||||
|
||||
for(var/area/A in shuttle_area) // an image copy of the elevator platform is prepared here
|
||||
for(var/turf/T in A)
|
||||
elevator_animation.vis_contents += T
|
||||
|
||||
if(!returning_to_CC)
|
||||
handle_arrival_sequence() // coming to Horizon
|
||||
else
|
||||
handle_departure_sequence() // leaving the Horizon
|
||||
|
||||
elevator_animation.vis_contents.Cut() // animation is done, we can get rid of the elevator platform image
|
||||
|
||||
/datum/shuttle/autodock/ferry/supply/proc/handle_arrival_sequence()
|
||||
var/obj/effect/step_trigger/cargo_elevator/trigger
|
||||
|
||||
playsound(locate(target_dest_x + SHAFT_CENTER_OFFSET, target_dest_y - SHAFT_CENTER_OFFSET, target_dest_z), 'sound/machines/industrial_lift_raising.ogg', 100, FALSE)
|
||||
|
||||
INVOKE_ASYNC(src, PROC_REF(handle_step_triggers))
|
||||
animate(hatch_left, pixel_x = -112, time = 5 SECONDS)
|
||||
animate(hatch_right, pixel_x = 112, time = 5 SECONDS)
|
||||
sleep(4 SECONDS)
|
||||
|
||||
animate(elevator_animation, pixel_x = 0, pixel_y = 0, time = 4 SECONDS)
|
||||
sleep(4.2 SECONDS)
|
||||
|
||||
for(var/group_key in step_trigger_group)
|
||||
for(trigger in step_trigger_group[group_key])
|
||||
trigger.safe_to_walk = TRUE
|
||||
|
||||
// We move the shafts away to avoid layering issues with turfs
|
||||
NW.moveToNullspace()
|
||||
NE.moveToNullspace()
|
||||
|
||||
addtimer(CALLBACK(src, PROC_REF(flip_rotating_alarms)), 4 SECONDS)
|
||||
addtimer(CALLBACK(src, PROC_REF(toggle_railings)), 2 SECONDS)
|
||||
|
||||
/datum/shuttle/autodock/ferry/supply/proc/handle_departure_sequence()
|
||||
flip_rotating_alarms()
|
||||
toggle_railings()
|
||||
sleep(2 SECONDS)
|
||||
|
||||
// checking for standers is redundant here, since the elevator won't leave if a forbidden type is standing
|
||||
// we also want to avoid sending people to CC level in a case where we don't immediately retrieve them back after doing so
|
||||
playsound(locate(target_dest_x + SHAFT_CENTER_OFFSET, target_dest_y - SHAFT_CENTER_OFFSET, target_dest_z), 'sound/machines/industrial_lift_lowering.ogg', 100, FALSE)
|
||||
animate(elevator_animation, pixel_x = ELEVATOR_DEPARTING_X, pixel_y = ELEVATOR_DEPARTING_Y, time = 4 SECONDS)
|
||||
sleep(4.2 SECONDS)
|
||||
|
||||
animate(hatch_left, pixel_x = 0, time = 5 SECONDS)
|
||||
animate(hatch_right, pixel_x = 0, time = 5 SECONDS)
|
||||
addtimer(CALLBACK(src, PROC_REF(flip_rotating_alarms)), 9 SECOND)
|
||||
|
||||
/// This attempts to sync up with hatch animation, by activating groups of step triggers in delayed order.
|
||||
/datum/shuttle/autodock/ferry/supply/proc/handle_step_triggers()
|
||||
var/obj/effect/step_trigger/cargo_elevator/trigger
|
||||
var/group_key
|
||||
for(var/i in 0 to 3)
|
||||
group_key = "distance_[i]"
|
||||
for(trigger in step_trigger_group[group_key]) // checking for the things standing on top of the hatch, then we send them to falling
|
||||
for(var/atom/movable/AM in get_turf(trigger))
|
||||
if(istype(AM, /obj/effect)) // avoid picking up step_triggers
|
||||
continue
|
||||
trigger.handle_falling(AM)
|
||||
trigger.safe_to_walk = FALSE
|
||||
|
||||
sleep(1 SECOND)
|
||||
|
||||
/datum/shuttle/autodock/ferry/supply/proc/flip_rotating_alarms()
|
||||
for(var/obj/machinery/rotating_alarm/RA in horizon_elevator_area)
|
||||
RA.toggle_state()
|
||||
|
||||
/datum/shuttle/autodock/ferry/supply/proc/toggle_railings()
|
||||
for(var/obj/structure/railing/retractable/R in horizon_elevator_area)
|
||||
R.toggle_state()
|
||||
|
||||
/obj/effect/landmark/destination_helper/cargo_elevator
|
||||
name = "cargo elevator destination helper"
|
||||
|
||||
/obj/effect/step_trigger/cargo_elevator
|
||||
name = "cargo elevator shaft"
|
||||
icon = 'icons/effects/map_effects.dmi'
|
||||
simulated = FALSE // this prevents the effects getting transported along with the elevator
|
||||
|
||||
/// List of turfs within the 'area/supply/dock'. Shared between all instances.
|
||||
var/static/list/possible_turfs_to_land_on = list()
|
||||
|
||||
/// Boolean, determines whether the movables should fall or not.
|
||||
var/safe_to_walk = TRUE
|
||||
|
||||
/obj/effect/step_trigger/cargo_elevator/Initialize()
|
||||
. = ..()
|
||||
if(!possible_turfs_to_land_on.len)
|
||||
possible_turfs_to_land_on = get_area_turfs(/area/supply/dock)
|
||||
|
||||
/obj/effect/step_trigger/cargo_elevator/Destroy()
|
||||
LAZYNULL(possible_turfs_to_land_on)
|
||||
return ..()
|
||||
|
||||
/obj/effect/step_trigger/cargo_elevator/Trigger(atom/movable/AM)
|
||||
if(safe_to_walk)
|
||||
return
|
||||
INVOKE_ASYNC(src, PROC_REF(handle_falling), AM)
|
||||
|
||||
/obj/effect/step_trigger/cargo_elevator/proc/handle_falling(atom/movable/AM)
|
||||
|
||||
if(!isliving(AM) && !isobj(AM)) // only mobs and objects
|
||||
return
|
||||
|
||||
if(isliving(AM))
|
||||
var/mob/living/L = AM
|
||||
if(L.CanAvoidGravity())
|
||||
return
|
||||
L.apply_effect(2, WEAKEN)
|
||||
|
||||
INVOKE_ASYNC(src, PROC_REF(animate_falling), AM) // this needs to run asynchronously, otherwise will cause issues
|
||||
|
||||
/obj/effect/step_trigger/cargo_elevator/proc/animate_falling(atom/movable/AM)
|
||||
sleep(0.1 SECOND) // allowing some time for mobs to get weaken effect applied
|
||||
var/oldalpha = AM.alpha
|
||||
var/oldcolor = AM.color
|
||||
var/old_pixel_y = AM.pixel_y
|
||||
animate(AM, transform = matrix() - matrix(), alpha = 0, color = rgb(0, 0, 0), time = 1 SECOND)
|
||||
|
||||
for(var/i in 1 to 5)
|
||||
//Make sure the item is still there after our sleep
|
||||
if(!AM || QDELETED(AM))
|
||||
return
|
||||
AM.pixel_y--
|
||||
sleep(0.2 SECONDS)
|
||||
|
||||
//Make sure the item is still there after our sleep
|
||||
if(!AM || QDELETED(AM))
|
||||
return
|
||||
|
||||
AM.visible_message(SPAN_WARNING("[AM] falls into [src]!"), SPAN_DANGER("You stumble and stare into \the [src] as you fall. It will be a long ride..."))
|
||||
AM.forceMove(pick(possible_turfs_to_land_on))
|
||||
|
||||
AM.alpha = oldalpha
|
||||
AM.color = oldcolor
|
||||
AM.transform = matrix()
|
||||
AM.pixel_y = old_pixel_y
|
||||
|
||||
if(isliving(AM))
|
||||
var/mob/living/L = AM
|
||||
L.adjustBruteLoss(rand(30,50))
|
||||
L.dir = pick(GLOB.cardinals)
|
||||
|
||||
#undef SHAFT_WIDTH
|
||||
#undef SHAFT_CENTER_OFFSET
|
||||
#undef ELEVATOR_DEPARTING_X
|
||||
#undef ELEVATOR_DEPARTING_Y
|
||||
|
||||
Reference in New Issue
Block a user