From 6a66f542d99ddb311c640806e13c19482fb0f3bf Mon Sep 17 00:00:00 2001 From: Uristqwerty Date: Wed, 20 Mar 2013 18:49:14 -0400 Subject: [PATCH] Update from early tubes with bugs, to tubes with less bugs and more features based on feedback. --- baystation12.dme | 3 +- .../Uristqwerty/transit_tube.dmi | Bin 12027 -> 0 bytes .../Uristqwerty/transit_tubes.dm | 405 ------------ code/game/objects/structures/transit_tubes.dm | 621 ++++++++++++++++++ icons/obj/pipes/transit_tube.dmi | Bin 0 -> 9791 bytes .../obj/pipes}/transit_tube_pod.dmi | Bin .../obj/pipes}/transit_tube_station.dmi | Bin 7 files changed, 622 insertions(+), 407 deletions(-) delete mode 100644 code/WorkInProgress/Uristqwerty/transit_tube.dmi delete mode 100644 code/WorkInProgress/Uristqwerty/transit_tubes.dm create mode 100644 code/game/objects/structures/transit_tubes.dm create mode 100644 icons/obj/pipes/transit_tube.dmi rename {code/WorkInProgress/Uristqwerty => icons/obj/pipes}/transit_tube_pod.dmi (100%) rename {code/WorkInProgress/Uristqwerty => icons/obj/pipes}/transit_tube_station.dmi (100%) diff --git a/baystation12.dme b/baystation12.dme index ed845c859c8..9ef6c90239f 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -14,7 +14,6 @@ #define FILE_DIR "code/WorkInProgress/Cael_Aislinn/ShieldGen" #define FILE_DIR "code/WorkInProgress/Cael_Aislinn/Supermatter" #define FILE_DIR "code/WorkInProgress/Susan" -#define FILE_DIR "code/WorkInProgress/Uristqwerty" #define FILE_DIR "html" #define FILE_DIR "icons" #define FILE_DIR "icons/48x48" @@ -606,6 +605,7 @@ #include "code\game\objects\structures\tables_racks.dm" #include "code\game\objects\structures\tank_dispenser.dm" #include "code\game\objects\structures\target_stake.dm" +#include "code\game\objects\structures\transit_tubes.dm" #include "code\game\objects\structures\watercloset.dm" #include "code\game\objects\structures\windoor_assembly.dm" #include "code\game\objects\structures\window.dm" @@ -1291,7 +1291,6 @@ #include "code\WorkInProgress\Ported\policetape.dm" #include "code\WorkInProgress\SkyMarshal\Ultralight_procs.dm" #include "code\WorkInProgress\Susan\susan_desert_turfs.dm" -#include "code\WorkInProgress\Uristqwerty\transit_tubes.dm" #include "code\WorkInProgress\virus2\analyser.dm" #include "code\WorkInProgress\virus2\antibodies.dm" #include "code\WorkInProgress\virus2\base.dm" diff --git a/code/WorkInProgress/Uristqwerty/transit_tube.dmi b/code/WorkInProgress/Uristqwerty/transit_tube.dmi deleted file mode 100644 index e70870018053792d14320637eaa45997445eb304..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12027 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 - GM.oxygen = (oxygen/sum)*amount - GM.carbon_dioxide = (carbon_dioxide/sum)*amount - GM.nitrogen = (nitrogen/sum)*amount - GM.toxins = (toxins/sum)*amount - - GM.temperature = T20C - GM.update_values() //Needed in ZAS to prevent suffocation. Not present in FEA. Comment/uncomment as nessecary. - - return GM - - - -// Called when a pod arrives at, and before a pod departs from a station, -// giving it a chance to mix its internal air supply with the turf it is -// currently on. -/obj/structure/transit_tube_pod/proc/mix_air() - //Needs to be implemented at some point - - - -// When the player moves, check if the pos is currently stopped at a station. -// if it is, check the direction. If the direction matches the direction of -// the station, try to exit. If the direction matches one of the station's -// tube directions, launch the pod in that direction. -/obj/structure/transit_tube_pod/relaymove(mob/mob, direction) - if(!moving && istype(mob, /mob) && mob.client) - for(var/obj/structure/transit_tube/station/station in loc) - if(!station.pod_moving && (dir in station.directions())) - if(direction == station.dir) - if(station.icon_state == "open") - mob.loc = loc - mob.client.Move(get_step(loc, direction), direction) - - else - station.open_animation() - - else if(direction in station.directions()) - dir = direction - station.launch_pod() - - - -/obj/structure/transit_tube/New(loc) - ..(loc) - - if(tube_dirs == null) - init_dirs() - - - -// 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() - tube_dirs = parse_dirs(icon_state) - - if(copytext(icon_state, 1, 3) == "D-") - density = 0 - - - -// 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)) - - - -// 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 = stringsplit(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 - else - return 0 \ No newline at end of file diff --git a/code/game/objects/structures/transit_tubes.dm b/code/game/objects/structures/transit_tubes.dm new file mode 100644 index 00000000000..5e85802b1fa --- /dev/null +++ b/code/game/objects/structures/transit_tubes.dm @@ -0,0 +1,621 @@ + +// Basic transit tubes. Straight pieces, curved sections, +// and basic splits/joins (no routing logic). +// Mappers: you can use "Generate Instances from Icon-states" +// to get the different pieces. +/obj/structure/transit_tube + icon = 'icons/obj/pipes/transit_tube.dmi' + icon_state = "E-W" + density = 1 + layer = 3.1 + anchored = 1.0 + var/list/tube_dirs = null + var/exit_delay = 2 + var/enter_delay = 1 + + // 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) + + +// A place where tube pods stop, and people can get in or out. +// Mappers: use "Generate Instances from Directions" for this +// one. +/obj/structure/transit_tube/station + icon = 'icons/obj/pipes/transit_tube_station.dmi' + icon_state = "closed" + exit_delay = 2 + enter_delay = 3 + var/pod_moving = 0 + var/automatic_launch_time = 100 + + var/const/OPEN_DURATION = 6 + var/const/CLOSE_DURATION = 6 + + + +/obj/structure/transit_tube_pod + icon = 'icons/obj/pipes/transit_tube_pod.dmi' + icon_state = "pod" + animate_movement = FORWARD_STEPS + anchored = 1.0 + density = 1 + var/moving = 0 + var/datum/gas_mixture/air_contents = new() + + + +/obj/structure/transit_tube_pod/Del() + for(var/atom/movable/AM in contents) + AM.loc = loc + + ..() + + + +// When destroyed by explosions, properly handle contents. +obj/structure/ex_act(severity) + switch(severity) + if(1.0) + for(var/atom/movable/AM in contents) + AM.loc = loc + AM.ex_act(severity++) + + del(src) + return + if(2.0) + if(prob(50)) + for(var/atom/movable/AM in contents) + AM.loc = loc + AM.ex_act(severity++) + + del(src) + return + if(3.0) + return + + + +/obj/structure/transit_tube_pod/New(loc) + ..(loc) + + air_contents.oxygen = MOLES_O2STANDARD * 2 + air_contents.nitrogen = MOLES_N2STANDARD + air_contents.temperature = T20C + + // Give auto tubes time to align before trying to start moving + spawn(5) + follow_tube() + + + +/obj/structure/transit_tube/New(loc) + ..(loc) + + if(tube_dirs == null) + init_dirs() + + + +/obj/structure/transit_tube/station/New(loc) + ..(loc) + + + +/obj/structure/transit_tube/station/Bumped(mob/AM as mob|obj) + if(!pod_moving && icon_state == "open" && istype(AM, /mob)) + for(var/obj/structure/transit_tube_pod/pod in loc) + if(!pod.moving && pod.dir in directions()) + AM.loc = pod + return + + + +/obj/structure/transit_tube/station/attack_hand(mob/user as mob) + if(!pod_moving) + for(var/obj/structure/transit_tube_pod/pod in loc) + if(!pod.moving && pod.dir in directions()) + if(icon_state == "closed") + open_animation() + + else if(icon_state == "open") + close_animation() + + + +/obj/structure/transit_tube/station/proc/open_animation() + if(icon_state == "closed") + icon_state = "opening" + spawn(OPEN_DURATION) + if(icon_state == "opening") + icon_state = "open" + + + +/obj/structure/transit_tube/station/proc/close_animation() + if(icon_state == "open") + icon_state = "closing" + spawn(CLOSE_DURATION) + if(icon_state == "closing") + icon_state = "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()) + spawn(5) + pod_moving = 1 + close_animation() + sleep(CLOSE_DURATION + 2) + if(icon_state == "closed" && pod) + pod.follow_tube() + + pod_moving = 0 + + return + + + +// 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 + + + +/obj/structure/transit_tube/station/should_stop_pod(pod, from_dir) + return 1 + + + +// Called when a pod stops in this tube section. +/obj/structure/transit_tube/proc/pod_stopped(pod, from_dir) + return + + + +/obj/structure/transit_tube/station/pod_stopped(obj/structure/transit_tube_pod/pod, from_dir) + pod_moving = 1 + spawn(5) + open_animation() + sleep(OPEN_DURATION + 2) + pod_moving = 0 + pod.mix_air() + + if(automatic_launch_time) + var/const/wait_step = 5 + var/i = 0 + while(i < automatic_launch_time) + sleep(wait_step) + i += wait_step + + if(pod_moving || icon_state != "open") + return + + launch_pod() + + + +// Returns a /list of directions this tube section can connect to. +// Tubes that have some sort of logic or changing direction might +// override it with additional logic. +/obj/structure/transit_tube/proc/directions() + return tube_dirs + + + +/obj/structure/transit_tube/proc/has_entrance(from_dir) + from_dir = turn(from_dir, 180) + + for(var/direction in directions()) + if(direction == from_dir) + return 1 + + return 0 + + + +/obj/structure/transit_tube/proc/has_exit(in_dir) + for(var/direction in directions()) + if(direction == in_dir) + return 1 + + return 0 + + + +// Searches for an exit direction within 45 degrees of the +// specified dir. Returns that direction, or 0 if none match. +/obj/structure/transit_tube/proc/get_exit(in_dir) + var/near_dir = 0 + var/in_dir_cw = turn(in_dir, -45) + var/in_dir_ccw = turn(in_dir, 45) + + for(var/direction in directions()) + if(direction == in_dir) + return direction + + else if(direction == in_dir_cw) + near_dir = direction + + else if(direction == in_dir_ccw) + near_dir = direction + + return near_dir + + + +// Return how many BYOND ticks to wait before entering/exiting +// the tube section. Default action is to return the value of +// a var, which wouldn't need a proc, but it makes it possible +// for later tube types to interact in more interesting ways +// such as being very fast in one direction, but slow in others +/obj/structure/transit_tube/proc/exit_delay(pod, to_dir) + return exit_delay + +/obj/structure/transit_tube/proc/enter_delay(pod, to_dir) + return enter_delay + + + +/obj/structure/transit_tube_pod/proc/follow_tube() + if(moving) + return + + moving = 1 + + spawn() + var/obj/structure/transit_tube/current_tube = null + var/next_dir + var/next_loc + var/last_delay = 0 + var/exit_delay + + 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) + dir = next_dir + Move(get_step(loc, dir)) // Allow collisions when leaving the tubes. + break + + last_delay = current_tube.enter_delay(src, next_dir) + sleep(last_delay) + dir = next_dir + loc = 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 = 1 + + // If the pod is no longer in a tube, move in a line until stopped or slowed to a halt. + // /turf/inertial_drift appears to only work on mobs, and re-implementing some of the + // logic allows a gradual slowdown and eventual stop when passing over non-space turfs. + if(!current_tube && last_delay <= 10) + do + sleep(last_delay) + + if(!istype(loc, /turf/space)) + last_delay++ + + if(last_delay > 10) + break + + while(isturf(loc) && Move(get_step(loc, dir))) + + moving = 0 + + +// Should I return a copy here? If the caller edits or del()s the returned +// datum, there might be problems if I don't... +/obj/structure/transit_tube_pod/return_air() + var/datum/gas_mixture/GM = new() + GM.oxygen = air_contents.oxygen + GM.carbon_dioxide = air_contents.carbon_dioxide + GM.nitrogen = air_contents.nitrogen + GM.toxins = air_contents.toxins + GM.temperature = air_contents.temperature + return GM + +// For now, copying what I found in an unused FEA file (and almost identical in a +// used ZAS file). Means that assume_air and remove_air don't actually alter the +// air contents. +/obj/structure/transit_tube_pod/assume_air(datum/gas_mixture/giver) + return air_contents.merge(giver) + +/obj/structure/transit_tube_pod/remove_air(amount) + return air_contents.remove(amount) + + + +// Called when a pod arrives at, and before a pod departs from a station, +// giving it a chance to mix its internal air supply with the turf it is +// currently on. +/obj/structure/transit_tube_pod/proc/mix_air() + var/datum/gas_mixture/environment = loc.return_air() + var/env_pressure = environment.return_pressure() + var/int_pressure = air_contents.return_pressure() + var/total_pressure = env_pressure + int_pressure + + if(total_pressure == 0) + return + + // Math here: Completely made up, not based on realistic equasions. + // Goal is to balance towards equal pressure, but ensure some gas + // transfer in both directions regardless. + // Feel free to rip this out and replace it with something better, + // I don't really know muhch about how gas transfer rates work in + // SS13. + var/transfer_in = max(0.1, 0.5 * (env_pressure - int_pressure) / total_pressure) + var/transfer_out = max(0.1, 0.3 * (int_pressure - env_pressure) / total_pressure) + + var/datum/gas_mixture/from_env = loc.remove_air(environment.total_moles() * transfer_in) + var/datum/gas_mixture/from_int = air_contents.remove(air_contents.total_moles() * transfer_out) + + loc.assume_air(from_int) + air_contents.merge(from_env) + + + +// When the player moves, check if the pos is currently stopped at a station. +// if it is, check the direction. If the direction matches the direction of +// the station, try to exit. If the direction matches one of the station's +// tube directions, launch the pod in that direction. +/obj/structure/transit_tube_pod/relaymove(mob/mob, direction) + if(istype(mob, /mob) && mob.client) + // If the pod is not in a tube at all, you can get out at any time. + if(!(locate(/obj/structure/transit_tube) in loc)) + mob.loc = loc + mob.client.Move(get_step(loc, direction), direction) + + //if(moving && istype(loc, /turf/space)) + // Todo: If you get out of a moving pod in space, you should move as well. + // Same direction as pod? Direcion you moved? Halfway between? + + if(!moving) + for(var/obj/structure/transit_tube/station/station in loc) + if(dir in station.directions()) + if(!station.pod_moving) + if(direction == station.dir) + if(station.icon_state == "open") + mob.loc = loc + mob.client.Move(get_step(loc, direction), direction) + + else + station.open_animation() + + else if(direction in station.directions()) + dir = direction + station.launch_pod() + return + + for(var/obj/structure/transit_tube/tube in loc) + if(dir in tube.directions()) + if(tube.has_exit(direction)) + dir = direction + return + + + +// 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() + + else + tube_dirs = parse_dirs(icon_state) + + if(copytext(icon_state, 1, 3) == "D-" || findtextEx(icon_state, "Pass")) + density = 0 + + + +// 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)) + + + +// 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() + + 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 + + else if(turn(direction, 180) in tube.directions()) + connected += direction + break + + 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) + + + +// 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() + + 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] + + 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/proc/select_automatic_icon_state(directions) + if(length(directions) == 2) + icon_state = "[dir2text_short(directions[1])]-[dir2text_short(directions[2])]" + + + +// 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 = stringsplit(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 + else + return 0 + + + +// 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" + else + return diff --git a/icons/obj/pipes/transit_tube.dmi b/icons/obj/pipes/transit_tube.dmi new file mode 100644 index 0000000000000000000000000000000000000000..45b2abc3c3efe0aa6dcd7924c99095df6377a408 GIT binary patch literal 9791 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