diff --git a/citadel.dme b/citadel.dme index 0da2380ea27..e308edc24ad 100644 --- a/citadel.dme +++ b/citadel.dme @@ -399,6 +399,7 @@ #include "code\__HELPERS\files\walk.dm" #include "code\__HELPERS\game\depth.dm" #include "code\__HELPERS\game\combat\arc.dm" +#include "code\__HELPERS\game\turfs\blocks.dm" #include "code\__HELPERS\game\turfs\line.dm" #include "code\__HELPERS\game\turfs\offsets.dm" #include "code\__HELPERS\graphs\astar.dm" @@ -3497,10 +3498,10 @@ #include "code\modules\mob\logout.dm" #include "code\modules\mob\mob-damage.dm" #include "code\modules\mob\mob-defense.dm" +#include "code\modules\mob\mob-iff.dm" #include "code\modules\mob\mob-keybind-triggers.dm" #include "code\modules\mob\mob.dm" #include "code\modules\mob\mob_defines.dm" -#include "code\modules\mob\mob-iff.dm" #include "code\modules\mob\mob_helpers.dm" #include "code\modules\mob\mob_transformation_simple.dm" #include "code\modules\mob\mobility.dm" @@ -4705,6 +4706,13 @@ #include "code\modules\shuttles\shuttles_vr.dm" #include "code\modules\shuttles\shuttles_web.dm" #include "code\modules\shuttles\web_datums.dm" +#include "code\modules\shuttles\effects\shuttle_landing.dm" +#include "code\modules\shuttles\shuttle\shuttle.dm" +#include "code\modules\shuttles\shuttle\shuttle_anchor.dm" +#include "code\modules\shuttles\shuttle\shuttle_area.dm" +#include "code\modules\shuttles\shuttle\shuttle_descriptor.dm" +#include "code\modules\shuttles\shuttle\shuttle_port.dm" +#include "code\modules\shuttles\shuttle\shuttle_template.dm" #include "code\modules\species\abilites.dm" #include "code\modules\species\character_species.dm" #include "code\modules\species\physiology.dm" @@ -5289,6 +5297,8 @@ #include "maps\sectors\virgo4_140\virgo4_140.dm" #include "maps\sectors\wasteland_140\wasteland_140.dm" #include "maps\sectors\wasteland_192\wasteland_192.dm" +#include "maps\shuttles\factions\corporations\nanotrasen\drone_prototype.dm" +#include "maps\shuttles\factions\corporations\nanotrasen\sci_vector.dm" #include "maps\submaps\_helpers.dm" #include "maps\submaps\_readme.dm" #include "maps\submaps\level_specific\debrisfield_vr\debrisfield_things.dm" diff --git a/code/__DEFINES/_flags/turf_flags.dm b/code/__DEFINES/_flags/turf_flags.dm index 4ebcf6344bb..41ea1782888 100644 --- a/code/__DEFINES/_flags/turf_flags.dm +++ b/code/__DEFINES/_flags/turf_flags.dm @@ -2,7 +2,7 @@ /// This is used in literally one place, turf.dm, to block ethwereal jaunt. #define NO_JAUNT (1<<0) /// Unused reservation turf -#define UNUSED_RESERVATION_TURF (1<<2) +#define TURF_FLAG_UNUSED_RESERVATION (1<<2) /// queued for planet turf addition #define TURF_PLANET_QUEUED (1<<3) /// registered to a planet @@ -28,7 +28,7 @@ DEFINE_BITFIELD(turf_flags, list( BITFIELD(NO_JAUNT), - BITFIELD(UNUSED_RESERVATION_TURF), + BITFIELD(TURF_FLAG_UNUSED_RESERVATION), BITFIELD(TURF_PLANET_QUEUED), BITFIELD(TURF_PLANET_REGISTERED), BITFIELD(TURF_ZONE_REBUILD_QUEUED), diff --git a/code/__DEFINES/_planes+layers.dm b/code/__DEFINES/_planes+layers.dm index b38ab1a0fdd..4dad67ea7f6 100644 --- a/code/__DEFINES/_planes+layers.dm +++ b/code/__DEFINES/_planes+layers.dm @@ -329,6 +329,7 @@ */ #define DEBUG_PLANE 23 #define DEBUG_LAYER_AREA_OVERLAYS 100 +#define DEBUG_LAYER_SHUTTLE_MARKERS 500 /** *! -- Ghost Plane diff --git a/code/__HELPERS/game/turfs/blocks.dm b/code/__HELPERS/game/turfs/blocks.dm new file mode 100644 index 00000000000..d0a5e064a0a --- /dev/null +++ b/code/__HELPERS/game/turfs/blocks.dm @@ -0,0 +1,83 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/** + * get turfs bordering a block of turfs + * + * * returned list will be empty if distance = 0 + * * returned list will have all nulls incurred by turfs being outside world border + * * returned list **has no particular order.** + * + * @params + * * ll_x - lowerleft x + * * ll_y - lowerleft y + * * ur_x - upperright x + * * ur_y - upperright y + * * z - z level + * * distance - border distance + * + * @return list() if distance = 0, list of turfs otherwise. turfs outside of world border will be null. + */ +/proc/border_of_turf_block(ll_x, ll_y, ur_x, ur_y, z, distance) + if(distance <= 0) + return list() + . = block( + ll_x - distance, + ll_y - distance, + z, + ll_x - 1, + ur_y + distance, + ) + block( + ur_x + 1, + ll_y - distance, + z, + ur_x + distance, + ur_y + distance, + ) + block( + ll_x, + ur_y + 1, + z, + ur_x, + ur_y + distance, + ) + block( + ll_x, + ll_y - distance, + z, + ur_x, + ll_y - 1, + ) + +/** + * get turfs bordering a block of turfs + * + * * returned list will be empty if distance = 0 + * * returned list will have all nulls incurred by turfs being outside world border + * * returned list is in clockwise order from the **upper left** turf, spiralling outwards from there. + * + * @params + * * ll_x - lowerleft x + * * ll_y - lowerleft y + * * ur_x - upperright x + * * ur_y - upperright y + * * z - z level + * * distance - border distance + * + * @return list() if distance = 0, list of turfs otherwise. turfs outside of world border will be null. + */ +/proc/border_of_turf_block_spiral_outwards_clockwise(ll_x, ll_y, ur_x, ur_y, z, distance) + if(distance <= 0) + return list() + . = list() + for(var/radius in distance) + // gather top left to right + for(var/x in (ll_x - radius) to (ur_x + radius)) + . += locate(x, ur_y + radius, z) + // gather right top to bottom excluding top and bottom turf + for(var/y in (ur_y + radius - 1) to (ll_y - radius + 1) step -1) + . += locate(ur_x + radius, y, z) + // gather bottom right to left + for(var/x in (ur_x + radius) to (ll_x - radius) step -1) + . += locate(x, ll_y - radius, z) + // gather left bottom to top excluding top and bottom turf + for(var/y in (ll_y - radius + 1) to (ur_y + radius - 1)) + . += locate(ll_x - radius, y, z) diff --git a/code/__HELPERS/game/turfs/line.dm b/code/__HELPERS/game/turfs/line.dm index c07645d3eb2..59a213720cd 100644 --- a/code/__HELPERS/game/turfs/line.dm +++ b/code/__HELPERS/game/turfs/line.dm @@ -1,5 +1,5 @@ //* This file is explicitly licensed under the MIT license. *// -//* Copyright (c) 2024 silicons *// +//* Copyright (c) 2024 Citadel Station Developers *// /** * line drawing algorithm diff --git a/code/__HELPERS/game/turfs/offsets.dm b/code/__HELPERS/game/turfs/offsets.dm index cd206ffe074..df4508beb42 100644 --- a/code/__HELPERS/game/turfs/offsets.dm +++ b/code/__HELPERS/game/turfs/offsets.dm @@ -1,5 +1,5 @@ //* This file is explicitly licensed under the MIT license. *// -//* Copyright (c) 2024 silicons *// +//* Copyright (c) 2024 Citadel Station Developers *// /** * get coordinate and direction tuple when entity is moved relative with a 'block' movement, diff --git a/code/controllers/subsystem/mapping/reservations.dm b/code/controllers/subsystem/mapping/reservations.dm index b9338097e3d..cd329e039ca 100644 --- a/code/controllers/subsystem/mapping/reservations.dm +++ b/code/controllers/subsystem/mapping/reservations.dm @@ -99,7 +99,7 @@ /datum/controller/subsystem/mapping/proc/reserve_turfs(list/turf/turfs) for(var/turf/T as anything in turfs) T.empty(RESERVED_TURF_TYPE, RESERVED_TURF_TYPE) - T.turf_flags |= UNUSED_RESERVATION_TURF + T.turf_flags |= TURF_FLAG_UNUSED_RESERVATION CHECK_TICK // todo: area.assimilate_turfs? reservation_unallocated_area.contents.Add(turfs) diff --git a/code/game/area/area.dm b/code/game/area/area.dm index cb17cde4736..e0a0850c031 100644 --- a/code/game/area/area.dm +++ b/code/game/area/area.dm @@ -53,6 +53,10 @@ /// default initial gas mix var/initial_gas_mix = GAS_STRING_STP + //* Identity *// + /// player-facing name, overrides name when / if necessary. + var/display_name + //? nightshift /// nightshift level /// in general, nightshift must be at or above this level for it to proc on areas. diff --git a/code/game/objects/effects/misc.dm b/code/game/objects/effects/misc.dm index d03e8a0d3c4..d5befd0dc5a 100644 --- a/code/game/objects/effects/misc.dm +++ b/code/game/objects/effects/misc.dm @@ -38,16 +38,6 @@ . = ..() animate(src, alpha = 0, time = time_to_die - 1) -/obj/effect/temporary_effect/shuttle_landing - name = "shuttle landing" - desc = "You better move if you don't want to go splat!" - icon_state = "shuttle_warning_still" - time_to_die = 4.9 SECONDS - -/obj/effect/temporary_effect/shuttle_landing/Initialize(mapload) - flick("shuttle_warning", src) // flick() forces the animation to always begin at the start. - . = ..() - // The manifestation of Zeus's might. Or just a really unlucky day. // This is purely a visual effect, this isn't the part of the code that hurts things. /obj/effect/temporary_effect/lightning_strike diff --git a/code/modules/mapping/turf_reservation.dm b/code/modules/mapping/turf_reservation.dm index 5404480cfd0..d58ff598bd1 100644 --- a/code/modules/mapping/turf_reservation.dm +++ b/code/modules/mapping/turf_reservation.dm @@ -75,6 +75,19 @@ release() return ..() +/datum/turf_reservation/proc/get_approximately_center_turf() + return locate( + bottom_left_coords[1] + floor(top_right_coords[1] - bottom_left_coords[1]), + bottom_left_coords[2] + floor(top_right_coords[2] - bottom_left_coords[2]), + bottom_left_coords[3], + ) + +/datum/turf_reservation/proc/is_atom_inside(atom/A) + A = get_turf(A) + return A.z == bottom_left_coords[3] && \ + A.x >= bottom_left_coords[1] && A.x <= top_right_coords[1] && \ + A.y >= bottom_left_coords[2] && A.y <= top_right_coords[2] + /datum/turf_reservation/proc/release() if(border) SSmapping.reserve_turfs(block(locate( @@ -170,7 +183,7 @@ 1 + (inner_y - 1) * TURF_CHUNK_RESOLUTION, level_index, ) - if(!(checking.turf_flags & UNUSED_RESERVATION_TURF)) + if(!(checking.turf_flags & TURF_FLAG_UNUSED_RESERVATION)) passing = FALSE break if(!passing) @@ -245,7 +258,7 @@ SSmapping.reservation_blocking_op = FALSE return FALSE for(var/turf/T as anything in final) - T.turf_flags &= ~UNUSED_RESERVATION_TURF + T.turf_flags &= ~TURF_FLAG_UNUSED_RESERVATION if(T.type != turf_type) T.ChangeTurf(turf_type, turf_type) @@ -262,7 +275,7 @@ // todo: take_turfs src.border_area.contents.Add(final_border) for(var/turf/T as anything in final_border) - T.turf_flags &= ~UNUSED_RESERVATION_TURF + T.turf_flags &= ~TURF_FLAG_UNUSED_RESERVATION // get just the first layer, but also init them at the same time var/list/turf/final_immediate_border // left diff --git a/code/modules/shuttles/effects/shuttle_landing.dm b/code/modules/shuttles/effects/shuttle_landing.dm new file mode 100644 index 00000000000..94469c5609d --- /dev/null +++ b/code/modules/shuttles/effects/shuttle_landing.dm @@ -0,0 +1,30 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +// todo: maybe orchestrate this with lists and timers on shuttle_transit_cycle? +/obj/effect/temporary_effect/shuttle_landing + name = "shuttle landing" + desc = "A massive entity is about to land here. You should not be here." + icon = 'icons/modules/shuttles/effects/shuttle_landing.dmi' + icon_state = "still" + time_to_die = 4.9 SECONDS + +/obj/effect/temporary_effect/shuttle_landing/Initialize(mapload, time_to_dock) + if(!isnull(time_to_dock)) + time_to_die = time_to_dock + run_animation() + return ..() + +/obj/effect/temporary_effect/shuttle_landing/proc/run_animation() + var/half_time = time_to_die / 2 + + var/matrix/using_matrix = matrix() + using_matrix.Scale(0.1, 0.1) + + transform = using_matrix + alpha = 75 + + using_matrix.Scale(10, 10) + animate(src, time = half_time, transform = using_matrix, alpha = 150) + + animate(src, time = half_time, alpha = 255) diff --git a/code/modules/shuttles/shuttle.dm b/code/modules/shuttles/shuttle.dm index c1add76a05a..604792f7ba2 100644 --- a/code/modules/shuttles/shuttle.dm +++ b/code/modules/shuttles/shuttle.dm @@ -1,7 +1,6 @@ //shuttle moving state defines are in setup.dm /datum/shuttle - var/name = "" var/warmup_time = 0 var/moving_status = SHUTTLE_IDLE @@ -14,8 +13,6 @@ var/category = /datum/shuttle var/multiz = 0 // How many multiz levels, starts at 0 TODO Leshana - Are we porting this? - var/ceiling_type = /turf/simulated/shuttle_ceiling // Type path of turf to roof over the shuttle when at multi-z landmarks. Ignored if null. - var/sound_takeoff = 'sound/effects/shuttles/shuttle_takeoff.ogg' var/sound_landing = 'sound/effects/shuttles/shuttle_landing.ogg' diff --git a/code/modules/shuttles/shuttle/shuttle.dm b/code/modules/shuttles/shuttle/shuttle.dm new file mode 100644 index 00000000000..e4dab761d4c --- /dev/null +++ b/code/modules/shuttles/shuttle/shuttle.dm @@ -0,0 +1,37 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/** + * # Shuttles + * + * Core datum for shuttles. + * + * ## Controllers + * + * All shuttle behaviors are now in controllers whenever possible. The base datum just handles the actual shuttle itself. + * Moving to transit and staying in transit? That's a controller thing. Temporary dynamic transit? That's a controller thing, too. + * + * todo: nestable-shuttle support ? e.g. transport ship on a shuttle ; this is not optimal for performance but sure is cool + * todo: multi-z shuttles; is this even possible? very long term. + * todo: areas is a shit system. this is probably not fixable, because how else would we do bounding boxes? + * todo: it would sure be nice to be able to dynamically expand shuttles in-game though; probably a bad idea too. + * todo: serialize/deserialize, but should it be on this side or the map tempalte side? we want save/loadable. + */ +/datum/shuttle + //* Intrinsics *// + /// our unique template id; this is *not* our ID and is *not* unique! + var/template_id + /// our descriptor instance; this is what determines how we act + /// to our controller, as well as things like overmaps. + var/datum/shuttle_descriptor/descriptor + + //* Identity *// + /// real / code name + var/name = "Unnamed Shuttle" + /// description for things like admin interfaces + var/desc = "Some kind of shuttle. The coder forgot to set this." + + //* Structure *// + /// if set, we generate a ceiling above the shuttle of this type, on the bottom of the turf stack. + // todo: vv hook this + var/ceiling_type = /turf/simulated/shuttle_ceiling diff --git a/code/modules/shuttles/shuttle/shuttle_anchor.dm b/code/modules/shuttles/shuttle/shuttle_anchor.dm new file mode 100644 index 00000000000..4f3051e4cd0 --- /dev/null +++ b/code/modules/shuttles/shuttle/shuttle_anchor.dm @@ -0,0 +1,135 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/** + * the physical shuttle object + * + * for aligned docks, we align the direction and the tile to the shuttle dock. + * + * ## Bounds + * + * size_x, size_y describes our total bounding box size when facing NORTH. + * offset_x, offset_y describes where the anchor is when facing NORTH. + * + * The anchor is always aligned to the top left, with no offsets, in this way. + * When rotated it is where it would be when rotated counterclockwise to the new position. + * + * For a size_x, size_y of 6, 4: + * + * offset_x, offset_y = 0, dir NORTH + * + * ^00000 + * 000000 + * 000000 + * 000000 + * + * offset_x, offset_y = 0, dir SOUTH + * + * 000000 + * 000000 + * 000000 + * 00000V + * + * offset_x, offset_y = 0, dir WEST + * + * 0000 + * 0000 + * 0000 + * 0000 + * 0000 + * <000 + * + * offset_x, offset_y = 3, -1, dir NORTH + * + * 000000 + * 000^00 + * 000000 + * 000000 + * + * offset_x, offset_y = 3, -1, dir SOUTH + * + * 000000 + * 000000 + * 00V000 + * 000000 + * + * offset_x, offset_y = 3, -1, dir WEST + * + * 0000 + * 0000 + * 0<00 + * 0000 + * 0000 + * 0000 + * + * Offsets can position the anchor outside. This works, albeit is a bad idea. + * + * ## Mappers + * + * * You don't need to put down anchors at all, they auto-generate. + * * If you place one anyways, it'll be respected. That said, the size will be auto-generated too. + * + * Do not mess with the variables; the init system will set them. + */ +/obj/shuttle_anchor + name = "Shuttle (uninitialized)" + desc = "Why do you see this?" + // by default this should be north. + dir = NORTH + icon = 'icons/modules/shuttles/shuttle_anchor.dmi' + icon_state = "main" + plane = DEBUG_PLANE + layer = DEBUG_LAYER_SHUTTLE_MARKERS + atom_flags = ATOM_ABSTRACT | ATOM_NONWORLD + +#ifndef CF_SHUTTLE_VISUALIZE_BOUNDING_BOXES + invisibility = INVISIBILITY_ABSTRACT +#else + invisibility = INVISIBILITY_NONE +#endif + + /// shuttle datum + var/tmp/datum/shuttle/shuttle + + /// see main documentation + var/tmp/size_x + /// see main documentation + var/tmp/size_y + /// see main documentation + var/tmp/offset_x + /// see main documentation + var/tmp/offset_y + + /// are we moving right now? + var/tmp/anchor_moving = FALSE + +// This file is WIP, and is just here so mappers can start using them. + +//* Movement Hooks ; We don't allow normal movement. *// + +/obj/shuttle_anchor/forceMove() + CRASH("attempted to forcemove a shuttle anchor") + +/obj/shuttle_anchor/setDir(ndir) + if(!anchor_moving) + CRASH("attempted to setDir an anchor") + return ..() + +/obj/shuttle_anchor/abstract_move(atom/new_loc) + if(!anchor_moving) + CRASH("attempted to abstract_move a shuttle anchor") + return ..() + +//* Grid Hooks ; Shuttle manually moves us. *// + +/obj/shuttle_anchor/grid_move(grid_flags, turf/new_turf) + return + +/obj/shuttle_anchor/grid_after(grid_flags, rotation_angle, list/late_call_hooks) + return + +/obj/shuttle_anchor/grid_collect(grid_flags, turf/new_turf, loc_opinion) + return + +/obj/shuttle_anchor/grid_finished(grid_flags, rotation_angle) + return diff --git a/code/modules/shuttles/shuttle/shuttle_area.dm b/code/modules/shuttles/shuttle/shuttle_area.dm new file mode 100644 index 00000000000..1aabc5e4c34 --- /dev/null +++ b/code/modules/shuttles/shuttle/shuttle_area.dm @@ -0,0 +1,42 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/** + * shuttle areas + */ +/area/shuttle + unique = FALSE + /// will be assigned the shuttle's ref post-init + var/datum/shuttle/shuttle + +/area/shuttle/proc/before_bounds_initializing(datum/shuttle/from_shuttle, datum/turf_reservation/from_reservation, datum/shuttle_template/from_template) + shuttle = from_shuttle + +/** + * autodetecting area + */ +/area/shuttle/auto + /// [name] [count?] [descriptor?] + var/count + /// [name] [count?] [descriptor?] + var/descriptor = "Compartment" + +/area/shuttle/auto/before_bounds_initializing(datum/shuttle/from_shuttle, datum/turf_reservation/from_reservation, datum/shuttle_template/from_template) + // todo: shuttle + +/area/shuttle/auto/proc/auto_name_instance(real_name, display_name) + src.name = "[real_name][count && " [count]"][descriptor && " [descriptor]"]" + src.display_name = display_name + +/area/shuttle/auto/primary + count = "Primary" + +/area/shuttle/auto/secondary + count = "Secondary" + +/area/shuttle/auto/tertiary + count = "Tertiary" + +/area/shuttle/auto/one_single_area + count = "" + descriptor = "" diff --git a/code/modules/shuttles/shuttle/shuttle_descriptor.dm b/code/modules/shuttles/shuttle/shuttle_descriptor.dm new file mode 100644 index 00000000000..7ebfbdfc003 --- /dev/null +++ b/code/modules/shuttles/shuttle/shuttle_descriptor.dm @@ -0,0 +1,35 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/** + * while /datum/shuttle_template describes the physical shuttle, this describes features + * like mass. + */ +/datum/shuttle_descriptor + //* Flight (overmaps / web) *// + /// mass in kilotons + // todo: in-game mass calculations? only really relevant for drone tbh + var/mass = 5 + /// if set to false, this is absolute-ly unable to land on a planet + var/allow_atmospheric_landing = TRUE + /// preferred flight orientation + /// + /// * null = use orientation at takeoff + var/preferred_orientation + + //* Jumps (ferry & moving to/from overmaps) *// + /// engine charging time when starting a move + // todo: should have support for being based on in game machinery (?) + var/jump_charging_time = 10 SECONDS + /// time spent in transit when performing a move + var/jump_move_time = 10 SECONDS + +/datum/shuttle_descriptor/clone(include_contents) + var/datum/shuttle_descriptor/clone = ..() + + clone.mass = mass + clone.allow_atmospheric_landing = allow_atmospheric_landing + clone.preferred_orientation = preferred_orientation + + clone.jump_charging_time = jump_charging_time + clone.jump_move_time = jump_move_time diff --git a/code/modules/shuttles/shuttle/shuttle_port.dm b/code/modules/shuttles/shuttle/shuttle_port.dm new file mode 100644 index 00000000000..159df194b80 --- /dev/null +++ b/code/modules/shuttles/shuttle/shuttle_port.dm @@ -0,0 +1,188 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/** + * shuttle-side docking port; put this on airlocks + */ +/obj/shuttle_port + /// port name - used in interfaces + name = "docking port" + /// port desc - used in interfaces + desc = "A port that allows the shuttle to align to a dock." + icon = 'icons/modules/shuttles/shuttle_anchor.dmi' + icon_state = "dock" + plane = DEBUG_PLANE + layer = DEBUG_LAYER_SHUTTLE_MARKERS + atom_flags = ATOM_ABSTRACT | ATOM_NONWORLD + +#ifndef CF_SHUTTLE_VISUALIZE_BOUNDING_BOXES + invisibility = INVISIBILITY_ABSTRACT +#else + invisibility = INVISIBILITY_NONE +#endif + + /// shuttle datum + var/tmp/datum/shuttle/shuttle + + /// dock width - this is how wide the airlock/otherwise opening is. + /// + /// the port is left-aligned to the width when looking north + /// so if it's width 3, + /// we have this: + /// ^XX + /// + /// if the port is rotated, we are left-aligned to the *direction of the port*, e.g. + /// east, = + /// > + /// x + /// x + var/port_width = 1 + /// offset the port right in the width + /// + /// width 3, offset 2: + /// XX^ + /// + /// this is needed because port alignment must always be + /// exact, so things like power lines and atmos lines can be connected. + var/port_offset = 0 + /// how many tiles of 'safety' extends to both sides of the width + /// this means that an airtight seal can be formed as long as the dock accomodates the safety region, + /// even if it's too big for the width + var/port_margin = 1 + /// port id - must be unique per shuttle instance + /// the maploader will handle ID scrambling + /// + /// * if this doesn't exist, stuff that need to hook it won't work. + /// * if this isn't set, we'll assign it a random one on init + var/port_id + + /// registered shuttle hooks + var/tmp/list/datum/shuttle_hook/hooks + + /// is this the primary port? + /// if it is, this is what we align with for roundstart loading. + var/primary_port = FALSE + + /// are we moving right now? + var/tmp/port_moving = FALSE + +/obj/shuttle_port/preloading_instance(with_id) + . = ..() + port_id = SSmapping.mangled_persistent_id(port_id, with_id) + +// This file is WIP, and is just here so mappers can start using them. + +//* Movement Hooks ; We don't allow normal movement. *// + +/obj/shuttle_port/forceMove() + CRASH("attempted to forceMove a shuttle port") + +/obj/shuttle_port/setDir(ndir) + if(!port_moving) + CRASH("attempted to setDir a shuttle port") + return ..() + +/obj/shuttle_port/abstract_move(atom/new_loc) + if(!port_moving) + CRASH("attempted to abstract_move a shuttle port") + return ..() + +//* Grid Hooks ; Shuttle manually moves us. *// + +/obj/shuttle_port/grid_move(grid_flags, turf/new_turf) + return + +/obj/shuttle_port/grid_after(grid_flags, rotation_angle, list/late_call_hooks) + return + +/obj/shuttle_port/grid_collect(grid_flags, turf/new_turf, loc_opinion) + return + +/obj/shuttle_port/grid_finished(grid_flags, rotation_angle) + return + +#define SHUTTLE_PORT_PATH(PATH) \ +/obj/shuttle_port/##PATH/primary { \ + primary_port = TRUE; \ + color = "#88ff88"; \ +} \ +/obj/shuttle_port/##PATH + +/obj/shuttle_port/north + dir = NORTH + +SHUTTLE_PORT_PATH(south) + dir = SOUTH + +SHUTTLE_PORT_PATH(east) + dir = EAST + +SHUTTLE_PORT_PATH(west) + dir = WEST + +SHUTTLE_PORT_PATH(two_wide) + abstract_type = /obj/shuttle_port/two_wide + icon = 'icons/modules/shuttles/shuttle_anchor_2x2.dmi' + icon_state = "dock" + port_width = 2 + +SHUTTLE_PORT_PATH(two_wide/left_aligned) + +SHUTTLE_PORT_PATH(two_wide/left_aligned/north) + dir = NORTH + +SHUTTLE_PORT_PATH(two_wide/left_aligned/south) + dir = SOUTH + port_offset = 1 + pixel_x = -32 + +SHUTTLE_PORT_PATH(two_wide/left_aligned/east) + dir = EAST + port_offset = 1 + pixel_y = -32 + +SHUTTLE_PORT_PATH(two_wide/left_aligned/west) + dir = WEST + +SHUTTLE_PORT_PATH(two_wide/right_aligned) + +SHUTTLE_PORT_PATH(two_wide/right_aligned/north) + dir = NORTH + port_offset = 1 + pixel_x = -32 + +SHUTTLE_PORT_PATH(two_wide/right_aligned/south) + dir = SOUTH + +SHUTTLE_PORT_PATH(two_wide/right_aligned/east) + dir = EAST + +SHUTTLE_PORT_PATH(two_wide/right_aligned/west) + dir = WEST + port_offset = 1 + pixel_y = -32 + +SHUTTLE_PORT_PATH(three_wide) + icon = 'icons/modules/shuttles/shuttle_anchor_3x3.dmi' + icon_state = "dock" + port_width = 3 + +SHUTTLE_PORT_PATH(three_wide/north) + dir = NORTH + port_offset = 1 + pixel_x = -32 + +SHUTTLE_PORT_PATH(three_wide/south) + dir = SOUTH + port_offset = 1 + pixel_x = -32 + +SHUTTLE_PORT_PATH(three_wide/east) + dir = EAST + port_offset = 1 + pixel_y = -32 + +SHUTTLE_PORT_PATH(three_wide/west) + dir = WEST + port_offset = 1 + pixel_y = -32 diff --git a/code/modules/shuttles/shuttle/shuttle_template.dm b/code/modules/shuttles/shuttle/shuttle_template.dm new file mode 100644 index 00000000000..ac947798b71 --- /dev/null +++ b/code/modules/shuttles/shuttle/shuttle_template.dm @@ -0,0 +1,143 @@ +//* This file is explicitly licensed under the MIT license. *// +//* Copyright (c) 2024 Citadel Station Developers *// + +/** + * the shuttle templates in charge of holding definitions of shuttles. + * + * each can be instantiated multiple times unless otherwise stated. + */ +/datum/shuttle_template + abstract_type = /datum/shuttle_template + + //* Basics + /// unique ID - use snake_case, must be unique & stable, including across rounds. + /// this means hardcoded ones shouldn't be changed willy-nilly. + var/id + + //* Identity + /// Full name + var/name + /// Full description + var/desc + /// lore fluff + var/fluff + + //* File + /// absolute path to file + var/absolute_path + /// relative path to file from current directory + var/relative_path + + //* Functionality + /// our shuttle typepath + /// + /// * yeah uh you probably shouldn't mess with this unless you know what you're doing + var/shuttle_type = /datum/shuttle + /// our descriptor, used for cross-interaction with other systems + /// this should not be a cached typepath, as opposed to a directly made typepath + /// or an instance. + /// + /// * because we intentionally don't cache typepaths, anonymous typepaths are allowed **and encouraged**. + /// + /// typepaths will be initialized. + /// instances will be cloned. + var/datum/shuttle_descriptor/descriptor = /datum/shuttle_descriptor + + //* .dmm + /// should we keep parsed map once first loaded? + var/cache_parsed_map = FALSE + /// our parsed map + var/datum/dmm_parsed/parsed_map + /// direction the shuttle is facing, in the map + /// please try to map shuttles in facing north. + var/facing_dir = NORTH + +/datum/shuttle_template/New(map_resource, use_dir) + if(map_resource) + absolute_path = map_resource + facing_dir = use_dir || NORTH + else + if(relative_path && !absolute_path) + var/our_file = __FILE__ + var/our_directory = copytext_char(our_file, 1, findlasttext_char(our_file, "/")) + absolute_path = "[our_directory]/[relative_path]" + + if(cache_parsed_map) + parsed_map = new(get_file()) + +/datum/shuttle_template/proc/get_file() + return isfile(absolute_path)? absolute_path : file(absolute_path) + +/** + * Do not directly use. Use create_shuttle() on SSshuttles! + * This will not automatically register the shuttle with the subsystem. + */ +/datum/shuttle_template/proc/instance(list/datum/map_injection/map_injections) + RETURN_TYPE(/datum/shuttle) + + var/datum/dmm_parsed/parsed_map = src.parsed_map + if(isnull(parsed_map)) + parsed_map = new(get_file()) + if(cache_parsed_map) + src.parsed_map = parsed_map + + var/datum/shuttle/instance = new shuttle_type + var/width = parsed_map.width + var/height = parsed_map.height + + // make reservation + var/datum/turf_reservation/reservation = SSmapping.request_block_reservation( + width + 2, + height + 2, + /datum/turf_reservation, + ) + + // create context + var/datum/dmm_context/context = create_dmm_context() + context.mangling_id = generate_mangling_id() + for(var/datum/map_injection/injection as anything in map_injections) + context.register_injection(injection) + + // load into reservation + var/datum/dmm_context/loaded_context = parsed_map.load( + reservation.bottom_left_coords[1] + 1, + reservation.bottom_left_coords[2] + 1, + reservation.bottom_left_coords[3], + context = context, + ) + var/list/loaded_bounds = loaded_context.loaded_bounds + + // set descriptor + instance.descriptor = instance_descriptor() + + // let shuttle do black magic first + // instance.before_bounds_init(reservation, src) + + // init the bounds + SSatoms.init_map_bounds(loaded_bounds) + + // let shuttle do post-init things + // instance.after_bounds_init(reservation, src) + + // set vars on shuttle + instance.template_id = id + + return instance + +/datum/shuttle_template/proc/instance_descriptor() + if(istype(descriptor)) + return descriptor.clone() + else if(IS_ANONYMOUS_TYPEPATH(descriptor)) + return new descriptor + else if(ispath(descriptor, /datum/shuttle_descriptor)) + return new descriptor + CRASH("what? [descriptor] ([REF(descriptor)])") + +/datum/shuttle_template/proc/generate_mangling_id() + var/static/notch = 0 + if(notch >= SHORT_REAL_LIMIT) + stack_trace("how the hell are we at this number?") + return "shuttle-[++notch]-[SSmapping.round_global_descriptor]" + +/datum/map_template/shuttle + abstract_type = /datum/map_template/shuttle diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi index 0dca1a9633c..6a7bac7c733 100644 Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ diff --git a/icons/modules/shuttles/bounding_3x3.dmi b/icons/modules/shuttles/bounding_3x3.dmi new file mode 100644 index 00000000000..296d644357b Binary files /dev/null and b/icons/modules/shuttles/bounding_3x3.dmi differ diff --git a/icons/modules/shuttles/effects/shuttle_landing.dmi b/icons/modules/shuttles/effects/shuttle_landing.dmi new file mode 100644 index 00000000000..550a3bb1e94 Binary files /dev/null and b/icons/modules/shuttles/effects/shuttle_landing.dmi differ diff --git a/icons/modules/shuttles/shuttle_anchor.dmi b/icons/modules/shuttles/shuttle_anchor.dmi new file mode 100644 index 00000000000..c226c9f8ac7 Binary files /dev/null and b/icons/modules/shuttles/shuttle_anchor.dmi differ diff --git a/icons/modules/shuttles/shuttle_anchor_2x2.dmi b/icons/modules/shuttles/shuttle_anchor_2x2.dmi new file mode 100644 index 00000000000..a35b6a96c84 Binary files /dev/null and b/icons/modules/shuttles/shuttle_anchor_2x2.dmi differ diff --git a/icons/modules/shuttles/shuttle_anchor_3x3.dmi b/icons/modules/shuttles/shuttle_anchor_3x3.dmi new file mode 100644 index 00000000000..827282d03f3 Binary files /dev/null and b/icons/modules/shuttles/shuttle_anchor_3x3.dmi differ diff --git a/maps/shuttles/README.md b/maps/shuttles/README.md new file mode 100644 index 00000000000..07c580774f8 --- /dev/null +++ b/maps/shuttles/README.md @@ -0,0 +1,33 @@ +# Shuttles + +Shuttle maps & datum defs go in here, as well as their corrosponding code, but not their docks. + +Shuttles may be re-instanced multiple times unless specified otherwise. + +## Bounding Boxes + +Shuttles have: + +- A basic square bounding box used for bounds checks +- Their actual /area bounding box + +The /area's in them that aren't `world.area` are used for the square bounding box allocation, but only the turfs in those said areas will move with the shuttle. + +There is currently, as of December 2023, no way to expand the areas in game without admin intervention. + +## Factions + +Organize as an exmaple like this; + +`maps/shuttles/factions/corporations/nanotrasen/*` +`maps/shuttles/factions/orion/tristar/*` +`maps/shuttles/generic/civillian/*` +`maps/shuttles/generic/outlaw/*` + +So on, so forth. + +Basically, just like the `code/game/content/*` and `icons/content/*` folders. + +# todo + +i'm kind of silly, we should finish the readme later ~silicons diff --git a/maps/shuttles/factions/corporations/nanotrasen/drone_prototype.dm b/maps/shuttles/factions/corporations/nanotrasen/drone_prototype.dm new file mode 100644 index 00000000000..13bc8f1f3c7 --- /dev/null +++ b/maps/shuttles/factions/corporations/nanotrasen/drone_prototype.dm @@ -0,0 +1,17 @@ +/datum/shuttle_template/nanotrasen/drone/prototype + name = "NT-S V1 Sensor Drone" + desc = "Nanotrasen's V1 Prototype Sensor Drone intended for unmanned sector scans in the depths of space. Not habitable." + fluff = "The rather blandly named V1 sensor drone. A prototype design, it is an unmanned craft used \ + for frontier exploration. Definitely not safe for life. As an upside, it runs on ion propulsion that \ + doesn't need to be refuelled for weeks on end." // v1 from ultrakill + id = "nt-drone-v1" + relative_path = "drone_prototype.dmm" + + descriptor = /datum/shuttle_descriptor{ + mass = 5; + } + +// todo: finish map + +/area/shuttle/nanotrasen/drone_prototype + name = "V1 Sensor Drone" diff --git a/maps/shuttles/factions/corporations/nanotrasen/drone_prototype.dmm b/maps/shuttles/factions/corporations/nanotrasen/drone_prototype.dmm new file mode 100644 index 00000000000..eb8a58ae1c4 --- /dev/null +++ b/maps/shuttles/factions/corporations/nanotrasen/drone_prototype.dmm @@ -0,0 +1,412 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"a" = ( +/turf/space/basic, +/area/space) +"c" = ( +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/drone_prototype) +"d" = ( +/obj/structure/handrail{ + dir = 4 + }, +/obj/structure/cable, +/obj/machinery/power/terminal{ + dir = 4 + }, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/drone_prototype) +"e" = ( +/obj/structure/handrail{ + dir = 8 + }, +/obj/structure/cable{ + icon_state = "2-8" + }, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/drone_prototype) +"g" = ( +/obj/effect/floor_decal/industrial/warning/full, +/obj/structure/cable{ + icon_state = "0-2" + }, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/drone_prototype) +"h" = ( +/obj/structure/handrail{ + dir = 8 + }, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/drone_prototype) +"i" = ( +/turf/simulated/shuttle/wall/voidcraft, +/area/shuttle/nanotrasen/drone_prototype) +"j" = ( +/obj/machinery/shipsensors, +/obj/effect/floor_decal/industrial/warning/full, +/turf/simulated/floor/plating/outdoors, +/area/shuttle/nanotrasen/drone_prototype) +"k" = ( +/obj/structure/handrail{ + dir = 4 + }, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/drone_prototype) +"l" = ( +/obj/effect/floor_decal/industrial/warning/full, +/obj/machinery/power/apc/south_mount, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/drone_prototype) +"q" = ( +/turf/simulated/wall/rshull, +/area/shuttle/nanotrasen/drone_prototype) +"s" = ( +/obj/effect/floor_decal/industrial/warning/full, +/obj/structure/cable{ + icon_state = "0-4" + }, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/drone_prototype) +"t" = ( +/obj/structure/railing, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/drone_prototype) +"w" = ( +/obj/effect/floor_decal/industrial/warning/full, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/drone_prototype) +"B" = ( +/obj/spawner/window/low_wall/reinforced/full, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/drone_prototype) +"E" = ( +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/drone_prototype) +"I" = ( +/obj/effect/floor_decal/industrial/warning/full, +/obj/structure/cable{ + icon_state = "4-8" + }, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/drone_prototype) +"L" = ( +/obj/structure/table/rack/shelf, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/drone_prototype) +"M" = ( +/obj/machinery/power/terminal{ + dir = 1 + }, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/drone_prototype) +"N" = ( +/obj/structure/railing{ + dir = 1 + }, +/obj/structure/cable{ + icon_state = "1-8" + }, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/drone_prototype) +"P" = ( +/obj/machinery/door/airlock/external/glass, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/drone_prototype) +"Q" = ( +/obj/effect/floor_decal/industrial/warning/full, +/turf/space/basic, +/area/shuttle/nanotrasen/drone_prototype) + +(1,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(2,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(3,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(4,1,1) = {" +a +a +a +a +a +a +a +a +Q +Q +Q +a +a +a +a +a +"} +(5,1,1) = {" +a +a +a +a +a +a +j +q +B +B +q +a +a +a +a +a +"} +(6,1,1) = {" +a +a +a +a +a +q +B +q +w +w +w +q +w +a +a +a +"} +(7,1,1) = {" +a +a +a +a +q +L +t +k +h +E +E +q +w +a +a +a +"} +(8,1,1) = {" +a +a +a +a +B +w +E +l +i +s +M +P +a +a +a +a +"} +(9,1,1) = {" +a +a +a +a +B +w +E +c +i +I +E +P +a +a +a +a +"} +(10,1,1) = {" +a +a +a +a +q +L +t +e +d +c +E +q +w +a +a +a +"} +(11,1,1) = {" +a +a +a +a +a +q +B +q +g +N +E +q +w +a +a +a +"} +(12,1,1) = {" +a +a +a +a +a +a +Q +q +B +B +q +a +a +a +a +a +"} +(13,1,1) = {" +a +a +a +a +a +a +a +a +Q +Q +Q +a +a +a +a +a +"} +(14,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(15,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} +(16,1,1) = {" +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +a +"} diff --git a/maps/shuttles/factions/corporations/nanotrasen/sci_vector.dm b/maps/shuttles/factions/corporations/nanotrasen/sci_vector.dm new file mode 100644 index 00000000000..e710836faff --- /dev/null +++ b/maps/shuttles/factions/corporations/nanotrasen/sci_vector.dm @@ -0,0 +1,34 @@ +/datum/shuttle_template/nanotrasen/science/vector + name = "NT-S Vector" + desc = "A research vessel built for medium-range archeology and analysis missions." + desc = "A newer design in Nanotrasen's lineup of deep-space shuttles, the Vector was built in-house by \ + the Research Division. While lacking most of the luxuries and heavy tooling of other shuttles, it does \ + contain a suite of astronavigational utilities." + id = "nt-vector" + relative_path = "sci_vector.dmm" + + descriptor = /datum/shuttle_descriptor{ + mass = 25; + } + +// todo: finish map + +/area/shuttle/nanotrasen/sci_vector + +/area/shuttle/nanotrasen/sci_vector/engineering + name = "NT-S Vector - Engineering Compartment" + +/area/shuttle/nanotrasen/sci_vector/service + name = "NT-S Vector - Service Compartment" + +/area/shuttle/nanotrasen/sci_vector/cockpit + name = "NT-S Vector - Cockpit" + +/area/shuttle/nanotrasen/sci_vector/crew + name = "NT-S Vector - Crew Compartment" + +/area/shuttle/nanotrasen/sci_vector/excursion + name = "NT-S Vector - Excursion Compartment" + +/area/shuttle/nanotrasen/sci_vector/airlock + name = "NT-S Vector - Airlock" diff --git a/maps/shuttles/factions/corporations/nanotrasen/sci_vector.dmm b/maps/shuttles/factions/corporations/nanotrasen/sci_vector.dmm new file mode 100644 index 00000000000..00050e12721 --- /dev/null +++ b/maps/shuttles/factions/corporations/nanotrasen/sci_vector.dmm @@ -0,0 +1,1233 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"aA" = ( +/obj/machinery/door/blast/regular, +/obj/structure/atmospheric_retention_field, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/service) +"aU" = ( +/obj/structure/handrail, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/service) +"aZ" = ( +/obj/structure/handrail, +/turf/space/basic, +/area/shuttle/nanotrasen/sci_vector/excursion) +"bF" = ( +/obj/machinery/power/smes, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/engineering) +"ch" = ( +/obj/machinery/atmospherics/pipe/tank{ + dir = 4 + }, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/engineering) +"cv" = ( +/obj/effect/decal/warning_stripes, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/engineering) +"cW" = ( +/obj/structure/bed/chair/bay/comfy{ + dir = 8 + }, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/excursion) +"dl" = ( +/obj/structure/handrail{ + dir = 8 + }, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/excursion) +"du" = ( +/obj/machinery/door/airlock/glass/research, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/excursion) +"dw" = ( +/obj/machinery/power/apc/east_mount, +/obj/machinery/recharge_station, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/cockpit) +"eh" = ( +/obj/machinery/telecomms/server, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/engineering) +"eu" = ( +/obj/structure/table/rack/shelf/steel, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/crew) +"fc" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/machinery/computer/shuttle_control{ + dir = 4 + }, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/cockpit) +"fX" = ( +/turf/simulated/wall/r_wall/prepainted/science, +/area/shuttle/nanotrasen/sci_vector/excursion) +"fY" = ( +/obj/structure/bed/chair/bay/comfy, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/crew) +"hA" = ( +/obj/effect/decal/warning_stripes, +/obj/effect/decal/warning_stripes, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/service) +"jw" = ( +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/service) +"kn" = ( +/obj/spawner/window/reinforced/full, +/obj/spawner/window/reinforced/full, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/excursion) +"kR" = ( +/obj/effect/decal/warning_stripes, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/service) +"lE" = ( +/obj/machinery/atmospherics/component/unary/engine/bigger, +/turf/space/basic, +/area/shuttle/nanotrasen/sci_vector/service) +"mY" = ( +/obj/structure/closet/secure_closet/engineering_welding, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/excursion) +"oj" = ( +/obj/structure/closet/secure_closet/xenoarchaeologist, +/obj/machinery/power/apc/east_mount, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/excursion) +"oy" = ( +/obj/spawner/window/reinforced/full, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/crew) +"oG" = ( +/turf/space/basic, +/area/shuttle/nanotrasen/sci_vector/service) +"pj" = ( +/obj/structure/closet/secure_closet/xenoarchaeologist, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/excursion) +"ps" = ( +/obj/machinery/door/airlock/external/glass, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/airlock) +"pu" = ( +/obj/structure/handrail{ + dir = 1 + }, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/engineering) +"qA" = ( +/obj/machinery/suit_storage_unit/exploration, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/cockpit) +"rb" = ( +/obj/structure/bed/chair/bay/comfy{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/crew) +"rw" = ( +/obj/structure/window/reinforced, +/obj/machinery/suit_storage_unit/exploration, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/airlock) +"rQ" = ( +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/airlock) +"sl" = ( +/obj/structure/table/rack/shelf, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/crew) +"tF" = ( +/obj/machinery/power/apc/north_mount, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/airlock) +"uA" = ( +/obj/machinery/atmospherics/pipe/tank/air{ + dir = 8 + }, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/engineering) +"vU" = ( +/obj/structure/bed/chair/bay/comfy{ + dir = 8 + }, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/cockpit) +"wr" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/table/rack/shelf, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/cockpit) +"xj" = ( +/obj/machinery/artifact_scanpad, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/crew) +"xr" = ( +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/cockpit) +"xv" = ( +/obj/machinery/computer/rdconsole{ + dir = 4 + }, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/excursion) +"xK" = ( +/obj/machinery/r_n_d/server, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/engineering) +"xO" = ( +/obj/effect/decal/warning_stripes, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/airlock) +"yR" = ( +/turf/simulated/wall/r_wall/prepainted/science, +/area/shuttle/nanotrasen/sci_vector/crew) +"zu" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/effect/decal/warning_stripes, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/service) +"zV" = ( +/obj/structure/handrail{ + dir = 1 + }, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/airlock) +"Ce" = ( +/obj/structure/handrail{ + dir = 4 + }, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/airlock) +"CI" = ( +/obj/machinery/suit_storage_unit/exploration, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/airlock) +"CP" = ( +/obj/machinery/computer/nanite_chamber{ + dir = 4 + }, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/service) +"DK" = ( +/obj/structure/bed/chair/bay/comfy{ + dir = 1 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/crew) +"DR" = ( +/obj/structure/dispenser/oxygen{ + dir = 8 + }, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/excursion) +"DS" = ( +/obj/structure/handrail, +/obj/machinery/power/apc/north_mount, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/service) +"EC" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/machinery/portable_atmospherics/canister/oxygen, +/turf/simulated/floor/plating, +/area/shuttle/nanotrasen/sci_vector/service) +"EG" = ( +/obj/structure/window/reinforced{ + dir = 1 + }, +/obj/structure/window/reinforced, +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/machinery/door/window{ + dir = 8 + }, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/engineering) +"EQ" = ( +/obj/machinery/mech_recharger, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/service) +"EX" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/effect/decal/warning_stripes, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/service) +"Fx" = ( +/obj/spawner/window/reinforced/full, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/cockpit) +"Gt" = ( +/obj/effect/decal/warning_stripes, +/turf/space/basic, +/area/shuttle/nanotrasen/sci_vector/engineering) +"GQ" = ( +/obj/machinery/artifact_harvester, +/obj/structure/window/reinforced{ + dir = 4 + }, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/crew) +"Hs" = ( +/obj/machinery/nanite_chamber, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/service) +"HY" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/table/reinforced, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/cockpit) +"Ib" = ( +/obj/machinery/door/airlock/glass/research, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/cockpit) +"Jr" = ( +/obj/machinery/exonet_node, +/obj/machinery/power/apc/west_mount, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/engineering) +"KS" = ( +/obj/machinery/atmospherics/pipe/tank/phoron{ + dir = 8 + }, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/service) +"Lv" = ( +/obj/effect/decal/warning_stripes, +/turf/space/basic, +/area/shuttle/nanotrasen/sci_vector/service) +"LZ" = ( +/obj/spawner/window/reinforced/full, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/excursion) +"Mz" = ( +/turf/space/basic, +/area/space) +"Ps" = ( +/turf/simulated/wall/r_wall/prepainted/science, +/area/shuttle/nanotrasen/sci_vector/service) +"Pt" = ( +/obj/structure/handrail, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/airlock) +"PP" = ( +/obj/structure/handrail{ + dir = 1 + }, +/turf/space/basic, +/area/shuttle/nanotrasen/sci_vector/service) +"Qc" = ( +/obj/structure/table/reinforced, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/crew) +"QF" = ( +/obj/machinery/r_n_d/circuit_imprinter, +/obj/structure/window/reinforced, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/excursion) +"Rk" = ( +/obj/machinery/atmospherics/component/binary/pump/fuel{ + dir = 4 + }, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/service) +"RH" = ( +/obj/structure/closet/crate/freezer/rations, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/crew) +"RR" = ( +/obj/machinery/artifact_analyser, +/obj/structure/window/reinforced{ + dir = 8 + }, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/crew) +"RX" = ( +/obj/machinery/r_n_d/protolathe, +/obj/structure/window/reinforced{ + dir = 1 + }, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/excursion) +"Su" = ( +/turf/simulated/wall/r_wall/prepainted/science, +/area/shuttle/nanotrasen/sci_vector/cockpit) +"Ti" = ( +/turf/simulated/wall/r_wall/prepainted/science, +/area/shuttle/nanotrasen/sci_vector/engineering) +"Vu" = ( +/obj/effect/decal/warning_stripes, +/turf/space/basic, +/area/shuttle/nanotrasen/sci_vector/excursion) +"Wl" = ( +/obj/machinery/door/airlock/external/glass, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/engineering) +"WQ" = ( +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/crew) +"Xm" = ( +/obj/machinery/door/airlock/glass/research, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/service) +"Yh" = ( +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/excursion) +"Yj" = ( +/obj/machinery/door/airlock/glass/research, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/engineering) +"Yl" = ( +/obj/structure/window/reinforced{ + dir = 4 + }, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/machinery/portable_atmospherics/canister/air, +/turf/simulated/floor/plating, +/area/shuttle/nanotrasen/sci_vector/service) +"YQ" = ( +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/engineering) +"Zt" = ( +/obj/spawner/window/reinforced/full, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/service) +"ZP" = ( +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/effect/decal/warning_stripes, +/obj/machinery/atmospherics/component/binary/pump/fuel{ + dir = 8 + }, +/turf/simulated/floor/plating/indoors, +/area/shuttle/nanotrasen/sci_vector/service) + +(1,1,1) = {" +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +"} +(2,1,1) = {" +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +"} +(3,1,1) = {" +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +"} +(4,1,1) = {" +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +"} +(5,1,1) = {" +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +"} +(6,1,1) = {" +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Vu +Vu +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Lv +Lv +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +"} +(7,1,1) = {" +Mz +Mz +Mz +Mz +Mz +Mz +Mz +yR +oy +fX +fX +LZ +LZ +kn +fX +fX +aZ +Mz +Mz +PP +Ps +Ps +Ps +lE +Mz +Mz +Mz +Mz +Mz +Mz +"} +(8,1,1) = {" +Mz +Mz +Mz +Mz +Mz +Mz +oy +Qc +sl +fX +mY +RX +xv +QF +DR +pj +fX +ps +ps +Ps +Hs +CP +Ps +oG +Mz +Mz +Mz +Mz +Mz +Mz +"} +(9,1,1) = {" +Mz +Mz +Mz +Mz +Mz +yR +Qc +WQ +WQ +du +Yh +Yh +cW +Yh +Yh +pj +LZ +Pt +zV +Ps +jw +hA +kR +Ps +lE +Mz +Mz +Mz +Mz +Mz +"} +(10,1,1) = {" +Mz +Mz +Mz +Mz +Mz +oy +fY +WQ +DK +LZ +Yh +Yh +Yh +dl +Yh +oj +LZ +Pt +zV +Ps +jw +zu +zu +Ps +oG +Mz +Mz +Mz +Mz +Mz +"} +(11,1,1) = {" +Mz +Mz +Mz +Mz +Mz +oy +fY +WQ +rb +Su +Fx +Fx +Fx +Su +du +fX +fX +ps +ps +Ps +aU +EQ +EQ +aA +Mz +Mz +Mz +Mz +Mz +Mz +"} +(12,1,1) = {" +Mz +Mz +Mz +Mz +Mz +yR +RR +WQ +RH +Su +HY +fc +wr +Su +tF +Ce +Ce +rQ +rQ +Xm +jw +EQ +EQ +aA +Mz +Mz +Mz +Mz +Mz +Mz +"} +(13,1,1) = {" +Mz +Mz +Mz +Mz +Mz +oy +xj +WQ +WQ +Fx +xr +vU +xr +Ib +rQ +rQ +rQ +rQ +xO +Zt +jw +EC +Yl +Ps +Mz +Mz +Mz +Mz +Mz +Mz +"} +(14,1,1) = {" +Mz +Mz +Mz +Mz +Mz +yR +GQ +WQ +eu +Su +qA +xr +dw +Su +CI +CI +rw +rQ +rQ +Xm +jw +EQ +EQ +aA +Mz +Mz +Mz +Mz +Mz +Mz +"} +(15,1,1) = {" +Mz +Mz +Mz +Mz +Mz +oy +fY +WQ +DK +Su +Su +Ib +Su +Su +Ti +Ti +Ti +Yj +Ti +Ps +DS +EQ +EQ +aA +Mz +Mz +Mz +Mz +Mz +Mz +"} +(16,1,1) = {" +Mz +Mz +Mz +Mz +Mz +oy +fY +WQ +rb +Ti +ch +YQ +YQ +Ti +Jr +eh +bF +YQ +xK +Ps +Rk +ZP +EX +Ps +lE +Mz +Mz +Mz +Mz +Mz +"} +(17,1,1) = {" +Mz +Mz +Mz +Mz +Mz +yR +Qc +WQ +WQ +Yj +YQ +YQ +YQ +Yj +YQ +YQ +YQ +YQ +YQ +Xm +jw +kR +kR +Ps +oG +Mz +Mz +Mz +Mz +Mz +"} +(18,1,1) = {" +Mz +Mz +Mz +Mz +Mz +Mz +oy +Qc +sl +Ti +uA +Ti +Wl +Ti +bF +EG +cv +cv +cv +Ps +KS +KS +Ps +lE +Mz +Mz +Mz +Mz +Mz +Mz +"} +(19,1,1) = {" +Mz +Mz +Mz +Mz +Mz +Mz +Mz +yR +oy +Ti +Ti +Ti +pu +Ti +Ti +Ti +Ti +Ti +Ti +Ps +Ps +Ps +Ps +oG +Mz +Mz +Mz +Mz +Mz +Mz +"} +(20,1,1) = {" +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Gt +Gt +Ti +Wl +Ti +Mz +Mz +Mz +Mz +Mz +Mz +Lv +Lv +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +"} +(21,1,1) = {" +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +"} +(22,1,1) = {" +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +"} +(23,1,1) = {" +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +"} +(24,1,1) = {" +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +"} +(25,1,1) = {" +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +Mz +"}