diff --git a/code/__DEFINES/shuttle.dm b/code/__DEFINES/shuttle.dm new file mode 100644 index 00000000000..22af9a38670 --- /dev/null +++ b/code/__DEFINES/shuttle.dm @@ -0,0 +1,16 @@ +//Docking error flags +#define DOCKING_SUCCESS 0 +#define DOCKING_BLOCKED (1<<0) +#define DOCKING_IMMOBILIZED (1<<1) +#define DOCKING_AREA_EMPTY (1<<2) +#define DOCKING_NULL_DESTINATION (1<<3) +#define DOCKING_NULL_SOURCE (1<<4) + +//Rotation params +#define ROTATE_DIR 1 +#define ROTATE_SMOOTH 2 +#define ROTATE_OFFSET 4 + +#define SHUTTLE_DOCKER_LANDING_CLEAR 1 +#define SHUTTLE_DOCKER_BLOCKED_BY_HIDDEN_PORT 2 +#define SHUTTLE_DOCKER_BLOCKED 3 \ No newline at end of file diff --git a/code/__HELPERS/maths.dm b/code/__HELPERS/maths.dm index c0c22872a32..ec9fcb5fb31 100644 --- a/code/__HELPERS/maths.dm +++ b/code/__HELPERS/maths.dm @@ -120,4 +120,24 @@ var/gaussian_next /proc/round_down(num) if(round(num) != num) return round(num--) - else return num \ No newline at end of file + else return num + +// Returns a list where [1] is all x values and [2] is all y values that overlap between the given pair of rectangles +/proc/get_overlap(x1, y1, x2, y2, x3, y3, x4, y4) + var/list/region_x1 = list() + var/list/region_y1 = list() + var/list/region_x2 = list() + var/list/region_y2 = list() + + // These loops create loops filled with x/y values that the boundaries inhabit + // ex: list(5, 6, 7, 8, 9) + for(var/i in min(x1, x2) to max(x1, x2)) + region_x1["[i]"] = TRUE + for(var/i in min(y1, y2) to max(y1, y2)) + region_y1["[i]"] = TRUE + for(var/i in min(x3, x4) to max(x3, x4)) + region_x2["[i]"] = TRUE + for(var/i in min(y3, y4) to max(y3, y4)) + region_y2["[i]"] = TRUE + + return list(region_x1 & region_x2, region_y1 & region_y2) \ No newline at end of file diff --git a/code/_globalvars/lists/objects.dm b/code/_globalvars/lists/objects.dm index acb86875a5a..3256f6375e9 100644 --- a/code/_globalvars/lists/objects.dm +++ b/code/_globalvars/lists/objects.dm @@ -14,6 +14,7 @@ GLOBAL_LIST_INIT(janitorial_equipment, list()) //list of janitorial equipment GLOBAL_LIST_INIT(crafting_recipes, list()) //list of all crafting recipes GLOBAL_LIST_INIT(prisoncomputer_list, list()) GLOBAL_LIST_INIT(cell_logs, list()) +GLOBAL_LIST_INIT(navigation_computers, list()) GLOBAL_LIST_INIT(all_areas, list()) GLOBAL_LIST_INIT(machines, list()) diff --git a/code/controllers/subsystem/shuttles.dm b/code/controllers/subsystem/shuttles.dm index 64ae30f2952..30021df4fb1 100644 --- a/code/controllers/subsystem/shuttles.dm +++ b/code/controllers/subsystem/shuttles.dm @@ -39,6 +39,8 @@ SUBSYSTEM_DEF(shuttle) var/list/supply_packs = list() var/datum/round_event/shuttle_loan/shuttle_loan var/sold_atoms = "" + var/list/hidden_shuttle_turfs = list() //all turfs hidden from navigation computers associated with a list containing the image hiding them and the type of the turf they are pretending to be + var/list/hidden_shuttle_turf_images = list() //only the images from the above list /datum/controller/subsystem/shuttle/Initialize(start_timeofday) ordernum = rand(1,9000) @@ -49,7 +51,7 @@ SUBSYSTEM_DEF(shuttle) WARNING("No /obj/docking_port/mobile/emergency/backup placed on the map!") if(!supply) WARNING("No /obj/docking_port/mobile/supply placed on the map!") - + initial_load() for(var/typepath in subtypesof(/datum/supply_packs)) @@ -259,4 +261,54 @@ SUBSYSTEM_DEF(shuttle) return O +/datum/controller/subsystem/shuttle/proc/get_dock_overlap(x0, y0, x1, y1, z) + . = list() + var/list/stationary_cache = stationary + for(var/i in 1 to stationary_cache.len) + var/obj/docking_port/port = stationary_cache[i] + if(!port || port.z != z) + continue + var/list/bounds = port.return_coords() + var/list/overlap = get_overlap(x0, y0, x1, y1, bounds[1], bounds[2], bounds[3], bounds[4]) + var/list/xs = overlap[1] + var/list/ys = overlap[2] + if(xs.len && ys.len) + .[port] = overlap + +/datum/controller/subsystem/shuttle/proc/update_hidden_docking_ports(list/remove_turfs, list/add_turfs) + var/list/remove_images = list() + var/list/add_images = list() + + if(remove_turfs) + for(var/T in remove_turfs) + var/list/L = hidden_shuttle_turfs[T] + if(L) + remove_images += L[1] + hidden_shuttle_turfs -= remove_turfs + + if(add_turfs) + for(var/V in add_turfs) + var/turf/T = V + var/image/I + if(remove_images.len) + //we can just reuse any images we are about to delete instead of making new ones + I = remove_images[1] + remove_images.Cut(1, 2) + I.loc = T + else + I = image(loc = T) + add_images += I + I.appearance = T.appearance + I.override = TRUE + hidden_shuttle_turfs[T] = list(I, T.type) + + hidden_shuttle_turf_images -= remove_images + hidden_shuttle_turf_images += add_images + + for(var/V in GLOB.navigation_computers) + var/obj/machinery/computer/camera_advanced/shuttle_docker/C = V + C.update_hidden_docking_ports(remove_images, add_images) + + QDEL_LIST(remove_images) + #undef CALL_SHUTTLE_REASON_LENGTH \ No newline at end of file diff --git a/code/game/machinery/computer/computer.dm b/code/game/machinery/computer/computer.dm index 80e56f0ca82..67f1527b199 100644 --- a/code/game/machinery/computer/computer.dm +++ b/code/game/machinery/computer/computer.dm @@ -35,25 +35,24 @@ /obj/machinery/computer/ex_act(severity) - switch(severity) - if(1.0) - qdel(src) - return - if(2.0) - if(prob(25)) + if(!(resistance_flags & INDESTRUCTIBLE)) + switch(severity) + if(1.0) qdel(src) return - if(prob(50)) - for(var/x in verbs) - verbs -= x - set_broken() - if(3.0) - if(prob(25)) - for(var/x in verbs) - verbs -= x - set_broken() - else - return + if(2.0) + if(prob(25)) + qdel(src) + return + if(prob(50)) + for(var/x in verbs) + verbs -= x + set_broken() + if(3.0) + if(prob(25)) + for(var/x in verbs) + verbs -= x + set_broken() /obj/machinery/computer/bullet_act(var/obj/item/projectile/Proj) if(prob(Proj.damage)) @@ -97,8 +96,9 @@ set_light(light_range_on, light_power_on) /obj/machinery/computer/proc/set_broken() - stat |= BROKEN - update_icon() + if(!(resistance_flags & INDESTRUCTIBLE)) + stat |= BROKEN + update_icon() /obj/machinery/computer/proc/decode(text) // Adds line breaks @@ -114,7 +114,7 @@ return ..() /obj/machinery/computer/attackby(obj/I, mob/user, params) - if(istype(I, /obj/item/screwdriver) && circuit) + if(istype(I, /obj/item/screwdriver) && circuit && !(resistance_flags & INDESTRUCTIBLE)) var/obj/item/screwdriver/S = I playsound(src.loc, S.usesound, 50, 1) if(do_after(user, 20 * S.toolspeed, target = src)) diff --git a/code/modules/shuttle/navigation_computer.dm b/code/modules/shuttle/navigation_computer.dm new file mode 100644 index 00000000000..8b5c73e32cb --- /dev/null +++ b/code/modules/shuttle/navigation_computer.dm @@ -0,0 +1,348 @@ +/obj/machinery/computer/camera_advanced/shuttle_docker + name = "navigation computer" + desc = "Used to designate a precise transit location for a spacecraft." + jump_action = null + var/datum/action/innate/shuttledocker_rotate/rotate_action = new + var/datum/action/innate/shuttledocker_place/place_action = new + var/shuttleId = "" + var/shuttlePortId = "" + var/shuttlePortName = "custom location" + var/list/jumpto_ports = list() //list of ports to jump to + var/access_station = TRUE //can we park near the station? + var/access_sats = TRUE //can we park near telecomms/construction site? + var/access_mining = TRUE //can we park near the mining asteroid? + var/access_derelict = FALSE //can we explore the derelict zlevel? + var/obj/docking_port/stationary/my_port //the custom docking port placed by this console + var/obj/docking_port/mobile/shuttle_port //the mobile docking port of the connected shuttle + var/view_range = 7 + var/x_offset = 0 + var/y_offset = 0 + var/space_turfs_only = TRUE + var/see_hidden = FALSE + var/designate_time = 0 + var/turf/designating_target_loc + +/obj/machinery/computer/camera_advanced/shuttle_docker/Initialize() + . = ..() + GLOB.navigation_computers += src + if(access_station) + jumpto_ports += list("nav_z1" = 1) + if(access_sats) + jumpto_ports += list("nav_z3" = 1, "nav_z4" = 1) + if(access_mining) + jumpto_ports += list("nav_z5" = 1) + if(access_derelict) + jumpto_ports += list("nav_z6" = 1) + +/obj/machinery/computer/camera_advanced/shuttle_docker/Destroy() + . = ..() + GLOB.navigation_computers -= src + +/obj/machinery/computer/camera_advanced/shuttle_docker/attack_hand(mob/user) + if(!shuttle_port && !SSshuttle.getShuttle(shuttleId)) + to_chat(user,"Warning: Shuttle connection severed!") + return + return ..() + +/obj/machinery/computer/camera_advanced/shuttle_docker/GrantActions(mob/living/user) + if(jumpto_ports.len) + jump_action = new /datum/action/innate/camera_jump/shuttle_docker + ..() + /* //technically working but some icons are buggy as shit and either don't rotate or rotate wrong : + //namely shuttle walls, shuttle windows, shuttle engines and buckled mobs + if(rotate_action) + rotate_action.target = user + rotate_action.Grant(user) + actions += rotate_action + */ + if(place_action) + place_action.target = user + place_action.Grant(user) + actions += place_action + +/obj/machinery/computer/camera_advanced/shuttle_docker/CreateEye() + shuttle_port = SSshuttle.getShuttle(shuttleId) + if(QDELETED(shuttle_port)) + shuttle_port = null + return + + eyeobj = new /mob/camera/aiEye/remote/shuttle_docker(null, src) + var/mob/camera/aiEye/remote/shuttle_docker/the_eye = eyeobj + the_eye.setDir(shuttle_port.dir) + var/turf/origin = locate(shuttle_port.x + x_offset, shuttle_port.y + y_offset, shuttle_port.z) + for(var/V in shuttle_port.shuttle_areas) + var/area/A = V + for(var/turf/T in A) + if(T.z != origin.z) + continue + var/image/I = image('icons/effects/alphacolors.dmi', origin, "red") + var/x_off = T.x - origin.x + var/y_off = T.y - origin.y + I.loc = locate(origin.x + x_off, origin.y + y_off, origin.z) //we have to set this after creating the image because it might be null, and images created in nullspace are immutable. + I.layer = ABOVE_NORMAL_TURF_LAYER + I.plane = 0 + I.mouse_opacity = MOUSE_OPACITY_TRANSPARENT + the_eye.placement_images[I] = list(x_off, y_off) + +/obj/machinery/computer/camera_advanced/shuttle_docker/give_eye_control(mob/user) + ..() + if(!QDELETED(user) && user.client) + var/mob/camera/aiEye/remote/shuttle_docker/the_eye = eyeobj + var/list/to_add = list() + to_add += the_eye.placement_images + to_add += the_eye.placed_images + if(!see_hidden) + to_add += SSshuttle.hidden_shuttle_turf_images + + user.client.images += to_add + user.client.SetView(view_range) + +/obj/machinery/computer/camera_advanced/shuttle_docker/remove_eye_control(mob/living/user) + ..() + if(!QDELETED(user) && user.client) + var/mob/camera/aiEye/remote/shuttle_docker/the_eye = eyeobj + var/list/to_remove = list() + to_remove += the_eye.placement_images + to_remove += the_eye.placed_images + if(!see_hidden) + to_remove += SSshuttle.hidden_shuttle_turf_images + + user.client.images -= to_remove + user.client.SetView(7) + +/obj/machinery/computer/camera_advanced/shuttle_docker/proc/placeLandingSpot() + if(designating_target_loc || !current_user) + return + + var/mob/camera/aiEye/remote/shuttle_docker/the_eye = eyeobj + var/landing_clear = checkLandingSpot() + if(designate_time && (landing_clear != SHUTTLE_DOCKER_BLOCKED)) + to_chat(current_user, "Targeting transit location, please wait [DisplayTimeText(designate_time)]...") + designating_target_loc = the_eye.loc + var/wait_completed = do_after(current_user, designate_time, FALSE, designating_target_loc, TRUE, CALLBACK(src, /obj/machinery/computer/camera_advanced/shuttle_docker/proc/canDesignateTarget)) + designating_target_loc = null + if(!current_user) + return + if(!wait_completed) + to_chat(current_user, "Operation aborted.") + return + landing_clear = checkLandingSpot() + + if(landing_clear != SHUTTLE_DOCKER_LANDING_CLEAR) + switch(landing_clear) + if(SHUTTLE_DOCKER_BLOCKED) + to_chat(current_user, "Invalid transit location") + if(SHUTTLE_DOCKER_BLOCKED_BY_HIDDEN_PORT) + to_chat(current_user, "Unknown object detected in landing zone. Please designate another location.") + return + + if(!my_port) + my_port = new() + my_port.name = shuttlePortName + my_port.id = shuttlePortId + my_port.height = shuttle_port.height + my_port.width = shuttle_port.width + my_port.dheight = shuttle_port.dheight + my_port.dwidth = shuttle_port.dwidth + my_port.hidden = shuttle_port.hidden + my_port.register() + my_port.setDir(the_eye.dir) + my_port.forceMove(locate(eyeobj.x - x_offset, eyeobj.y - y_offset, eyeobj.z)) + if(current_user.client) + current_user.client.images -= the_eye.placed_images + + QDEL_LIST(the_eye.placed_images) + + for(var/V in the_eye.placement_images) + var/image/I = V + var/image/newI = image('icons/effects/alphacolors.dmi', the_eye.loc, "blue") + newI.loc = I.loc //It is highly unlikely that any landing spot including a null tile will get this far, but better safe than sorry. + newI.layer = ABOVE_OPEN_TURF_LAYER + newI.plane = 0 + newI.mouse_opacity = 0 + the_eye.placed_images += newI + + if(current_user.client) + current_user.client.images += the_eye.placed_images + to_chat(current_user, "Transit location designated") + return + +/obj/machinery/computer/camera_advanced/shuttle_docker/proc/canDesignateTarget() + if(!designating_target_loc || !current_user || (eyeobj.loc != designating_target_loc) || (stat & (NOPOWER|BROKEN)) ) + return FALSE + return TRUE + +/obj/machinery/computer/camera_advanced/shuttle_docker/proc/rotateLandingSpot() + var/mob/camera/aiEye/remote/shuttle_docker/the_eye = eyeobj + var/list/image_cache = the_eye.placement_images + the_eye.setDir(turn(the_eye.dir, -90)) + for(var/i in 1 to image_cache.len) + var/image/pic = image_cache[i] + var/list/coords = image_cache[pic] + var/Tmp = coords[1] + coords[1] = coords[2] + coords[2] = -Tmp + pic.loc = locate(the_eye.x + coords[1], the_eye.y + coords[2], the_eye.z) + var/Tmp = x_offset + x_offset = y_offset + y_offset = -Tmp + checkLandingSpot() + +/obj/machinery/computer/camera_advanced/shuttle_docker/proc/checkLandingSpot() + var/mob/camera/aiEye/remote/shuttle_docker/the_eye = eyeobj + var/turf/eyeturf = get_turf(the_eye) + if(!eyeturf) + return SHUTTLE_DOCKER_BLOCKED + + . = SHUTTLE_DOCKER_LANDING_CLEAR + var/list/bounds = shuttle_port.return_coords(the_eye.x - x_offset, the_eye.y - y_offset, the_eye.dir) + var/list/overlappers = SSshuttle.get_dock_overlap(bounds[1], bounds[2], bounds[3], bounds[4], the_eye.z) + var/list/image_cache = the_eye.placement_images + for(var/i in 1 to image_cache.len) + var/image/I = image_cache[i] + var/list/coords = image_cache[I] + var/turf/T = locate(eyeturf.x + coords[1], eyeturf.y + coords[2], eyeturf.z) + I.loc = T + switch(checkLandingTurf(T, overlappers)) + if(SHUTTLE_DOCKER_LANDING_CLEAR) + I.icon_state = "green" + if(SHUTTLE_DOCKER_BLOCKED_BY_HIDDEN_PORT) + I.icon_state = "green" + if(. == SHUTTLE_DOCKER_LANDING_CLEAR) + . = SHUTTLE_DOCKER_BLOCKED_BY_HIDDEN_PORT + else + I.icon_state = "red" + . = SHUTTLE_DOCKER_BLOCKED + +/obj/machinery/computer/camera_advanced/shuttle_docker/proc/checkLandingTurf(turf/T, list/overlappers) + // Too close to the map edge is never allowed + if(!T || T.x <= 10 || T.y <= 10 || T.x >= world.maxx - 10 || T.y >= world.maxy - 10) + return SHUTTLE_DOCKER_BLOCKED + // If it's one of our shuttle areas assume it's ok to be there + if(shuttle_port.shuttle_areas[T.loc]) + return SHUTTLE_DOCKER_LANDING_CLEAR + . = SHUTTLE_DOCKER_LANDING_CLEAR + // See if the turf is hidden from us + var/list/hidden_turf_info + if(!see_hidden) + hidden_turf_info = SSshuttle.hidden_shuttle_turfs[T] + if(hidden_turf_info) + . = SHUTTLE_DOCKER_BLOCKED_BY_HIDDEN_PORT + + if(space_turfs_only) + var/turf_type = hidden_turf_info ? hidden_turf_info[2] : T.type + if(!ispath(turf_type, /turf/space)) + return SHUTTLE_DOCKER_BLOCKED + + if(istype(T.loc.type, /area/syndicate_depot)) + return SHUTTLE_DOCKER_BLOCKED + + // Checking for overlapping dock boundaries + for(var/i in 1 to overlappers.len) + var/obj/docking_port/port = overlappers[i] + if(port == my_port || locate(port) in jumpto_ports) + continue + var/port_hidden = !see_hidden && port.hidden + var/list/overlap = overlappers[port] + var/list/xs = overlap[1] + var/list/ys = overlap[2] + if(xs["[T.x]"] && ys["[T.y]"]) + if(port_hidden) + . = SHUTTLE_DOCKER_BLOCKED_BY_HIDDEN_PORT + else + return SHUTTLE_DOCKER_BLOCKED + +/obj/machinery/computer/camera_advanced/shuttle_docker/proc/update_hidden_docking_ports(list/remove_images, list/add_images) + if(!see_hidden && current_user && current_user.client) + current_user.client.images -= remove_images + current_user.client.images += add_images + +/obj/machinery/computer/camera_advanced/shuttle_docker/proc/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE) + if(port && (shuttleId == initial(shuttleId) || override)) + shuttleId = port.id + shuttlePortId = "[port.id]_custom" + if(dock) + jumpto_ports[dock.id] = TRUE + +/mob/camera/aiEye/remote/shuttle_docker + visible_icon = FALSE + use_static = FALSE + simulated = FALSE + var/list/placement_images = list() + var/list/placed_images = list() + +/mob/camera/aiEye/remote/shuttle_docker/Initialize(mapload, obj/machinery/computer/camera_advanced/origin) + src.origin = origin + return ..() + +/mob/camera/aiEye/remote/shuttle_docker/setLoc(T) + ..() + var/obj/machinery/computer/camera_advanced/shuttle_docker/console = origin + console.checkLandingSpot() + +/mob/camera/aiEye/remote/shuttle_docker/update_remote_sight(mob/living/user) + user.sight = SEE_TURFS + //user.lighting_alpha = LIGHTING_PLANE_ALPHA_INVISIBLE + //user.sync_lighting_plane_alpha() + return TRUE + +/datum/action/innate/shuttledocker_rotate + name = "Rotate" + icon_icon = 'icons/mob/actions/actions_mecha.dmi' + button_icon_state = "mech_cycle_equip_off" + +/datum/action/innate/shuttledocker_rotate/Activate() + if(QDELETED(target) || !isliving(target)) + return + var/mob/living/C = target + var/mob/camera/aiEye/remote/remote_eye = C.remote_control + var/obj/machinery/computer/camera_advanced/shuttle_docker/origin = remote_eye.origin + origin.rotateLandingSpot() + +/datum/action/innate/shuttledocker_place + name = "Place" + icon_icon = 'icons/mob/actions/actions_mecha.dmi' + button_icon_state = "mech_zoom_off" + +/datum/action/innate/shuttledocker_place/Activate() + if(QDELETED(target) || !isliving(target)) + return + var/mob/living/C = target + var/mob/camera/aiEye/remote/remote_eye = C.remote_control + var/obj/machinery/computer/camera_advanced/shuttle_docker/origin = remote_eye.origin + origin.placeLandingSpot(target) + +/datum/action/innate/camera_jump/shuttle_docker + name = "Jump to Location" + button_icon_state = "camera_jump" + +/datum/action/innate/camera_jump/shuttle_docker/Activate() + if(QDELETED(target) || !isliving(target)) + return + var/mob/living/C = target + var/mob/camera/aiEye/remote/remote_eye = C.remote_control + var/obj/machinery/computer/camera_advanced/shuttle_docker/console = remote_eye.origin + + playsound(console, 'sound/machines/terminal_prompt_deny.ogg', 25, 0) + + var/list/L = list() + for(var/V in SSshuttle.stationary) + if(!V) + continue + var/obj/docking_port/stationary/S = V + if(console.jumpto_ports[S.id]) + L[S.name] = S + + playsound(console, 'sound/machines/terminal_prompt.ogg', 25, 0) + var/selected = input("Choose location to jump to", "Locations", null) as null|anything in L + if(QDELETED(src) || QDELETED(target) || !isliving(target)) + return + playsound(src, "terminal_type", 25, 0) + if(selected) + var/turf/T = get_turf(L[selected]) + if(T) + playsound(console, 'sound/machines/terminal_prompt_confirm.ogg', 25, 0) + remote_eye.setLoc(T) + to_chat(target, "Jumped to [selected]") + else + playsound(console, 'sound/machines/terminal_prompt_deny.ogg', 25, 0) \ No newline at end of file diff --git a/code/modules/shuttle/on_move.dm b/code/modules/shuttle/on_move.dm index 4a587ac1253..44edebdca50 100644 --- a/code/modules/shuttle/on_move.dm +++ b/code/modules/shuttle/on_move.dm @@ -57,19 +57,4 @@ /obj/machinery/door/airlock/postDock(obj/docking_port/stationary/S1) . = ..() if(!S1.lock_shuttle_doors && id_tag == "s_docking_airlock") - INVOKE_ASYNC(src, .proc/unlock) - -// Shuttle Rotation // -/atom/proc/shuttleRotate(rotation) - //rotate our direction - dir = angle2dir(rotation+dir2angle(dir)) - - //rotate the pixel offsets too. - if(pixel_x || pixel_y) - if(rotation < 0) - rotation += 360 - for(var/turntimes=rotation/90;turntimes>0;turntimes--) - var/oldPX = pixel_x - var/oldPY = pixel_y - pixel_x = oldPY - pixel_y = (oldPX*(-1)) + INVOKE_ASYNC(src, .proc/unlock) \ No newline at end of file diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index fe00b6b3611..75aea7725a3 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -24,6 +24,7 @@ var/timid = FALSE var/list/ripples = list() + var/hidden = FALSE //are we invisible to shuttle navigation computers? //these objects are indestructable /obj/docking_port/Destroy(force) @@ -76,6 +77,12 @@ _y + (-dwidth+width-1)*sin + (-dheight+height-1)*cos ) +//returns turfs within our projected rectangle in no particular order +/obj/docking_port/proc/return_turfs() + var/list/L = return_coords() + var/turf/T0 = locate(L[1], L[2], z) + var/turf/T1 = locate(L[3], L[4], z) + return block(T0, T1) //returns turfs within our projected rectangle in a specific order. //this ensures that turfs are copied over in the same order, regardless of any rotation @@ -200,6 +207,7 @@ icon_state = "pinonclose" var/area/shuttle/areaInstance + var/list/shuttle_areas var/timer //used as a timer (if you want time left to complete move, use timeLeft proc) var/mode = SHUTTLE_IDLE //current shuttle mode (see global defines) @@ -227,12 +235,16 @@ highlight("#0f0") #endif - - - /obj/docking_port/mobile/Initialize() if(!timid) register() + shuttle_areas = list() + var/list/all_turfs = return_ordered_turfs(x, y, z, dir) + for(var/i in 1 to all_turfs.len) + var/turf/curT = all_turfs[i] + var/area/cur_area = curT.loc + if(istype(cur_area, areaInstance)) + shuttle_areas[cur_area] = TRUE ..() /obj/docking_port/mobile/register() @@ -255,6 +267,7 @@ areaInstance = null destination = null previous = null + shuttle_areas = null return ..() //this is a hook for custom behaviour. Maybe at some point we could add checks to see if engines are intact @@ -821,11 +834,10 @@ /obj/machinery/computer/shuttle/ert name = "specops shuttle console" - //circuit = /obj/item/circuitboard/ert req_access = list(access_cent_general) shuttleId = "specops" possible_destinations = "specops_home;specops_away" - + resistance_flags = INDESTRUCTIBLE /obj/machinery/computer/shuttle/white_ship name = "White Ship Console" @@ -834,12 +846,6 @@ shuttleId = "whiteship" possible_destinations = "whiteship_away;whiteship_home;whiteship_z4" -/obj/machinery/computer/shuttle/vox - name = "skipjack control console" - req_access = list(access_vox) - shuttleId = "skipjack" - possible_destinations = "skipjack_away;skipjack_ne;skipjack_nw;skipjack_se;skipjack_sw;skipjack_z5" - /obj/machinery/computer/shuttle/engineering name = "Engineering Shuttle Console" desc = "Used to call and send the engineering shuttle." @@ -857,28 +863,11 @@ desc = "Used to call and send the administration shuttle." shuttleId = "admin" possible_destinations = "admin_home;admin_away" - -/obj/machinery/computer/shuttle/sst - name = "Syndicate Strike Time Shuttle Console" - desc = "Used to call and send the SST shuttle." - icon_keyboard = "syndie_key" - icon_screen = "syndishuttle" - req_access = list(access_syndicate) - shuttleId = "sst" - possible_destinations = "sst_home;sst_away" - -/obj/machinery/computer/shuttle/sit - name = "Syndicate Infiltration Team Shuttle Console" - desc = "Used to call and send the SIT shuttle." - icon_keyboard = "syndie_key" - icon_screen = "syndishuttle" - req_access = list(access_syndicate) - shuttleId = "sit" - possible_destinations = "sit_arrivals;sit_engshuttle;sit_away" - + resistance_flags = INDESTRUCTIBLE /obj/machinery/computer/shuttle/trade name = "Freighter Console" + resistance_flags = INDESTRUCTIBLE /obj/machinery/computer/shuttle/trade/sol req_access = list(access_trade_sol) diff --git a/code/modules/shuttle/shuttle_rotate.dm b/code/modules/shuttle/shuttle_rotate.dm new file mode 100644 index 00000000000..f2f35b1139c --- /dev/null +++ b/code/modules/shuttle/shuttle_rotate.dm @@ -0,0 +1,112 @@ +/* +All shuttleRotate procs go here +If ever any of these procs are useful for non-shuttles, rename it to proc/rotate and move it to be a generic atom proc +*/ + +/************************************Base proc************************************/ + +/atom/proc/shuttleRotate(rotation, params=ROTATE_DIR|ROTATE_SMOOTH|ROTATE_OFFSET) + if(params & ROTATE_DIR) + //rotate our direction + setDir(angle2dir(rotation+dir2angle(dir))) + + //resmooth if need be. + if(smooth && (params & ROTATE_SMOOTH)) + queue_smooth(src) + + //rotate the pixel offsets too. + if((pixel_x || pixel_y) && (params & ROTATE_OFFSET)) + if(rotation < 0) + rotation += 360 + for(var/turntimes=rotation/90;turntimes>0;turntimes--) + var/oldPX = pixel_x + var/oldPY = pixel_y + pixel_x = oldPY + pixel_y = (oldPX*(-1)) + +/************************************Turf rotate procs************************************/ + +/************************************Mob rotate procs************************************/ + +//override to avoid rotating pixel_xy on mobs +/mob/shuttleRotate(rotation, params) + params = NONE + . = ..() + if(!buckled) + setDir(angle2dir(rotation+dir2angle(dir))) + +/mob/dead/observer/shuttleRotate(rotation, params) + . = ..() + update_icons() + +/************************************Structure rotate procs************************************/ + +/obj/structure/cable/shuttleRotate(rotation, params) + params &= ~ROTATE_DIR + . = ..() + if(d1) + d1 = angle2dir(rotation+dir2angle(d1)) + if(d2) + d2 = angle2dir(rotation+dir2angle(d2)) + + //d1 should be less than d2 for cable icons to work + if(d1 > d2) + var/temp = d1 + d1 = d2 + d2 = temp + update_icon() + +//Fixes dpdir on shuttle rotation +/obj/structure/disposalpipe/shuttleRotate(rotation, params) + . = ..() + var/new_dpdir = 0 + for(var/D in list(NORTH, SOUTH, EAST, WEST)) + if(dpdir & D) + new_dpdir = new_dpdir | angle2dir(rotation+dir2angle(D)) + dpdir = new_dpdir + +/obj/structure/alien/weeds/shuttleRotate(rotation, params) + params &= ~ROTATE_OFFSET + return ..() + +//prevents shuttles attempting to rotate this since it messes up sprites +/obj/structure/table/shuttleRotate(rotation, params) + params = NONE + return ..() + +/obj/structure/table_frame/shuttleRotate(rotation, params) + params = NONE + return ..() + +/************************************Machine rotate procs************************************/ + +/*/obj/machinery/atmospherics/shuttleRotate(rotation, params) + var/list/real_node_connect = getNodeConnects() + for(var/i in 1 to device_type) + real_node_connect[i] = angle2dir(rotation+dir2angle(real_node_connect[i])) + . = ..() + SetInitDirections() + var/list/supposed_node_connect = getNodeConnects() + var/list/nodes_copy = nodes.Copy() + for(var/i in 1 to device_type) + var/new_pos = supposed_node_connect.Find(real_node_connect[i]) + nodes[new_pos] = nodes_copy[i] +*/ +//prevents shuttles attempting to rotate this since it messes up sprites +/obj/machinery/gateway/shuttleRotate(rotation, params) + params = NONE + return ..() + +//prevents shuttles attempting to rotate this since it messes up sprites +/obj/machinery/gravity_generator/shuttleRotate(rotation, params) + params = NONE + return ..() +/* +/obj/machinery/door/airlock/shuttleRotate(rotation, params) + . = ..() + if(cyclelinkeddir && (params & ROTATE_DIR)) + cyclelinkeddir = angle2dir(rotation+dir2angle(cyclelinkeddir)) + // If we update the linked airlock here, the partner airlock might + // not be present yet, so don't do that. Just assume we're still + // partnered with the same airlock as before. +*/ \ No newline at end of file diff --git a/code/modules/shuttle/syndicate.dm b/code/modules/shuttle/syndicate.dm index 14fde8c1be0..532fedc5497 100644 --- a/code/modules/shuttle/syndicate.dm +++ b/code/modules/shuttle/syndicate.dm @@ -7,7 +7,8 @@ req_access = list(access_syndicate) circuit = /obj/item/circuitboard/shuttle/syndicate shuttleId = "syndicate" - possible_destinations = "syndicate_away;syndicate_z5;syndicate_z3;syndicate_ne;syndicate_nw;syndicate_n;syndicate_se;syndicate_sw;syndicate_s" + possible_destinations = "syndicate_away;syndicate_z5;syndicate_z3;syndicate_ne;syndicate_nw;syndicate_n;syndicate_se;syndicate_sw;syndicate_s;syndicate_custom" + resistance_flags = INDESTRUCTIBLE var/challenge = FALSE var/moved = FALSE @@ -40,4 +41,55 @@ return 0 ..() -#undef SYNDICATE_CHALLENGE_TIMER +/obj/machinery/computer/shuttle/sst + name = "Syndicate Strike Time Shuttle Console" + desc = "Used to call and send the SST shuttle." + icon_keyboard = "syndie_key" + icon_screen = "syndishuttle" + req_access = list(access_syndicate) + shuttleId = "sst" + possible_destinations = "sst_home;sst_away;sst_custom" + resistance_flags = INDESTRUCTIBLE + +/obj/machinery/computer/shuttle/sit + name = "Syndicate Infiltration Team Shuttle Console" + desc = "Used to call and send the SIT shuttle." + icon_keyboard = "syndie_key" + icon_screen = "syndishuttle" + req_access = list(access_syndicate) + shuttleId = "sit" + possible_destinations = "sit_arrivals;sit_engshuttle;sit_away;sit_custom" + resistance_flags = INDESTRUCTIBLE + +/obj/machinery/computer/camera_advanced/shuttle_docker/syndicate + name = "syndicate shuttle navigation computer" + desc = "Used to designate a precise transit location for the syndicate shuttle." + icon_screen = "syndishuttle" + icon_keyboard = "syndie_key" + shuttleId = "syndicate" + shuttlePortId = "syndicate_custom" + view_range = 13 + x_offset = -5 + y_offset = -1 + see_hidden = TRUE + resistance_flags = INDESTRUCTIBLE + +/obj/machinery/computer/camera_advanced/shuttle_docker/syndicate/SST + name = "SST shuttle navigation computer" + desc = "Used to designate a precise transit location for the SST shuttle." + shuttleId = "sst" + shuttlePortId = "sst_custom" + view_range = 13 + x_offset = 0 + y_offset = 0 + +/obj/machinery/computer/camera_advanced/shuttle_docker/syndicate/SIT + name = "SIT shuttle navigation computer" + desc = "Used to designate a precise transit location for the SIT shuttle." + shuttleId = "sit" + shuttlePortId = "sit_custom" + view_range = 13 + x_offset = 0 + y_offset = 0 + +#undef SYNDICATE_CHALLENGE_TIMER \ No newline at end of file diff --git a/code/modules/shuttle/vox.dm b/code/modules/shuttle/vox.dm new file mode 100644 index 00000000000..7b3be543e20 --- /dev/null +++ b/code/modules/shuttle/vox.dm @@ -0,0 +1,19 @@ +/obj/machinery/computer/shuttle/vox + name = "skipjack control console" + req_access = list(access_vox) + shuttleId = "skipjack" + possible_destinations = "skipjack_away;skipjack_ne;skipjack_nw;skipjack_se;skipjack_sw;skipjack_z5;skipjack_custom" + resistance_flags = INDESTRUCTIBLE + +/obj/machinery/computer/camera_advanced/shuttle_docker/vox + name = "skipjack navigation computer" + desc = "Used to designate a precise transit location for the skipjack." + icon_screen = "shuttle" + icon_keyboard = "tech_key" + shuttleId = "skipjack" + shuttlePortId = "skipjack_custom" + view_range = 13 + x_offset = -10 + y_offset = -10 + resistance_flags = INDESTRUCTIBLE + access_derelict = TRUE diff --git a/code/modules/space_management/space_level.dm b/code/modules/space_management/space_level.dm index e53264e5d57..67fd1d6dc69 100644 --- a/code/modules/space_management/space_level.dm +++ b/code/modules/space_management/space_level.dm @@ -27,6 +27,7 @@ flags = traits build_space_destination_arrays() set_linkage(transition_type) + set_navbeacon() /datum/space_level/Destroy() if(linkage == CROSSLINKED) @@ -134,6 +135,14 @@ if(SELFLOOPING) link_to_self() // `link_to_self` is defined in space_transitions.dm +//create docking ports for navigation consoles to jump to +/datum/space_level/proc/set_navbeacon() + var/obj/docking_port/stationary/D = new /obj/docking_port/stationary(src) + D.name = name + D.id = "nav_z[zpos]" + D.register() + D.forceMove(locate(122, 122, zpos)) + var/list/atmos_machine_typecache = typecacheof(/obj/machinery/atmospherics) var/list/cable_typecache = typecacheof(/obj/structure/cable) var/list/maploader_typecache = typecacheof(/obj/effect/landmark/map_loader) diff --git a/paradise.dme b/paradise.dme index 912ff79c344..020aa9d41ae 100644 --- a/paradise.dme +++ b/paradise.dme @@ -54,6 +54,7 @@ #include "code\__DEFINES\reagents.dm" #include "code\__DEFINES\role_preferences.dm" #include "code\__DEFINES\rolebans.dm" +#include "code\__DEFINES\shuttle.dm" #include "code\__DEFINES\sight.dm" #include "code\__DEFINES\snpc.dm" #include "code\__DEFINES\sound.dm" @@ -2265,12 +2266,15 @@ #include "code\modules\security_levels\security levels.dm" #include "code\modules\shuttle\assault_pod.dm" #include "code\modules\shuttle\emergency.dm" +#include "code\modules\shuttle\navigation_computer.dm" #include "code\modules\shuttle\on_move.dm" #include "code\modules\shuttle\ripple.dm" #include "code\modules\shuttle\shuttle.dm" #include "code\modules\shuttle\shuttle_manipulator.dm" +#include "code\modules\shuttle\shuttle_rotate.dm" #include "code\modules\shuttle\supply.dm" #include "code\modules\shuttle\syndicate.dm" +#include "code\modules\shuttle\vox.dm" #include "code\modules\space_management\heap_space_level.dm" #include "code\modules\space_management\level_check.dm" #include "code\modules\space_management\level_traits.dm"