mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-12 18:51:53 +00:00
## About The Pull Request <details> - renamed ai folder to announcer -- announcer -- - moved vox_fem to announcer - moved approachingTG to announcer - separated the ambience folder into ambience and instrumental -- ambience -- - created holy folder moved all related sounds there - created engineering folder and moved all related sounds there - created security folder and moved ambidet there - created general folder and moved ambigen there - created icemoon folder and moved all icebox-related ambience there - created medical folder and moved all medbay-related ambi there - created ruin folder and moves all ruins ambi there - created beach folder and moved seag and shore there - created lavaland folder and moved related ambi there - created aurora_caelus folder and placed its ambi there - created misc folder and moved the rest of the files that don't have a specific category into it -- instrumental -- - moved traitor folder here - created lobby_music folder and placed our songs there (title0 not used anywhere? - server-side modification?) -- items -- - moved secdeath to hailer - moved surgery to handling -- effects -- - moved chemistry into effects - moved hallucinations into effects - moved health into effects - moved magic into effects -- vehicles -- - moved mecha into vehicles created mobs folder -- mobs -- - moved creatures folder into mobs - moved voice into mobs renamed creatures to non-humanoids renamed voice to humanoids -- non-humanoids-- created cyborg folder created hiss folder moved harmalarm.ogg to cyborg -- humanoids -- -- misc -- moved ghostwhisper to misc moved insane_low_laugh to misc I give up trying to document this. </details> - [X] ambience - [x] announcer - [x] effects - [X] instrumental - [x] items - [x] machines - [x] misc - [X] mobs - [X] runtime - [X] vehicles - [ ] attributions ## Why It's Good For The Game This folder is so disorganized that it's vomit inducing, will make it easier to find and add new sounds, providng a minor structure to the sound folder. ## Changelog 🆑 grungussuss refactor: the sound folder in the source code has been reorganized, please report any oddities with sounds playing or not playing server: lobby music has been repathed to sound/music/lobby_music /🆑
641 lines
25 KiB
Plaintext
641 lines
25 KiB
Plaintext
/// If anyone changes the hydraulic sound effect I sure hope they update this...
|
|
#define HYDRAULIC_SFX_DURATION (2 SECONDS)
|
|
|
|
///coordinate and control movement across linked transport_controllers. allows moving large single multitile platforms and many 1 tile platforms.
|
|
///also is capable of linking platforms across linked z levels
|
|
/datum/transport_controller/linear
|
|
///the lift platforms we consider as part of this transport. ordered in order of lowest z level to highest z level after init.
|
|
///(the sorting algorithm sucks btw)
|
|
var/list/obj/structure/transport/linear/transport_modules
|
|
|
|
/// Typepath list of what to ignore smashing through, controls all lifts
|
|
var/static/list/ignored_smashthroughs = list(
|
|
/obj/machinery/power/supermatter_crystal,
|
|
/obj/structure/holosign,
|
|
/obj/machinery/field,
|
|
/obj/structure/fluff/tram_rail,
|
|
)
|
|
|
|
///whether the lift handled by this transport_controller datum is multitile as opposed to nxm platforms per z level
|
|
var/modular_set = FALSE
|
|
|
|
///taken from our lift platforms. if true we go through each z level of platforms and attempt to make the lowest left corner platform
|
|
///into one giant multitile object the size of all other platforms on that z level.
|
|
var/create_modular_set = FALSE
|
|
|
|
///lift platforms have already been sorted in order of z level.
|
|
var/z_sorted = FALSE
|
|
|
|
///transport_id taken from our base lift platform, used to put us into SStransport.transports_by_type
|
|
var/transport_id = TRANSPORT_TYPE_ELEVATOR
|
|
|
|
///overridable ID string to link control units to this specific transport_controller datum. created by placing a transport id landmark object
|
|
///somewhere on the tram, if its anywhere on the tram we'll find it in init and set this to whatever it specifies
|
|
var/specific_transport_id
|
|
|
|
///bitfield of various transport states
|
|
var/controller_status = NONE
|
|
|
|
/// probability of being thrown hard during an emergency stop
|
|
var/throw_chance = 17.5
|
|
|
|
/datum/transport_controller/linear/New(obj/structure/transport/linear/transport_module)
|
|
transport_id = transport_module.transport_id
|
|
create_modular_set = transport_module.create_modular_set
|
|
|
|
link_transport_modules(transport_module)
|
|
ignored_smashthroughs = typecacheof(ignored_smashthroughs)
|
|
|
|
LAZYADDASSOCLIST(SStransport.transports_by_type, transport_id, src)
|
|
|
|
for(var/obj/structure/transport/linear/lift as anything in transport_modules)
|
|
lift.add_initial_contents()
|
|
|
|
/datum/transport_controller/linear/Destroy()
|
|
for(var/obj/structure/transport/linear/transport_module as anything in transport_modules)
|
|
transport_module.transport_controller_datum = null
|
|
transport_modules = null
|
|
|
|
LAZYREMOVEASSOC(SStransport.transports_by_type, transport_id, src)
|
|
if(isnull(SStransport.transports_by_type))
|
|
SStransport.transports_by_type = list()
|
|
|
|
return ..()
|
|
|
|
/datum/transport_controller/linear/proc/add_transport_modules(obj/structure/transport/linear/new_transport_module)
|
|
if(new_transport_module in transport_modules)
|
|
return
|
|
for(var/obj/structure/transport/linear/other_module in new_transport_module.loc)
|
|
if(other_module != new_transport_module)
|
|
stack_trace("there is more than one transport module on a tile when a controller adds it. this causes problems")
|
|
qdel(other_module)
|
|
|
|
new_transport_module.transport_controller_datum = src
|
|
LAZYADD(transport_modules, new_transport_module)
|
|
RegisterSignal(new_transport_module, COMSIG_QDELETING, PROC_REF(remove_transport_modules))
|
|
|
|
check_for_landmarks(new_transport_module)
|
|
|
|
if(z_sorted)//make sure we dont lose z ordering if we get additional platforms after init
|
|
order_platforms_by_z_level()
|
|
|
|
/datum/transport_controller/linear/proc/remove_transport_modules(obj/structure/transport/linear/old_transport_module)
|
|
SIGNAL_HANDLER
|
|
|
|
if(!(old_transport_module in transport_modules))
|
|
return
|
|
|
|
old_transport_module.transport_controller_datum = null
|
|
LAZYREMOVE(transport_modules, old_transport_module)
|
|
UnregisterSignal(old_transport_module, COMSIG_QDELETING)
|
|
if(!length(transport_modules))
|
|
qdel(src)
|
|
|
|
///Collect all bordered platforms via a simple floodfill algorithm. allows multiz trams because its funny
|
|
/datum/transport_controller/linear/proc/link_transport_modules(obj/structure/transport/linear/base_transport_module)
|
|
add_transport_modules(base_transport_module)
|
|
var/list/possible_expansions = list(base_transport_module)
|
|
|
|
while(possible_expansions.len)
|
|
for(var/obj/structure/transport/linear/borderline as anything in possible_expansions)
|
|
var/list/result = borderline.module_adjacency(src)
|
|
if(length(result))
|
|
for(var/obj/structure/transport/linear/transport_module as anything in result)
|
|
if(transport_modules.Find(transport_module))
|
|
continue
|
|
|
|
add_transport_modules(transport_module)
|
|
possible_expansions |= transport_module
|
|
|
|
possible_expansions -= borderline
|
|
|
|
///check for any landmarks placed inside the locs of the given transport_module
|
|
/datum/transport_controller/linear/proc/check_for_landmarks(obj/structure/transport/linear/new_transport_module)
|
|
SHOULD_CALL_PARENT(TRUE)
|
|
|
|
for(var/turf/platform_loc as anything in new_transport_module.locs)
|
|
var/obj/effect/landmark/transport/transport_id/id_giver = locate() in platform_loc
|
|
|
|
if(id_giver)
|
|
set_info_from_id_landmark(id_giver)
|
|
|
|
///set vars and such given an overriding transport_id landmark
|
|
/datum/transport_controller/linear/proc/set_info_from_id_landmark(obj/effect/landmark/transport/transport_id/landmark)
|
|
SHOULD_CALL_PARENT(TRUE)
|
|
|
|
if(!istype(landmark, /obj/effect/landmark/transport/transport_id))//transport_controller subtypes can want differnet id's than the base type wants
|
|
return
|
|
|
|
if(landmark.specific_transport_id)
|
|
specific_transport_id = landmark.specific_transport_id
|
|
|
|
qdel(landmark)
|
|
|
|
///orders the lift platforms in order of lowest z level to highest z level.
|
|
/datum/transport_controller/linear/proc/order_platforms_by_z_level()
|
|
//contains nested lists for every z level in the world. why? because its really easy to sort
|
|
var/list/platforms_by_z = list()
|
|
platforms_by_z.len = world.maxz
|
|
|
|
for(var/z in 1 to world.maxz)
|
|
platforms_by_z[z] = list()
|
|
|
|
for(var/obj/structure/transport/linear/transport_module as anything in transport_modules)
|
|
if(QDELETED(transport_module) || !transport_module.z)
|
|
transport_modules -= transport_module
|
|
continue
|
|
|
|
platforms_by_z[transport_module.z] += transport_module
|
|
|
|
if(create_modular_set)
|
|
for(var/list/z_list as anything in platforms_by_z)
|
|
if(!length(z_list))
|
|
continue
|
|
|
|
create_modular_set_for_z_level(z_list)//this will subtract all but one platform from the list
|
|
|
|
var/list/output = list()
|
|
|
|
for(var/list/z_list as anything in platforms_by_z)
|
|
output += z_list
|
|
|
|
transport_modules = output
|
|
|
|
z_sorted = TRUE
|
|
|
|
///goes through all platforms in the given list and finds the one in the lower left corner
|
|
/datum/transport_controller/linear/proc/create_modular_set_for_z_level(list/obj/structure/transport/linear/platforms_in_z)
|
|
var/min_x = INFINITY
|
|
var/max_x = 0
|
|
|
|
var/min_y = INFINITY
|
|
var/max_y = 0
|
|
|
|
var/z = 0
|
|
|
|
for(var/obj/structure/transport/linear/module_to_sort as anything in platforms_in_z)
|
|
if(!z)
|
|
if(!module_to_sort.z)
|
|
stack_trace("create_modular_set_for_z_level() was given a platform in nullspace or not on a turf!")
|
|
platforms_in_z -= module_to_sort
|
|
continue
|
|
|
|
z = module_to_sort.z
|
|
|
|
if(z != module_to_sort.z)
|
|
stack_trace("create_modular_set_for_z_level() was given lifts on different z levels!")
|
|
platforms_in_z -= module_to_sort
|
|
continue
|
|
|
|
min_x = min(min_x, module_to_sort.x)
|
|
max_x = max(max_x, module_to_sort.x)
|
|
|
|
min_y = min(min_y, module_to_sort.y)
|
|
max_y = max(max_y, module_to_sort.y)
|
|
|
|
var/turf/lower_left_corner_loc = locate(min_x, min_y, z)
|
|
if(!lower_left_corner_loc)
|
|
CRASH("was unable to find a turf at the lower left corner of this z")
|
|
|
|
var/obj/structure/transport/linear/lower_left_corner_transport = locate() in lower_left_corner_loc
|
|
|
|
if(!lower_left_corner_transport)
|
|
CRASH("there was no transport in the lower left corner of the given transport")
|
|
|
|
platforms_in_z.Cut()
|
|
platforms_in_z += lower_left_corner_transport//we want to change the list given to us not create a new one. so we do this
|
|
|
|
lower_left_corner_transport.create_modular_set(min_x, min_y, max_x, max_y, z)
|
|
|
|
///returns the closest transport to the specified atom, prioritizing transports on the same z level. used for comparing distance
|
|
/datum/transport_controller/linear/proc/return_closest_platform_to(atom/comparison, allow_multiple_answers = FALSE)
|
|
if(!istype(comparison) || !comparison.z)
|
|
return FALSE
|
|
|
|
var/list/obj/structure/transport/linear/candidate_platforms = list()
|
|
|
|
for(var/obj/structure/transport/linear/platform as anything in transport_modules)
|
|
if(platform.z == comparison.z)
|
|
candidate_platforms += platform
|
|
|
|
var/obj/structure/transport/linear/winner = candidate_platforms[1]
|
|
var/winner_distance = get_dist(comparison, winner)
|
|
|
|
var/list/tied_winners = list(winner)
|
|
|
|
for(var/obj/structure/transport/linear/platform_to_sort as anything in candidate_platforms)
|
|
var/platform_distance = get_dist(comparison, platform_to_sort)
|
|
|
|
if(platform_distance < winner_distance)
|
|
winner = platform_to_sort
|
|
winner_distance = platform_distance
|
|
|
|
if(allow_multiple_answers)
|
|
tied_winners = list(winner)
|
|
|
|
else if(platform_distance == winner_distance && allow_multiple_answers)
|
|
tied_winners += platform_to_sort
|
|
|
|
if(allow_multiple_answers)
|
|
return tied_winners
|
|
|
|
return winner
|
|
|
|
/// Returns a platform on the z-level which is vertically closest to the passed target_z
|
|
/datum/transport_controller/linear/proc/return_closest_platform_to_z(target_z)
|
|
var/obj/structure/transport/linear/found_platform
|
|
for(var/obj/structure/transport/linear/lift as anything in transport_modules)
|
|
// Already at the same Z-level, we can stop
|
|
if(lift.z == target_z)
|
|
found_platform = lift
|
|
break
|
|
|
|
// Set up an initial lift to compare to
|
|
if(!found_platform)
|
|
found_platform = lift
|
|
continue
|
|
|
|
// Same level, we can go with the one we currently have
|
|
if(lift.z == found_platform.z)
|
|
continue
|
|
|
|
// If the difference between the current found platform and the target
|
|
// if less than the distance between the next lift and the target,
|
|
// our current platform is closer to the target than the next one, so we can skip it
|
|
if(abs(found_platform.z - target_z) < abs(lift.z - target_z))
|
|
continue
|
|
|
|
// The difference is smaller for this lift, so it's closer
|
|
found_platform = lift
|
|
|
|
return found_platform
|
|
|
|
/// Returns a list of all the z-levels our transport is currently on.
|
|
/datum/transport_controller/linear/proc/get_zs_we_are_on()
|
|
var/list/zs_we_are_present_on = list()
|
|
for(var/obj/structure/transport/linear/lift as anything in transport_modules)
|
|
zs_we_are_present_on |= lift.z
|
|
return zs_we_are_present_on
|
|
|
|
///returns all transport modules associated with this transport on the given z level or given atoms z level
|
|
/datum/transport_controller/linear/proc/get_platforms_on_level(atom/atom_reference_OR_z_level_number)
|
|
var/z = atom_reference_OR_z_level_number
|
|
if(isatom(atom_reference_OR_z_level_number))
|
|
z = atom_reference_OR_z_level_number.z
|
|
|
|
if(!isnum(z) || z < 0 || z > world.maxz)
|
|
return null
|
|
|
|
var/list/platforms_in_z = list()
|
|
|
|
for(var/obj/structure/transport/linear/lift_to_check as anything in transport_modules)
|
|
if(lift_to_check.z)
|
|
platforms_in_z += lift_to_check
|
|
|
|
return platforms_in_z
|
|
|
|
/**
|
|
* Moves the platform UP or DOWN, this is what users invoke with their hand.
|
|
* This is a SAFE proc, ensuring every part of it moves SANELY.
|
|
*
|
|
* Arguments:
|
|
* going - UP or DOWN directions, where the platform should go. Keep in mind by this point checks of whether it should go up or down have already been done.
|
|
* user - Whomever made the movement.
|
|
*/
|
|
/datum/transport_controller/linear/proc/move_lift_vertically(going, mob/user)
|
|
//transport_modules are sorted in order of lowest z to highest z, so going upwards we need to move them in reverse order to not collide
|
|
if(going == UP)
|
|
var/obj/structure/transport/linear/platform_to_move
|
|
var/current_index = length(transport_modules)
|
|
|
|
while(current_index > 0)
|
|
platform_to_move = transport_modules[current_index]
|
|
current_index--
|
|
|
|
platform_to_move.travel(going)
|
|
|
|
else if(going == DOWN)
|
|
for(var/obj/structure/transport/linear/transport_module as anything in transport_modules)
|
|
transport_module.travel(going)
|
|
|
|
/**
|
|
* Moves the platform after a passed delay.
|
|
*
|
|
* This is a more "user friendly" or "realistic" move.
|
|
* It includes things like:
|
|
* - Allowing platform "travel time"
|
|
* - Shutting elevator safety doors
|
|
* - Sound effects while moving
|
|
* - Safety warnings for anyone below the platform (while it's moving downwards)
|
|
*
|
|
* Arguments:
|
|
* duration - required, how long do we wait to move the platform?
|
|
* door_duration - optional, how long should we wait to open the doors after arriving? If null, we won't open or close doors
|
|
* direction - which direction are we moving the lift?
|
|
* user - optional, who is moving the lift?
|
|
*/
|
|
/datum/transport_controller/linear/proc/move_after_delay(lift_move_duration, door_duration, direction, mob/user)
|
|
if(!isnum(lift_move_duration))
|
|
CRASH("[type] move_after_delay called with invalid duration ([lift_move_duration]).")
|
|
if(lift_move_duration <= 0 SECONDS)
|
|
move_lift_vertically(direction, user)
|
|
return
|
|
|
|
// Get the lowest or highest platform according to which direction we're moving
|
|
var/obj/structure/transport/linear/prime_lift = return_closest_platform_to_z(direction == UP ? world.maxz : 0)
|
|
|
|
// ...because we use the duration of the sound effect to make it last for roughly the duration of the lift travel
|
|
playsound(prime_lift, 'sound/vehicles/mecha/hydraulic.ogg', 25, vary = TRUE, frequency = clamp(HYDRAULIC_SFX_DURATION / lift_move_duration, 0.33, 3))
|
|
|
|
// Move the platform after a timer
|
|
addtimer(CALLBACK(src, PROC_REF(move_lift_vertically), direction, user), lift_move_duration, TIMER_UNIQUE)
|
|
// Open doors after the set duration if supplied
|
|
if(isnum(door_duration))
|
|
addtimer(CALLBACK(src, PROC_REF(open_lift_doors_callback)), door_duration, TIMER_UNIQUE)
|
|
|
|
// Here on we only care about platforms going DOWN
|
|
if(direction != DOWN)
|
|
return
|
|
|
|
// Okay we're going down, let's try to display some warnings to people below
|
|
var/list/turf/lift_locs = list()
|
|
for(var/obj/structure/transport/linear/going_to_move as anything in transport_modules)
|
|
// This platform has no warnings so we don't even need to worry about it
|
|
if(!going_to_move.warns_on_down_movement)
|
|
continue
|
|
// Collect all the turfs our platform is found at
|
|
lift_locs |= going_to_move.locs
|
|
|
|
for(var/turf/moving in lift_locs)
|
|
// Find what's below the turf that's moving
|
|
var/turf/below_us = get_step_multiz(moving, DOWN)
|
|
// Hold up the turf below us is also in our locs list. Multi-z? Don't show a warning
|
|
if(below_us in lift_locs)
|
|
continue
|
|
// Display the warning for until we land
|
|
new /obj/effect/temp_visual/telegraphing/lift_travel(below_us, lift_move_duration)
|
|
|
|
/**
|
|
* Simple wrapper for checking if we can move 1 zlevel, and if we can, do said move.
|
|
* Locks controls, closes all doors, then moves the platform and re-opens the doors afterwards.
|
|
*
|
|
* Arguments:
|
|
* direction - which direction are we moving?
|
|
* lift_move_duration - how long does the move take? can be 0 or null for instant move.
|
|
* door_duration - how long does it take for the doors to open after a move?
|
|
* user - optional, who moved it?
|
|
*/
|
|
/datum/transport_controller/linear/proc/simple_move_wrapper(direction, lift_move_duration, mob/user)
|
|
if(!Check_lift_move(direction))
|
|
return FALSE
|
|
|
|
// Lock controls, to prevent moving-while-moving memes
|
|
controls_lock(TRUE)
|
|
// Send out a signal that we're going
|
|
SEND_SIGNAL(src, COMSIG_LIFT_SET_DIRECTION, direction)
|
|
// Close all lift doors
|
|
update_lift_doors(action = CYCLE_CLOSED)
|
|
|
|
if(isnull(lift_move_duration) || lift_move_duration <= 0 SECONDS)
|
|
// Do an instant move
|
|
move_lift_vertically(direction, user)
|
|
// Open doors on the zs we arrive at
|
|
update_lift_doors(get_zs_we_are_on(), action = CYCLE_OPEN)
|
|
// And unlock the controls after
|
|
controls_lock(FALSE)
|
|
return TRUE
|
|
|
|
// Do a delayed move
|
|
move_after_delay(
|
|
lift_move_duration = lift_move_duration,
|
|
door_duration = lift_move_duration * 1.5,
|
|
direction = direction,
|
|
user = user,
|
|
)
|
|
|
|
addtimer(CALLBACK(src, PROC_REF(finish_simple_move_wrapper)), lift_move_duration * 1.5)
|
|
return TRUE
|
|
|
|
/**
|
|
* Wrap everything up from simple_move_wrapper finishing its movement
|
|
*/
|
|
/datum/transport_controller/linear/proc/finish_simple_move_wrapper()
|
|
SEND_SIGNAL(src, COMSIG_LIFT_SET_DIRECTION, 0)
|
|
controls_lock(FALSE)
|
|
|
|
/**
|
|
* Moves the platform to the passed z-level.
|
|
*
|
|
* Checks for validity of the move: Are we moving to the same z-level, can we actually move to that z-level?
|
|
* Does NOT check if the controls are currently locked.
|
|
*
|
|
* Moves to the passed z-level by calling move_after_delay repeatedly until the passed z-level is reached.
|
|
* This proc sleeps as it moves.
|
|
*
|
|
* Arguments:
|
|
* target_z - required, the Z we want to move to
|
|
* loop_callback - optional, an additional callback invoked during the loop that allows the move to cancel.
|
|
* user - optional, who started the move
|
|
*/
|
|
/datum/transport_controller/linear/proc/move_to_zlevel(target_z, datum/callback/loop_callback, mob/user)
|
|
if(!isnum(target_z) || target_z <= 0)
|
|
CRASH("[type] move_to_zlevel was passed an invalid target_z ([target_z]).")
|
|
|
|
var/obj/structure/transport/linear/prime_lift = return_closest_platform_to_z(target_z)
|
|
var/lift_z = prime_lift.z
|
|
// We're already at the desired z-level!
|
|
if(target_z == lift_z)
|
|
return FALSE
|
|
|
|
// The amount of z levels between the our and target_z
|
|
var/z_difference = abs(target_z - lift_z)
|
|
// Direction (up/down) needed to go to reach target_z
|
|
var/direction = lift_z < target_z ? UP : DOWN
|
|
|
|
// We can't go that way anymore, or possibly ever
|
|
if(!Check_lift_move(direction))
|
|
return FALSE
|
|
|
|
// Okay we're ready to start moving now.
|
|
controls_lock(TRUE)
|
|
// Send out a signal that we're going
|
|
SEND_SIGNAL(src, COMSIG_LIFT_SET_DIRECTION, direction)
|
|
var/travel_speed = prime_lift.elevator_vertical_speed
|
|
|
|
// Close all lift doors
|
|
update_lift_doors(action = CYCLE_CLOSED)
|
|
sleep(1.1 SECONDS)
|
|
// Approach the desired z-level one step at a time
|
|
for(var/i in 1 to z_difference)
|
|
if(!Check_lift_move(direction))
|
|
break
|
|
if(loop_callback && !loop_callback.Invoke())
|
|
break
|
|
// move_after_delay will set up a timer and cause us to move after a time
|
|
move_after_delay(
|
|
lift_move_duration = travel_speed,
|
|
direction = direction,
|
|
user = user,
|
|
)
|
|
// and we don't want to send another request until the timer's done
|
|
stoplag(travel_speed + 0.1 SECONDS)
|
|
if(QDELETED(src) || QDELETED(prime_lift))
|
|
return
|
|
|
|
update_lift_doors(get_zs_we_are_on(), action = CYCLE_OPEN)
|
|
SEND_SIGNAL(src, COMSIG_LIFT_SET_DIRECTION, 0)
|
|
controls_lock(FALSE)
|
|
return TRUE
|
|
|
|
/**
|
|
* Updates all blast doors and shutters that share an ID with our lift.
|
|
*
|
|
* Arguments:
|
|
* on_z_level - optional, only open doors on this z-level or list of z-levels
|
|
* action - how do we update the doors? CYCLE_OPEN to make them open, CYCLE_CLOSED to make them shut
|
|
*/
|
|
/datum/transport_controller/linear/proc/update_lift_doors(on_z_level, action)
|
|
|
|
if(!isnull(on_z_level) && !islist(on_z_level))
|
|
on_z_level = list(on_z_level)
|
|
|
|
var/played_ding = FALSE
|
|
for(var/obj/machinery/door/elevator_door as anything in GLOB.elevator_doors)
|
|
if(elevator_door.transport_linked_id != specific_transport_id)
|
|
continue
|
|
if(on_z_level && !(elevator_door.z in on_z_level))
|
|
continue
|
|
switch(action)
|
|
if(CYCLE_OPEN)
|
|
elevator_door.elevator_status = LIFT_PLATFORM_UNLOCKED
|
|
if(!played_ding)
|
|
playsound(elevator_door, 'sound/machines/ping.ogg', 50, TRUE)
|
|
played_ding = TRUE
|
|
addtimer(CALLBACK(elevator_door, TYPE_PROC_REF(/obj/machinery/door, open)), 0.7 SECONDS)
|
|
if(CYCLE_CLOSED)
|
|
elevator_door.elevator_status = LIFT_PLATFORM_LOCKED
|
|
INVOKE_ASYNC(elevator_door, TYPE_PROC_REF(/obj/machinery/door, close))
|
|
else
|
|
stack_trace("Elevator lift update_lift_doors called with an improper action ([action]).")
|
|
|
|
/// Helper used in callbacks to open all the doors our platform is on
|
|
/datum/transport_controller/linear/proc/open_lift_doors_callback()
|
|
update_lift_doors(get_zs_we_are_on(), action = CYCLE_OPEN)
|
|
|
|
/**
|
|
* Moves the platform, this is what users invoke with their hand.
|
|
* This is a SAFE proc, ensuring every part of the lift moves SANELY.
|
|
* It also locks controls for the (miniscule) duration of the movement, so the elevator cannot be broken by spamming.
|
|
*/
|
|
/datum/transport_controller/linear/proc/move_transport_horizontally(going)
|
|
if(modular_set)
|
|
controls_lock(TRUE)
|
|
for(var/obj/structure/transport/linear/module_to_move as anything in transport_modules)
|
|
module_to_move.travel(going)
|
|
|
|
controls_lock(FALSE)
|
|
return
|
|
|
|
var/max_x = 0
|
|
var/max_y = 0
|
|
var/max_z = 0
|
|
var/min_x = world.maxx
|
|
var/min_y = world.maxy
|
|
var/min_z = world.maxz
|
|
|
|
for(var/obj/structure/transport/linear/transport_module as anything in transport_modules)
|
|
max_z = max(max_z, transport_module.z)
|
|
min_z = min(min_z, transport_module.z)
|
|
|
|
min_x = min(min_x, transport_module.x)
|
|
max_x = max(max_x, transport_module.x)
|
|
//this assumes that all z levels have identical horizontal bounding boxes
|
|
//but if youre still using a non multitile platform at this point
|
|
//then its your own problem. it wont runtime it will just be slower than it needs to be if this assumption isnt
|
|
//the case
|
|
|
|
min_y = min(min_y, transport_module.y)
|
|
max_y = max(max_y, transport_module.y)
|
|
|
|
for(var/z in min_z to max_z)
|
|
//This must be safe way to border tile to tile move of bordered platforms, that excludes platform overlapping.
|
|
if(going & WEST)
|
|
//Go along the X axis from min to max, from left to right
|
|
for(var/x in min_x to max_x)
|
|
if(going & NORTH)
|
|
//Go along the Y axis from max to min, from up to down
|
|
for(var/y in max_y to min_y step -1)
|
|
var/obj/structure/transport/linear/transport_module = locate(/obj/structure/transport/linear, locate(x, y, z))
|
|
transport_module?.travel(going)
|
|
|
|
else if(going & SOUTH)
|
|
//Go along the Y axis from min to max, from down to up
|
|
for(var/y in min_y to max_y)
|
|
var/obj/structure/transport/linear/transport_module = locate(/obj/structure/transport/linear, locate(x, y, z))
|
|
transport_module?.travel(going)
|
|
|
|
else
|
|
for(var/y in min_y to max_y)
|
|
var/obj/structure/transport/linear/transport_module = locate(/obj/structure/transport/linear, locate(x, y, z))
|
|
transport_module?.travel(going)
|
|
else
|
|
//Go along the X axis from max to min, from right to left
|
|
for(var/x in max_x to min_x step -1)
|
|
if(going & NORTH)
|
|
//Go along the Y axis from max to min, from up to down
|
|
for(var/y in max_y to min_y step -1)
|
|
var/obj/structure/transport/linear/transport_module = locate(/obj/structure/transport/linear, locate(x, y, z))
|
|
transport_module?.travel(going)
|
|
|
|
else if (going & SOUTH)
|
|
for(var/y in min_y to max_y)
|
|
var/obj/structure/transport/linear/transport_module = locate(/obj/structure/transport/linear, locate(x, y, z))
|
|
transport_module?.travel(going)
|
|
|
|
else
|
|
//Go along the Y axis from min to max, from down to up
|
|
for(var/y in min_y to max_y)
|
|
var/obj/structure/transport/linear/transport_module = locate(/obj/structure/transport/linear, locate(x, y, z))
|
|
transport_module?.travel(going)
|
|
|
|
///Check destination turfs
|
|
/datum/transport_controller/linear/proc/Check_lift_move(check_dir)
|
|
for(var/obj/structure/transport/linear/transport_module as anything in transport_modules)
|
|
for(var/turf/bound_turf in transport_module.locs)
|
|
var/turf/T = get_step_multiz(transport_module, check_dir)
|
|
if(!T)//the edges of multi-z maps
|
|
return FALSE
|
|
if(check_dir == UP && !istype(T, /turf/open/openspace)) // We don't want to go through the ceiling!
|
|
return FALSE
|
|
if(check_dir == DOWN && !istype(get_turf(transport_module), /turf/open/openspace)) // No going through the floor!
|
|
return FALSE
|
|
return TRUE
|
|
|
|
/**
|
|
* Sets transport controls_locked state. Used to prevent moving mid movement, or cooldowns.
|
|
*/
|
|
/datum/transport_controller/linear/proc/controls_lock(state)
|
|
switch(state)
|
|
if(FALSE)
|
|
controller_status &= ~CONTROLS_LOCKED
|
|
else
|
|
controller_status |= CONTROLS_LOCKED
|
|
|
|
/**
|
|
* resets the contents of all platforms to their original state in case someone put a bunch of shit onto the platform.
|
|
* intended to be called by admins. passes all arguments to reset_contents() for each of our platforms.
|
|
*
|
|
* Arguments:
|
|
* * consider_anything_past - number. if > 0 our platforms will only handle foreign contents that exceed this number in each of their locs
|
|
* * foreign_objects - bool. if true our platforms will consider /atom/movable's that arent mobs as part of foreign contents
|
|
* * foreign_non_player_mobs - bool. if true our platforms consider mobs that dont have a mind to be foreign
|
|
* * consider_player_mobs - bool. if true our platforms consider player mobs to be foreign. only works if foreign_non_player_mobs is true as well
|
|
*/
|
|
/datum/transport_controller/linear/proc/reset_lift_contents(consider_anything_past = 0, foreign_objects = TRUE, foreign_non_player_mobs = TRUE, consider_player_mobs = FALSE)
|
|
for(var/obj/structure/transport/linear/lift_to_reset in transport_modules)
|
|
lift_to_reset.reset_contents(consider_anything_past, foreign_objects, foreign_non_player_mobs, consider_player_mobs)
|
|
|
|
return TRUE
|
|
|
|
#undef HYDRAULIC_SFX_DURATION
|