mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-23 03:57:13 +01:00
Refactors transit tubes (#22452)
* Rework transit tube pods to not use timers * please work * yes * henri review * Fix mapping mishaps * fix icon mishaps * re-adds missing intercomm
This commit is contained in:
@@ -8,8 +8,10 @@
|
||||
// one.
|
||||
/obj/structure/transit_tube/station
|
||||
name = "station tube station"
|
||||
desc = "The lynchpin of the transit system."
|
||||
icon = 'icons/obj/pipes/transit_tube_station.dmi'
|
||||
icon_state = "closed"
|
||||
icon_state = "closed_station0"
|
||||
base_icon_state = "station0"
|
||||
exit_delay = 1
|
||||
enter_delay = 2
|
||||
var/pod_moving = FALSE
|
||||
@@ -18,6 +20,8 @@
|
||||
var/hatch_state = TRANSIT_TUBE_CLOSED
|
||||
|
||||
var/list/disallowed_mobs = list(/mob/living/silicon/ai)
|
||||
/// Direction by which you can board the tube
|
||||
var/boarding_dir
|
||||
|
||||
/obj/structure/transit_tube/station/Initialize(mapload)
|
||||
. = ..()
|
||||
@@ -27,24 +31,32 @@
|
||||
STOP_PROCESSING(SSobj, src)
|
||||
return ..()
|
||||
|
||||
// Stations which will send the tube in the opposite direction after their stop.
|
||||
/obj/structure/transit_tube/station/reverse
|
||||
reverse_launch = TRUE
|
||||
/obj/structure/transit_tube/station/init_tube_dirs()
|
||||
// Tube station directions are simply 90 to either side of
|
||||
// the exit.
|
||||
switch(dir)
|
||||
if(NORTH)
|
||||
tube_dirs = list(EAST, WEST)
|
||||
if(SOUTH)
|
||||
tube_dirs = list(EAST, WEST)
|
||||
if(EAST)
|
||||
tube_dirs = list(NORTH, SOUTH)
|
||||
if(WEST)
|
||||
tube_dirs = list(NORTH, SOUTH)
|
||||
boarding_dir = reverse_direction(dir)
|
||||
|
||||
/obj/structure/transit_tube/station/should_stop_pod(pod, from_dir)
|
||||
return TRUE
|
||||
|
||||
/obj/structure/transit_tube/station/Bumped(mob/living/L)
|
||||
if(!pod_moving && hatch_state == TRANSIT_TUBE_OPEN && isliving(L) && !is_type_in_list(L, disallowed_mobs))
|
||||
var/failed = FALSE
|
||||
if(!pod_moving && L.dir == boarding_dir && hatch_state == TRANSIT_TUBE_OPEN && isliving(L) && !is_type_in_list(L, disallowed_mobs))
|
||||
for(var/obj/structure/transit_tube_pod/pod in loc)
|
||||
if(pod.contents.len)
|
||||
failed = TRUE
|
||||
else if(!pod.moving && (pod.dir in directions()))
|
||||
if(length(pod.contents))
|
||||
to_chat(L, "<span class='warning'>The pod is already occupied.</span>")
|
||||
return
|
||||
if(!pod.moving && ((pod.dir in directions()) || (reverse_launch && (turn(pod.dir, 180) in directions()))))
|
||||
pod.move_into(L)
|
||||
return
|
||||
if(failed)
|
||||
to_chat(L, "<span class='warning'>The pod is already occupied.</span>")
|
||||
|
||||
|
||||
|
||||
@@ -88,31 +100,36 @@
|
||||
|
||||
/obj/structure/transit_tube/station/proc/open_hatch()
|
||||
if(hatch_state == TRANSIT_TUBE_CLOSED)
|
||||
icon_state = "opening"
|
||||
icon_state = "opening_[base_icon_state]"
|
||||
hatch_state = TRANSIT_TUBE_OPENING
|
||||
addtimer(CALLBACK(src, PROC_REF(open_hatch_callback)), OPEN_DURATION)
|
||||
|
||||
/obj/structure/transit_tube/station/proc/open_hatch_callback()
|
||||
if(hatch_state == TRANSIT_TUBE_OPENING)
|
||||
icon_state = "open"
|
||||
hatch_state = TRANSIT_TUBE_OPEN
|
||||
|
||||
|
||||
addtimer(CALLBACK(src, PROC_REF(finish_animation)), OPEN_DURATION)
|
||||
|
||||
/obj/structure/transit_tube/station/proc/close_hatch()
|
||||
if(hatch_state == TRANSIT_TUBE_OPEN)
|
||||
icon_state = "closing"
|
||||
icon_state = "closing_[base_icon_state]"
|
||||
hatch_state = TRANSIT_TUBE_CLOSING
|
||||
addtimer(CALLBACK(src, PROC_REF(close_hatch_calllback)), CLOSE_DURATION)
|
||||
addtimer(CALLBACK(src, PROC_REF(finish_animation)), CLOSE_DURATION)
|
||||
|
||||
/obj/structure/transit_tube/station/proc/close_hatch_calllback()
|
||||
if(hatch_state == TRANSIT_TUBE_CLOSING)
|
||||
icon_state = "closed"
|
||||
hatch_state = TRANSIT_TUBE_CLOSED
|
||||
/obj/structure/transit_tube/station/proc/finish_animation()
|
||||
switch(hatch_state)
|
||||
if(TRANSIT_TUBE_OPENING)
|
||||
icon_state = "open_[base_icon_state]"
|
||||
hatch_state = TRANSIT_TUBE_OPEN
|
||||
for(var/obj/structure/transit_tube_pod/pod in loc)
|
||||
for(var/thing in pod)
|
||||
if(ismob(thing))
|
||||
var/mob/mob_content = thing
|
||||
if(mob_content.client && mob_content.stat < UNCONSCIOUS)
|
||||
continue // Let the mobs with clients decide what they want to do themselves.
|
||||
var/atom/movable/movable_content = thing
|
||||
movable_content.forceMove(loc) //Everything else is moved out of.
|
||||
if(TRANSIT_TUBE_CLOSING)
|
||||
icon_state = "closed_[base_icon_state]"
|
||||
hatch_state = TRANSIT_TUBE_CLOSED
|
||||
|
||||
/obj/structure/transit_tube/station/proc/launch_pod()
|
||||
for(var/obj/structure/transit_tube_pod/pod in loc)
|
||||
if(!pod.moving && (pod.dir in directions()))
|
||||
if(!pod.moving && ((pod.dir in directions()) || (reverse_launch && (turn(pod.dir, 180) in directions()))))
|
||||
addtimer(CALLBACK(src, PROC_REF(launch_pod_callback), pod), 5)
|
||||
return
|
||||
|
||||
@@ -131,7 +148,7 @@
|
||||
if(!nexttube)
|
||||
pod.dir = turn(pod.dir, 180)
|
||||
|
||||
if(hatch_state == TRANSIT_TUBE_CLOSED && pod)
|
||||
if(hatch_state == TRANSIT_TUBE_CLOSED && pod && pod.loc == loc)
|
||||
pod.follow_tube()
|
||||
|
||||
pod_moving = FALSE
|
||||
@@ -142,6 +159,7 @@
|
||||
|
||||
/obj/structure/transit_tube/station/pod_stopped(obj/structure/transit_tube_pod/pod, from_dir)
|
||||
pod_moving = TRUE
|
||||
pod.stop_following()
|
||||
addtimer(CALLBACK(src, PROC_REF(pod_stopped_callback), pod), 5)
|
||||
|
||||
/obj/structure/transit_tube/station/proc/pod_stopped_callback(obj/structure/transit_tube_pod/pod)
|
||||
@@ -152,10 +170,103 @@
|
||||
pod_moving = FALSE
|
||||
pod.mix_air()
|
||||
|
||||
// Tube station directions are simply 90 to either side of
|
||||
// the exit.
|
||||
/obj/structure/transit_tube/station/init_dirs()
|
||||
tube_dirs = list(turn(dir, 90), turn(dir, -90))
|
||||
/obj/structure/transit_tube/station/flipped
|
||||
icon_state = "closed_station1"
|
||||
base_icon_state = "station1"
|
||||
|
||||
/obj/structure/transit_tube/station/flipped/init_tube_dirs()
|
||||
..()
|
||||
boarding_dir = dir
|
||||
|
||||
// Stations which will send the tube in the opposite direction after their stop.
|
||||
/obj/structure/transit_tube/station/reverse
|
||||
icon_state = "closed_terminus0"
|
||||
base_icon_state = "terminus0"
|
||||
reverse_launch = TRUE
|
||||
|
||||
/obj/structure/transit_tube/station/reverse/init_tube_dirs()
|
||||
tube_dirs = list(turn(dir, -90))
|
||||
boarding_dir = reverse_direction(dir)
|
||||
|
||||
/obj/structure/transit_tube/station/reverse/flipped
|
||||
icon_state = "closed_terminus1"
|
||||
base_icon_state = "terminus1"
|
||||
|
||||
/obj/structure/transit_tube/station/reverse/flipped/init_tube_dirs()
|
||||
..()
|
||||
boarding_dir = dir
|
||||
|
||||
//special dispenser station, it creates a pod for you to enter when you bump into it.
|
||||
|
||||
/obj/structure/transit_tube/station/dispenser
|
||||
name = "station tube pod dispenser"
|
||||
icon_state = "open_dispenser0"
|
||||
desc = "The lynchpin of a GOOD transit system."
|
||||
enter_delay = 1
|
||||
base_icon_state = "dispenser0"
|
||||
hatch_state = TRANSIT_TUBE_OPEN
|
||||
|
||||
/obj/structure/transit_tube/station/dispenser/examine(mob/user)
|
||||
. = ..()
|
||||
. += "<span class='notice'>This station will create a pod for you to ride, no need to wait for one.</span>"
|
||||
. += "<span class='notice'>Any pods arriving at this station will be reclaimed.</span>"
|
||||
|
||||
/obj/structure/transit_tube/station/dispenser/close_hatch()
|
||||
. = ..()
|
||||
return
|
||||
|
||||
/obj/structure/transit_tube/station/dispenser/launch_pod()
|
||||
for(var/obj/structure/transit_tube_pod/pod in loc)
|
||||
if(!pod.moving)
|
||||
pod_moving = TRUE
|
||||
pod.follow_tube()
|
||||
pod_moving = FALSE
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/structure/transit_tube/station/dispenser/Bumped(atom/movable/AM)
|
||||
if(!(istype(AM) && AM.dir == boarding_dir) || AM.anchored)
|
||||
return
|
||||
var/obj/structure/transit_tube_pod/dispensed/pod = new(loc)
|
||||
AM.visible_message("<span class='notice'>[pod] forms around [AM].</span>", "<span class='notice'>[pod] materializes around you.</span>")
|
||||
playsound(src, 'sound/weapons/emitter2.ogg', 50, TRUE)
|
||||
pod.dir = turn(dir, -90)
|
||||
pod.move_into(AM)
|
||||
launch_pod()
|
||||
|
||||
/obj/structure/transit_tube/station/dispenser/pod_stopped(obj/structure/transit_tube_pod/pod)
|
||||
playsound(src, 'sound/machines/ding.ogg', 50, TRUE)
|
||||
qdel(pod)
|
||||
|
||||
|
||||
|
||||
/obj/structure/transit_tube/station/dispenser/flipped
|
||||
icon_state = "open_dispenser1"
|
||||
base_icon_state = "dispenser1"
|
||||
|
||||
/obj/structure/transit_tube/station/dispenser/flipped/init_tube_dirs()
|
||||
..()
|
||||
boarding_dir = dir
|
||||
|
||||
|
||||
/obj/structure/transit_tube/station/dispenser/reverse
|
||||
reverse_launch = TRUE
|
||||
icon_state = "open_terminusdispenser0"
|
||||
base_icon_state = "terminusdispenser0"
|
||||
|
||||
/obj/structure/transit_tube/station/dispenser/reverse/init_tube_dirs()
|
||||
tube_dirs = list(turn(dir, 90))
|
||||
boarding_dir = reverse_direction(dir)
|
||||
|
||||
/obj/structure/transit_tube/station/dispenser/reverse/flipped
|
||||
icon_state = "open_terminusdispenser1"
|
||||
base_icon_state = "terminusdispenser1"
|
||||
|
||||
/obj/structure/transit_tube/station/dispenser/reverse/flipped/init_tube_dirs()
|
||||
..()
|
||||
boarding_dir = dir
|
||||
|
||||
|
||||
|
||||
#undef CLOSE_DURATION
|
||||
#undef OPEN_DURATION
|
||||
|
||||
@@ -4,8 +4,10 @@
|
||||
// Mappers: you can use "Generate Instances from Icon-states"
|
||||
// to get the different pieces.
|
||||
/obj/structure/transit_tube
|
||||
name = "transit tube"
|
||||
desc = "A pneumatic tube that brings you from here to there."
|
||||
icon = 'icons/obj/pipes/transit_tube.dmi'
|
||||
icon_state = "E-W"
|
||||
icon_state = "straight"
|
||||
density = TRUE
|
||||
layer = 3.1
|
||||
anchored = TRUE
|
||||
@@ -13,29 +15,39 @@
|
||||
var/exit_delay = 1
|
||||
var/enter_delay = 0
|
||||
|
||||
// alldirs in global.dm is the same list of directions, but since
|
||||
// the specific order matters to get a usable icon_state, it is
|
||||
// copied here so that, in the unlikely case that alldirs is changed,
|
||||
// this continues to work.
|
||||
var/global/list/tube_dir_list = list(NORTH, SOUTH, EAST, WEST, NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST)
|
||||
/obj/structure/transit_tube/Initialize(mapload, new_direction)
|
||||
. = ..()
|
||||
if(new_direction)
|
||||
setDir(new_direction)
|
||||
// set up our appearance after the initialize in case someone's setting our direction afterwards
|
||||
// (especially for things like admin spawning)
|
||||
addtimer(CALLBACK(src, PROC_REF(setup_appearance)), 1)
|
||||
|
||||
/obj/structure/transit_tube/proc/setup_appearance()
|
||||
init_tube_dirs()
|
||||
update_appearance()
|
||||
|
||||
/obj/structure/transit_tube/Destroy()
|
||||
for(var/obj/structure/transit_tube_pod/P in loc)
|
||||
P.empty_pod()
|
||||
return ..()
|
||||
|
||||
/obj/structure/transit_tube/CanPass(atom/movable/mover, turf/target)
|
||||
if(istype(mover) && mover.checkpass(PASSGLASS))
|
||||
return 1
|
||||
return TRUE
|
||||
return !density
|
||||
|
||||
// When destroyed by explosions, properly handle contents.
|
||||
/obj/structure/transit_tube/ex_act(severity)
|
||||
switch(severity)
|
||||
if(1.0)
|
||||
if(EXPLODE_DEVASTATE)
|
||||
for(var/atom/movable/AM in contents)
|
||||
AM.loc = loc
|
||||
AM.ex_act(severity++)
|
||||
|
||||
qdel(src)
|
||||
return
|
||||
if(2.0)
|
||||
if(EXPLODE_HEAVY)
|
||||
if(prob(50))
|
||||
for(var/atom/movable/AM in contents)
|
||||
AM.loc = loc
|
||||
@@ -43,20 +55,12 @@
|
||||
|
||||
qdel(src)
|
||||
return
|
||||
if(3.0)
|
||||
if(EXPLODE_LIGHT)
|
||||
return
|
||||
|
||||
|
||||
/obj/structure/transit_tube/New(loc)
|
||||
..(loc)
|
||||
|
||||
if(tube_dirs == null)
|
||||
init_dirs()
|
||||
|
||||
|
||||
// Called to check if a pod should stop upon entering this tube.
|
||||
/obj/structure/transit_tube/proc/should_stop_pod(pod, from_dir)
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
// Called when a pod stops in this tube section.
|
||||
/obj/structure/transit_tube/proc/pod_stopped(pod, from_dir)
|
||||
@@ -76,18 +80,18 @@
|
||||
|
||||
for(var/direction in directions())
|
||||
if(direction == from_dir)
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
|
||||
|
||||
/obj/structure/transit_tube/proc/has_exit(in_dir)
|
||||
for(var/direction in directions())
|
||||
if(direction == in_dir)
|
||||
return 1
|
||||
return TRUE
|
||||
|
||||
return 0
|
||||
return FALSE
|
||||
|
||||
|
||||
|
||||
@@ -122,191 +126,157 @@
|
||||
/obj/structure/transit_tube/proc/enter_delay(pod, to_dir)
|
||||
return enter_delay
|
||||
|
||||
/obj/structure/transit_tube/proc/init_tube_dirs()
|
||||
switch(dir)
|
||||
if(NORTH, SOUTH)
|
||||
tube_dirs = list(NORTH, SOUTH)
|
||||
if(EAST, WEST)
|
||||
tube_dirs = list(EAST, WEST)
|
||||
|
||||
// Parse the icon_state into a list of directions.
|
||||
// This means that mappers can use Dream Maker's built in
|
||||
// "Generate Instances from Icon-states" option to get all
|
||||
// variations. Additionally, as a separate proc, sub-types
|
||||
// can handle it more intelligently.
|
||||
/obj/structure/transit_tube/proc/init_dirs()
|
||||
if(icon_state == "auto")
|
||||
// Additional delay, for map loading.
|
||||
spawn(1)
|
||||
init_dirs_automatic()
|
||||
/obj/structure/transit_tube/update_overlays()
|
||||
. = ..()
|
||||
for(var/direction in directions())
|
||||
if(!IS_DIR_DIAGONAL(direction))
|
||||
. += create_tube_overlay(direction)
|
||||
continue
|
||||
if(!(direction & NORTH))
|
||||
continue
|
||||
|
||||
. += create_tube_overlay(direction ^ (NORTH|SOUTH), NORTH)
|
||||
if(direction & EAST)
|
||||
. += create_tube_overlay(direction ^ (EAST|WEST), EAST)
|
||||
else
|
||||
. += create_tube_overlay(direction ^ (EAST|WEST), WEST)
|
||||
|
||||
|
||||
/obj/structure/transit_tube/proc/create_tube_overlay(direction, shift_dir)
|
||||
// We use image() because a mutable appearance will have its dir mirror the parent which sort of fucks up what we're doing here
|
||||
var/image/tube_overlay = image(icon, dir = direction)
|
||||
if(shift_dir)
|
||||
tube_overlay.icon_state = "decorative_diag"
|
||||
switch(shift_dir)
|
||||
if(NORTH)
|
||||
tube_overlay.pixel_y = 32
|
||||
if(SOUTH)
|
||||
tube_overlay.pixel_y = -32
|
||||
if(EAST)
|
||||
tube_overlay.pixel_x = 32
|
||||
if(WEST)
|
||||
tube_overlay.pixel_x = -32
|
||||
else
|
||||
tube_dirs = parse_dirs(icon_state)
|
||||
tube_overlay.icon_state = "decorative"
|
||||
|
||||
if(copytext(icon_state, 1, 3) == "D-" || findtextEx(icon_state, "Pass"))
|
||||
density = FALSE
|
||||
tube_overlay.overlays += emissive_blocker(icon, tube_overlay.icon_state, src)
|
||||
return tube_overlay
|
||||
|
||||
//Some of these are mostly for mapping use
|
||||
/obj/structure/transit_tube/horizontal
|
||||
dir = WEST
|
||||
|
||||
|
||||
/obj/structure/transit_tube/diagonal
|
||||
icon_state = "diagonal"
|
||||
|
||||
/obj/structure/transit_tube/diagonal/init_tube_dirs()
|
||||
switch(dir)
|
||||
if(NORTH)
|
||||
tube_dirs = list(NORTHEAST, SOUTHWEST)
|
||||
if(SOUTH)
|
||||
tube_dirs = list(NORTHEAST, SOUTHWEST)
|
||||
if(EAST)
|
||||
tube_dirs = list(NORTHWEST, SOUTHEAST)
|
||||
if(WEST)
|
||||
tube_dirs = list(NORTHWEST, SOUTHEAST)
|
||||
|
||||
//mostly for mapping use
|
||||
/obj/structure/transit_tube/diagonal/topleft
|
||||
dir = WEST
|
||||
|
||||
/obj/structure/transit_tube/diagonal/crossing
|
||||
density = FALSE
|
||||
icon_state = "diagonal_crossing"
|
||||
|
||||
//mostly for mapping use
|
||||
/obj/structure/transit_tube/diagonal/crossing/topleft
|
||||
dir = WEST
|
||||
|
||||
|
||||
// Initialize dirs by searching for tubes that do/might connect
|
||||
// on nearby turfs. Create corner pieces if nessecary.
|
||||
// Pick two directions, preferring tubes that already connect
|
||||
// to loc, or other auto tubes if there aren't enough connections.
|
||||
/obj/structure/transit_tube/proc/init_dirs_automatic()
|
||||
var/list/connected = list()
|
||||
var/list/connected_auto = list()
|
||||
/obj/structure/transit_tube/curved
|
||||
icon_state = "curved0"
|
||||
|
||||
for(var/direction in tube_dir_list)
|
||||
var/location = get_step(loc, direction)
|
||||
for(var/obj/structure/transit_tube/tube in location)
|
||||
if(tube.directions() == null && tube.icon_state == "auto")
|
||||
connected_auto += direction
|
||||
break
|
||||
/obj/structure/transit_tube/curved/init_tube_dirs()
|
||||
switch(dir)
|
||||
if(NORTH)
|
||||
tube_dirs = list(NORTH, SOUTHWEST)
|
||||
if(SOUTH)
|
||||
tube_dirs = list(SOUTH, NORTHEAST)
|
||||
if(EAST)
|
||||
tube_dirs = list(EAST, NORTHWEST)
|
||||
if(WEST)
|
||||
tube_dirs = list(SOUTHEAST, WEST)
|
||||
|
||||
else if(turn(direction, 180) in tube.directions())
|
||||
connected += direction
|
||||
break
|
||||
/obj/structure/transit_tube/curved/flipped
|
||||
icon_state = "curved1"
|
||||
|
||||
connected += connected_auto
|
||||
|
||||
tube_dirs = select_automatic_dirs(connected)
|
||||
|
||||
if(length(tube_dirs) == 2 && tube_dir_list.Find(tube_dirs[1]) > tube_dir_list.Find(tube_dirs[2]))
|
||||
tube_dirs.Swap(1, 2)
|
||||
|
||||
generate_automatic_corners(tube_dirs)
|
||||
select_automatic_icon_state(tube_dirs)
|
||||
/obj/structure/transit_tube/curved/flipped/init_tube_dirs()
|
||||
switch(dir)
|
||||
if(NORTH)
|
||||
tube_dirs = list(NORTH, SOUTHEAST)
|
||||
if(SOUTH)
|
||||
tube_dirs = list(SOUTH, NORTHWEST)
|
||||
if(EAST)
|
||||
tube_dirs = list(EAST, SOUTHWEST)
|
||||
if(WEST)
|
||||
tube_dirs = list(NORTHEAST, WEST)
|
||||
|
||||
|
||||
/obj/structure/transit_tube/junction
|
||||
icon_state = "junction0"
|
||||
|
||||
// Given a list of directions, look a pair that forms a 180 or
|
||||
// 135 degree angle, and return a list containing the pair.
|
||||
// If none exist, return list(connected[1], turn(connected[1], 180)
|
||||
/obj/structure/transit_tube/proc/select_automatic_dirs(connected)
|
||||
if(length(connected) < 1)
|
||||
return list()
|
||||
/obj/structure/transit_tube/junction/init_tube_dirs()
|
||||
switch(dir)
|
||||
if(NORTH)
|
||||
tube_dirs = list(NORTH, SOUTHEAST, SOUTHWEST)//ending with the prefered direction
|
||||
if(SOUTH)
|
||||
tube_dirs = list(SOUTH, NORTHWEST, NORTHEAST)
|
||||
if(EAST)
|
||||
tube_dirs = list(EAST, SOUTHWEST, NORTHWEST)
|
||||
if(WEST)
|
||||
tube_dirs = list(WEST, NORTHEAST, SOUTHEAST)
|
||||
|
||||
for(var/i = 1, i <= length(connected), i++)
|
||||
for(var/j = i + 1, j <= length(connected), j++)
|
||||
var/d1 = connected[i]
|
||||
var/d2 = connected[j]
|
||||
/obj/structure/transit_tube/junction/flipped
|
||||
icon_state = "junction1"
|
||||
|
||||
if(d1 == turn(d2, 135) || d1 == turn(d2, 180) || d1 == turn(d2, 225))
|
||||
return list(d1, d2)
|
||||
|
||||
return list(connected[1], turn(connected[1], 180))
|
||||
/obj/structure/transit_tube/junction/flipped/init_tube_dirs()
|
||||
switch(dir)
|
||||
if(NORTH)
|
||||
tube_dirs = list(NORTH, SOUTHWEST, SOUTHEAST)//ending with the prefered direction
|
||||
if(SOUTH)
|
||||
tube_dirs = list(SOUTH, NORTHEAST, NORTHWEST)
|
||||
if(EAST)
|
||||
tube_dirs = list(EAST, NORTHWEST, SOUTHWEST)
|
||||
if(WEST)
|
||||
tube_dirs = list(WEST, SOUTHEAST, NORTHEAST)
|
||||
|
||||
|
||||
/obj/structure/transit_tube/crossing
|
||||
icon_state = "crossing"
|
||||
density = FALSE
|
||||
|
||||
/obj/structure/transit_tube/proc/select_automatic_icon_state(directions)
|
||||
if(length(directions) == 2)
|
||||
icon_state = "[dir2text_short(directions[1])]-[dir2text_short(directions[2])]"
|
||||
//mostly for mapping use
|
||||
/obj/structure/transit_tube/crossing/horizontal
|
||||
dir = WEST
|
||||
|
||||
// cosmetic "cap" for tubes. Note that tubes can't enter this.
|
||||
/obj/structure/transit_tube/cap
|
||||
icon_state = "cap"
|
||||
|
||||
/obj/structure/transit_tube/cap/init_tube_dirs()
|
||||
tube_dirs = list(turn(dir, 180)) // back the way we came
|
||||
|
||||
// Look for diagonal directions, generate the decorative corners in each.
|
||||
/obj/structure/transit_tube/proc/generate_automatic_corners(directions)
|
||||
for(var/direction in directions)
|
||||
if(direction == 5 || direction == 6 || direction == 9 || direction == 10)
|
||||
if(direction & NORTH)
|
||||
create_automatic_decorative_corner(get_step(loc, NORTH), direction ^ 3)
|
||||
|
||||
else
|
||||
create_automatic_decorative_corner(get_step(loc, SOUTH), direction ^ 3)
|
||||
|
||||
if(direction & EAST)
|
||||
create_automatic_decorative_corner(get_step(loc, EAST), direction ^ 12)
|
||||
|
||||
else
|
||||
create_automatic_decorative_corner(get_step(loc, WEST), direction ^ 12)
|
||||
|
||||
|
||||
|
||||
// Generate a corner, if one doesn't exist for the direction on the turf.
|
||||
/obj/structure/transit_tube/proc/create_automatic_decorative_corner(location, direction)
|
||||
var/state = "D-[dir2text_short(direction)]"
|
||||
|
||||
for(var/obj/structure/transit_tube/tube in location)
|
||||
if(tube.icon_state == state)
|
||||
return
|
||||
|
||||
var/obj/structure/transit_tube/tube = new(location)
|
||||
tube.icon_state = state
|
||||
tube.init_dirs()
|
||||
|
||||
|
||||
|
||||
// Uses a list() to cache return values. Since they should
|
||||
// never be edited directly, all tubes with a certain
|
||||
// icon_state can just reference the same list. In theory,
|
||||
// reduces memory usage, and improves CPU cache usage.
|
||||
// In reality, I don't know if that is quite how BYOND works,
|
||||
// but it is probably safer to assume the existence of, and
|
||||
// rely on, a sufficiently smart compiler/optimizer.
|
||||
/obj/structure/transit_tube/proc/parse_dirs(text)
|
||||
var/global/list/direction_table = list()
|
||||
|
||||
if(text in direction_table)
|
||||
return direction_table[text]
|
||||
|
||||
var/list/split_text = splittext(text, "-")
|
||||
|
||||
// If the first token is D, the icon_state represents
|
||||
// a purely decorative tube, and doesn't actually
|
||||
// connect to anything.
|
||||
if(split_text[1] == "D")
|
||||
direction_table[text] = list()
|
||||
return null
|
||||
|
||||
var/list/directions = list()
|
||||
|
||||
for(var/text_part in split_text)
|
||||
var/direction = text2dir_extended(text_part)
|
||||
|
||||
if(direction > 0)
|
||||
directions += direction
|
||||
|
||||
direction_table[text] = directions
|
||||
return directions
|
||||
|
||||
|
||||
|
||||
// A copy of text2dir, extended to accept one and two letter
|
||||
// directions, and to clearly return 0 otherwise.
|
||||
/obj/structure/transit_tube/proc/text2dir_extended(direction)
|
||||
switch(uppertext(direction))
|
||||
if("NORTH", "N")
|
||||
return 1
|
||||
if("SOUTH", "S")
|
||||
return 2
|
||||
if("EAST", "E")
|
||||
return 4
|
||||
if("WEST", "W")
|
||||
return 8
|
||||
if("NORTHEAST", "NE")
|
||||
return 5
|
||||
if("NORTHWEST", "NW")
|
||||
return 9
|
||||
if("SOUTHEAST", "SE")
|
||||
return 6
|
||||
if("SOUTHWEST", "SW")
|
||||
return 10
|
||||
|
||||
|
||||
|
||||
// A copy of dir2text, which returns the short one or two letter
|
||||
// directions used in tube icon states.
|
||||
/obj/structure/transit_tube/proc/dir2text_short(direction)
|
||||
switch(direction)
|
||||
if(1)
|
||||
return "N"
|
||||
if(2)
|
||||
return "S"
|
||||
if(4)
|
||||
return "E"
|
||||
if(8)
|
||||
return "W"
|
||||
if(5)
|
||||
return "NE"
|
||||
if(6)
|
||||
return "SE"
|
||||
if(9)
|
||||
return "NW"
|
||||
if(10)
|
||||
return "SW"
|
||||
/obj/structure/transit_tube/cap/has_entrance(from_dir)
|
||||
return FALSE
|
||||
|
||||
/obj/structure/transit_tube/cap/create_tube_overlay()
|
||||
// cap sprites already have overlays
|
||||
return
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#define MOVE_ANIMATION_STAGE_ONE 1
|
||||
#define MOVE_ANIMATION_STAGE_TWO 2
|
||||
|
||||
/obj/structure/transit_tube_pod
|
||||
icon = 'icons/obj/pipes/transit_tube_pod.dmi'
|
||||
icon_state = "pod"
|
||||
@@ -6,9 +9,25 @@
|
||||
density = TRUE
|
||||
var/moving = FALSE
|
||||
var/datum/gas_mixture/air_contents = new()
|
||||
/// The tube we're currently traveling through
|
||||
var/obj/structure/transit_tube/current_tube = null
|
||||
/// The direction of our next transit from pipe to pipe. Stored between process calls here.
|
||||
var/next_dir
|
||||
/// The location of our next target tube. Stored same as above
|
||||
var/next_loc
|
||||
/// How long to wait when entering a new tube
|
||||
var/enter_delay = 0
|
||||
/// How long to wait when exiting a new tube
|
||||
var/exit_delay
|
||||
/// The next time we'll be moving
|
||||
COOLDOWN_DECLARE(move_cooldown)
|
||||
/// The move animation mode for the next processing tick
|
||||
var/current_move_anim_mode = MOVE_ANIMATION_STAGE_ONE
|
||||
/// Icon state in use while we're occupied
|
||||
var/occupied_icon_state = "pod_occupied"
|
||||
|
||||
/obj/structure/transit_tube_pod/New(loc)
|
||||
..(loc)
|
||||
/obj/structure/transit_tube_pod/Initialize(mapload)
|
||||
. = ..()
|
||||
|
||||
air_contents.oxygen = MOLES_O2STANDARD * 2
|
||||
air_contents.nitrogen = MOLES_N2STANDARD
|
||||
@@ -18,9 +37,16 @@
|
||||
spawn(5)
|
||||
follow_tube()
|
||||
|
||||
/obj/structure/transit_tube_pod/update_icon_state()
|
||||
. = ..()
|
||||
icon_state = length(contents) ? occupied_icon_state : initial(icon_state)
|
||||
|
||||
/obj/structure/transit_tube_pod/proc/stop_following()
|
||||
STOP_PROCESSING(SStransit_tube, src)
|
||||
|
||||
/obj/structure/transit_tube_pod/Destroy()
|
||||
for(var/atom/movable/AM in contents)
|
||||
AM.forceMove(get_turf(src))
|
||||
empty_pod()
|
||||
stop_following()
|
||||
return ..()
|
||||
|
||||
/obj/structure/transit_tube_pod/Process_Spacemove()
|
||||
@@ -28,66 +54,111 @@
|
||||
return TRUE
|
||||
else return ..()
|
||||
|
||||
/obj/structure/transit_tube_pod/proc/empty_pod(atom/location)
|
||||
if(!location)
|
||||
location = get_turf(src)
|
||||
for(var/atom/movable/M in contents)
|
||||
M.forceMove(location)
|
||||
update_appearance()
|
||||
|
||||
/obj/structure/transit_tube_pod/crowbar_act(mob/living/user, obj/item/I)
|
||||
. = ..()
|
||||
if(moving)
|
||||
return
|
||||
|
||||
if(length(contents))
|
||||
I.play_tool_sound(src)
|
||||
user.visible_message("<span class='notice'>[user] pries [src] open.</span>")
|
||||
empty_pod()
|
||||
|
||||
/obj/structure/transit_tube_pod/process()
|
||||
..()
|
||||
|
||||
if(!COOLDOWN_FINISHED(src, move_cooldown))
|
||||
return
|
||||
|
||||
var/move_result = move_animation(current_move_anim_mode)
|
||||
if(isnull(move_result))
|
||||
if(isnull(current_tube) || (!(dir in current_tube.directions()) && !(reverse_direction(dir) in current_tube.directions())))
|
||||
outside_tube()
|
||||
return PROCESS_KILL
|
||||
|
||||
current_move_anim_mode = move_result
|
||||
|
||||
/obj/structure/transit_tube_pod/proc/outside_tube()
|
||||
var/list/savedcontents = contents.Copy()
|
||||
var/saveddir = dir
|
||||
var/turf/destination = get_edge_target_turf(src, saveddir)
|
||||
visible_message("<span class='warning'>[src] ejects its insides out!</span>")
|
||||
for(var/i in savedcontents)
|
||||
var/atom/movable/AM = i
|
||||
AM.throw_at(destination, rand(1, 3), 5)
|
||||
|
||||
|
||||
/obj/structure/transit_tube_pod/proc/move_animation(stage = MOVE_ANIMATION_STAGE_ONE)
|
||||
if(stage == MOVE_ANIMATION_STAGE_ONE)
|
||||
next_dir = current_tube.get_exit(dir)
|
||||
|
||||
if(!next_dir)
|
||||
moving = FALSE
|
||||
density = TRUE
|
||||
return
|
||||
exit_delay = current_tube.exit_delay
|
||||
next_loc = get_step(src, next_dir)
|
||||
current_tube = null
|
||||
for(var/obj/structure/transit_tube/tube in next_loc)
|
||||
if(tube.has_entrance(next_dir))
|
||||
current_tube = tube
|
||||
break
|
||||
|
||||
if(isnull(current_tube))
|
||||
setDir(next_dir)
|
||||
Move(get_step(loc, dir), dir) // Allow collisions when leaving the tubes.
|
||||
moving = FALSE
|
||||
density = TRUE
|
||||
return
|
||||
|
||||
enter_delay = current_tube.enter_delay(src, next_dir)
|
||||
if(enter_delay > 0)
|
||||
COOLDOWN_START(src, move_cooldown, enter_delay)
|
||||
return MOVE_ANIMATION_STAGE_TWO
|
||||
|
||||
stage = MOVE_ANIMATION_STAGE_TWO
|
||||
|
||||
if(stage == MOVE_ANIMATION_STAGE_TWO)
|
||||
setDir(next_dir)
|
||||
forceMove(next_loc) // When moving from one tube to another, skip collision and such.
|
||||
density = current_tube.density
|
||||
|
||||
if(current_tube?.should_stop_pod(src, next_dir))
|
||||
current_tube.pod_stopped(src, dir)
|
||||
else
|
||||
COOLDOWN_START(src, move_cooldown, exit_delay)
|
||||
return MOVE_ANIMATION_STAGE_ONE
|
||||
|
||||
density = TRUE
|
||||
moving = FALSE
|
||||
|
||||
return MOVE_ANIMATION_STAGE_ONE
|
||||
|
||||
|
||||
/obj/structure/transit_tube_pod/proc/follow_tube(reverse_launch)
|
||||
if(moving)
|
||||
return
|
||||
|
||||
moving = TRUE
|
||||
|
||||
spawn()
|
||||
var/obj/structure/transit_tube/current_tube = null
|
||||
var/next_dir
|
||||
var/next_loc
|
||||
var/last_delay = 0
|
||||
var/exit_delay
|
||||
|
||||
if(reverse_launch)
|
||||
dir = turn(dir, 180) // Back it up
|
||||
|
||||
for(var/obj/structure/transit_tube/tube in loc)
|
||||
if(tube.has_exit(dir))
|
||||
current_tube = tube
|
||||
break
|
||||
|
||||
while(current_tube)
|
||||
next_dir = current_tube.get_exit(dir)
|
||||
|
||||
if(!next_dir)
|
||||
break
|
||||
|
||||
exit_delay = current_tube.exit_delay(src, dir)
|
||||
last_delay += exit_delay
|
||||
|
||||
sleep(exit_delay)
|
||||
|
||||
next_loc = get_step(loc, next_dir)
|
||||
|
||||
current_tube = null
|
||||
for(var/obj/structure/transit_tube/tube in next_loc)
|
||||
if(tube.has_entrance(next_dir))
|
||||
current_tube = tube
|
||||
break
|
||||
|
||||
if(current_tube == null)
|
||||
setDir(next_dir)
|
||||
Move(get_step(loc, dir), dir) // Allow collisions when leaving the tubes.
|
||||
break
|
||||
|
||||
last_delay = current_tube.enter_delay(src, next_dir)
|
||||
sleep(last_delay)
|
||||
setDir(next_dir)
|
||||
forceMove(next_loc) // When moving from one tube to another, skip collision and such.
|
||||
density = current_tube.density
|
||||
|
||||
if(current_tube && current_tube.should_stop_pod(src, next_dir))
|
||||
current_tube.pod_stopped(src, dir)
|
||||
break
|
||||
|
||||
density = TRUE
|
||||
for(var/obj/structure/transit_tube/tube in loc)
|
||||
if(tube.has_exit(dir))
|
||||
current_tube = tube
|
||||
break
|
||||
|
||||
if(!isnull(current_tube))
|
||||
START_PROCESSING(SStransit_tube, src)
|
||||
// move_animation(MOVE_ANIMATION_STAGE_ONE)
|
||||
else
|
||||
moving = FALSE
|
||||
|
||||
|
||||
// Should I return a copy here? If the caller edits or qdel()s the returned
|
||||
// datum, there might be problems if I don't...
|
||||
/obj/structure/transit_tube_pod/return_air()
|
||||
@@ -174,8 +245,8 @@
|
||||
return
|
||||
|
||||
/obj/structure/transit_tube_pod/proc/move_into(atom/movable/A)
|
||||
icon_state = "pod_occupied"
|
||||
A.forceMove(src)
|
||||
update_appearance()
|
||||
|
||||
/obj/structure/transit_tube_pod/proc/eject_mindless(direction)
|
||||
for(var/atom/movable/A in contents)
|
||||
@@ -188,9 +259,24 @@
|
||||
|
||||
|
||||
/obj/structure/transit_tube_pod/proc/eject(atom/movable/A, direction)
|
||||
icon_state = "pod"
|
||||
A.forceMove(loc)
|
||||
update_appearance()
|
||||
A.Move(get_step(loc, direction), direction)
|
||||
if(ismob(A))
|
||||
var/mob/M = A
|
||||
M.reset_perspective(null)
|
||||
|
||||
|
||||
/obj/structure/transit_tube_pod/dispensed
|
||||
name = "temporary transit tube pod"
|
||||
desc = "Gets you from here to there, and no further."
|
||||
icon_state = "temppod"
|
||||
occupied_icon_state = "temppod_occupied"
|
||||
|
||||
|
||||
/obj/structure/transit_tube_pod/dispensed/outside_tube()
|
||||
if(!QDELETED(src))
|
||||
qdel(src)
|
||||
|
||||
#undef MOVE_ANIMATION_STAGE_TWO
|
||||
#undef MOVE_ANIMATION_STAGE_ONE
|
||||
|
||||
Reference in New Issue
Block a user