mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-07-12 00:20:42 +01:00
0ae5bc0574
fixes https://github.com/Aurorastation/Aurora.3/issues/22409 The reason for the increased elevator timer was due to how rarely it came up that the supplier time would be longer than the base 30 second timer, so instead the two timers were combined to trial how a longer timer would feel.
374 lines
14 KiB
Plaintext
374 lines
14 KiB
Plaintext
/// 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
|
|
/// 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
|
|
|
|
/// Underlays of the elevator saved before transit.
|
|
var/list/saved_underlays
|
|
|
|
/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 = SSshuttle.cargo_dest_helper
|
|
if(!dest_helper)
|
|
crash_with("No cargo destination helper found for the 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)
|
|
return
|
|
|
|
if(isnull(location))
|
|
return
|
|
|
|
//it would be cool to play a sound here
|
|
moving_status = SHUTTLE_WARMUP
|
|
spawn(warmup_time*10)
|
|
if (moving_status == SHUTTLE_IDLE)
|
|
return //someone cancelled the launch
|
|
|
|
if (at_station() && forbidden_atoms_check())
|
|
//cancel the launch because of forbidden atoms. announce over supply channel?
|
|
moving_status = SHUTTLE_IDLE
|
|
return
|
|
|
|
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)
|
|
moving_status = SHUTTLE_INTRANSIT
|
|
|
|
//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 = launch_estimate()
|
|
while (world.time <= arrive_time)
|
|
sleep(5)
|
|
|
|
if (next_location != away_waypoint)
|
|
//late
|
|
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
|
|
|
|
if (!at_station()) //at centcom
|
|
SScargo.sell()
|
|
|
|
// returns 1 if the supply shuttle should be prevented from moving because it contains forbidden atoms
|
|
/datum/shuttle/autodock/ferry/supply/proc/forbidden_atoms_check()
|
|
if (!at_station())
|
|
return 0 //if badmins want to send mobs or a nuke on the supply shuttle from centcom we don't care
|
|
|
|
for(var/area/A in shuttle_area)
|
|
if(SScargo.forbidden_atoms_check(A))
|
|
return 1
|
|
|
|
/datum/shuttle/autodock/ferry/supply/proc/at_station()
|
|
return (!location)
|
|
|
|
//returns 1 if the shuttle is idle and we can still mess with the cargo shopping list
|
|
/datum/shuttle/autodock/ferry/supply/proc/idle()
|
|
return (moving_status == SHUTTLE_IDLE)
|
|
|
|
/// returns the ETA in seconds
|
|
/datum/shuttle/autodock/ferry/supply/proc/eta_seconds()
|
|
var/ticksleft = arrive_time - world.time
|
|
if(ticksleft > 0)
|
|
return "[round(ticksleft/10,1)] seconds"
|
|
else
|
|
return "soon."
|
|
|
|
/// Gets the cargo moving time
|
|
/datum/shuttle/autodock/ferry/supply/proc/launch_estimate(var/in_seconds = FALSE)
|
|
var/time = world.time + SScargo.movetime
|
|
if(in_seconds)
|
|
time = time - world.time
|
|
return round(time/10,1)
|
|
else
|
|
return time
|
|
|
|
/**************************
|
|
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) // we have to do this here or we turn the elevator into a white cube
|
|
for(var/obj/structure/machinery/light/L in A) // we turn off lights to avoid having to fight the lighting plane
|
|
L.stat |= POWEROFF
|
|
L.update()
|
|
|
|
sleep(2 SECONDS)
|
|
|
|
elevator_animation.icon_state = "elevator_test"
|
|
|
|
for(var/area/A in shuttle_area) // an image copy of the elevator platform is prepared here
|
|
for(var/turf/T in A)
|
|
LAZYADDASSOC(saved_underlays, T, T.underlays)
|
|
T.underlays.Cut()
|
|
elevator_animation.vis_contents += T
|
|
for(var/atom/movable/AM in T.contents)
|
|
AM.blocks_emissive = FALSE
|
|
AM.update_emissive_blocker()
|
|
|
|
if(!returning_to_CC)
|
|
handle_arrival_sequence() // coming to Horizon
|
|
else
|
|
handle_departure_sequence() // leaving the Horizon
|
|
|
|
for(var/turf/T in elevator_animation.vis_contents)
|
|
T.underlays = LAZYACCESS(saved_underlays, T)
|
|
LAZYREMOVE(saved_underlays, T)
|
|
for(var/atom/movable/AM in T.contents)
|
|
AM.blocks_emissive = initial(AM.blocks_emissive)
|
|
AM.update_emissive_blocker()
|
|
AM.update_light()
|
|
for(var/obj/structure/machinery/light/L in T.contents)
|
|
L.stat &= ~POWEROFF
|
|
L.update()
|
|
|
|
elevator_animation.icon_state = null
|
|
|
|
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/structure/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/landmark/destination_helper/cargo_elevator/Initialize(mapload)
|
|
..()
|
|
return INITIALIZE_HINT_LATELOAD
|
|
|
|
/obj/effect/landmark/destination_helper/cargo_elevator/LateInitialize()
|
|
. = ..()
|
|
if(SSshuttle.cargo_dest_helper)
|
|
log_and_message_admins("Multiple cargo destination helpers detected; overriding.")
|
|
SSshuttle.cargo_dest_helper = src
|
|
|
|
/obj/effect/landmark/destination_helper/cargo_elevator/Destroy()
|
|
if(SSshuttle.cargo_dest_helper == src)
|
|
SSshuttle.cargo_dest_helper = null
|
|
return ..()
|
|
|
|
/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
|