Conflicts!!!
This commit is contained in:
@@ -0,0 +1,268 @@
|
||||
#define Z_DIST 500
|
||||
#define CUSTOM_ENGINES_START_TIME 65
|
||||
#define CALCULATE_STATS_COOLDOWN 2
|
||||
|
||||
/obj/machinery/computer/custom_shuttle
|
||||
name = "nanotrasen shuttle flight controller"
|
||||
desc = "A terminal used to fly shuttles defined by the Shuttle Zoning Designator"
|
||||
circuit = /obj/item/circuitboard/computer/shuttle/flight_control
|
||||
icon_screen = "shuttle"
|
||||
icon_keyboard = "tech_key"
|
||||
light_color = LIGHT_COLOR_CYAN
|
||||
req_access = list( )
|
||||
var/shuttleId
|
||||
var/possible_destinations = "whiteship_home"
|
||||
var/admin_controlled
|
||||
var/no_destination_swap = 0
|
||||
var/calculated_mass = 0
|
||||
var/calculated_dforce = 0
|
||||
var/calculated_speed = 0
|
||||
var/calculated_engine_count = 0
|
||||
var/calculated_consumption = 0
|
||||
var/calculated_cooldown = 0
|
||||
var/calculated_non_operational_thrusters = 0
|
||||
var/calculated_fuel_less_thrusters = 0
|
||||
var/target_fuel_cost = 0
|
||||
var/targetLocation
|
||||
var/datum/browser/popup
|
||||
|
||||
var/stat_calc_cooldown = 0
|
||||
|
||||
//Upgrades
|
||||
var/distance_multiplier = 1
|
||||
|
||||
/obj/machinery/computer/custom_shuttle/examine(mob/user)
|
||||
. = ..()
|
||||
. += distance_multiplier < 1 ? "Bluespace shortcut module installed. Route is [distance_multiplier]x the original length." : ""
|
||||
|
||||
/obj/machinery/computer/custom_shuttle/ui_interact(mob/user)
|
||||
var/list/options = params2list(possible_destinations)
|
||||
var/obj/docking_port/mobile/M = SSshuttle.getShuttle(shuttleId)
|
||||
var/dat = "[M ? "Current Location : [M.getStatusText()]" : "Shuttle link required."]<br><br>"
|
||||
if(M)
|
||||
dat += "<A href='?src=[REF(src)];calculate=1'>Run Flight Calculations</A><br>"
|
||||
dat += "<b>Shuttle Data</b><hr>"
|
||||
dat += "Shuttle Mass: [calculated_mass/10]tons<br>"
|
||||
dat += "Engine Force: [calculated_dforce]kN ([calculated_engine_count] engines)<br>"
|
||||
dat += "Sublight Speed: [calculated_speed]ms<sup>-1</sup><br>"
|
||||
dat += calculated_speed < 1 ? "<b>INSUFFICIENT ENGINE POWER</b><br>" : ""
|
||||
dat += calculated_non_operational_thrusters > 0 ? "<b>Warning: [calculated_non_operational_thrusters] thrusters offline.</b><br>" : ""
|
||||
dat += "Fuel Consumption: [calculated_consumption]units per distance<br>"
|
||||
dat += "Engine Cooldown: [calculated_cooldown]s<hr>"
|
||||
var/destination_found
|
||||
for(var/obj/docking_port/stationary/S in SSshuttle.stationary)
|
||||
if(!options.Find(S.id))
|
||||
continue
|
||||
if(!M.check_dock(S, silent=TRUE))
|
||||
continue
|
||||
if(calculated_speed == 0)
|
||||
break
|
||||
destination_found = TRUE
|
||||
var/dist = round(calculateDistance(S))
|
||||
dat += "<A href='?src=[REF(src)];setloc=[S.id]'>Target [S.name] (Dist: [dist] | Fuel Cost: [round(dist * calculated_consumption)] | Time: [round(dist / calculated_speed)])</A><br>"
|
||||
if(!destination_found)
|
||||
dat += "<B>No valid destinations</B><br>"
|
||||
dat += "<hr>[targetLocation ? "Target Location : [targetLocation]" : "No Target Location"]"
|
||||
dat += "<hr><A href='?src=[REF(src)];fly=1'>Initate Flight</A><br>"
|
||||
dat += "<A href='?src=[REF(user)];mach_close=computer'>Close</a>"
|
||||
|
||||
popup = new(user, "computer", M ? M.name : "shuttle", 350, 450)
|
||||
popup.set_content("<center>[dat]</center>")
|
||||
popup.set_title_image(usr.browse_rsc_icon(src.icon, src.icon_state))
|
||||
popup.open()
|
||||
|
||||
/obj/machinery/computer/custom_shuttle/Topic(href, href_list)
|
||||
if(..())
|
||||
return
|
||||
usr.set_machine(src)
|
||||
src.add_fingerprint(usr)
|
||||
if(!allowed(usr))
|
||||
to_chat(usr, "<span class='danger'>Access denied.</span>")
|
||||
return
|
||||
|
||||
if(href_list["calculate"])
|
||||
calculateStats()
|
||||
ui_interact(usr)
|
||||
return
|
||||
var/obj/docking_port/mobile/M = SSshuttle.getShuttle(shuttleId)
|
||||
if(!M)
|
||||
return
|
||||
if(M.launch_status == ENDGAME_LAUNCHED)
|
||||
return
|
||||
if(href_list["setloc"])
|
||||
SetTargetLocation(href_list["setloc"])
|
||||
ui_interact(usr)
|
||||
return
|
||||
else if(href_list["fly"])
|
||||
Fly()
|
||||
ui_interact(usr)
|
||||
return
|
||||
|
||||
/obj/machinery/computer/custom_shuttle/proc/calculateDistance(var/obj/docking_port/stationary/port)
|
||||
var/deltaX = port.x - x
|
||||
var/deltaY = port.y - y
|
||||
var/deltaZ = (port.z - z) * Z_DIST
|
||||
return sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ) * distance_multiplier
|
||||
|
||||
/obj/machinery/computer/custom_shuttle/proc/linkShuttle(var/new_id)
|
||||
shuttleId = new_id
|
||||
possible_destinations = "whiteship_home;shuttle[new_id]_custom"
|
||||
|
||||
/obj/machinery/computer/custom_shuttle/proc/calculateStats(var/useFuel = FALSE, var/dist = 0, var/ignore_cooldown = FALSE)
|
||||
if(!ignore_cooldown && stat_calc_cooldown >= world.time)
|
||||
to_chat(usr, "<span>You are using this too fast, please slow down</span>")
|
||||
return
|
||||
stat_calc_cooldown = world.time + CALCULATE_STATS_COOLDOWN
|
||||
var/obj/docking_port/mobile/M = SSshuttle.getShuttle(shuttleId)
|
||||
if(!M)
|
||||
return FALSE
|
||||
//Reset data
|
||||
calculated_mass = 0
|
||||
calculated_dforce = 0
|
||||
calculated_speed = 0
|
||||
calculated_engine_count = 0
|
||||
calculated_consumption = 0
|
||||
calculated_cooldown = 0
|
||||
calculated_fuel_less_thrusters = 0
|
||||
calculated_non_operational_thrusters = 0
|
||||
//Calculate all the data
|
||||
var/list/areas = M.shuttle_areas
|
||||
for(var/shuttleArea in areas)
|
||||
calculated_mass += length(get_area_turfs(shuttleArea))
|
||||
for(var/obj/machinery/shuttle/engine/E in shuttleArea)
|
||||
E.check_setup()
|
||||
if(!E.thruster_active) //Skipover thrusters with no valid heater
|
||||
calculated_non_operational_thrusters ++
|
||||
continue
|
||||
if(E.attached_heater)
|
||||
var/obj/machinery/atmospherics/components/unary/shuttle/heater/resolvedHeater = E.attached_heater.resolve()
|
||||
if(resolvedHeater && !resolvedHeater.hasFuel(dist * E.fuel_use) && useFuel)
|
||||
calculated_fuel_less_thrusters ++
|
||||
continue
|
||||
calculated_engine_count++
|
||||
calculated_dforce += E.thrust
|
||||
calculated_consumption += E.fuel_use
|
||||
calculated_cooldown = max(calculated_cooldown, E.cooldown)
|
||||
//This should really be accelleration, but its a 2d spessman game so who cares
|
||||
if(calculated_mass == 0)
|
||||
return FALSE
|
||||
calculated_speed = (calculated_dforce*1000) / (calculated_mass*100)
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/computer/custom_shuttle/proc/consumeFuel(var/dist)
|
||||
var/obj/docking_port/mobile/M = SSshuttle.getShuttle(shuttleId)
|
||||
if(!M)
|
||||
return FALSE
|
||||
//Calculate all the data
|
||||
for(var/obj/machinery/shuttle/engine/shuttle_machine in GLOB.custom_shuttle_machines)
|
||||
shuttle_machine.check_setup()
|
||||
if(!shuttle_machine.thruster_active)
|
||||
continue
|
||||
if(get_area(M) != get_area(shuttle_machine))
|
||||
continue
|
||||
if(shuttle_machine.attached_heater)
|
||||
var/obj/machinery/atmospherics/components/unary/shuttle/heater/resolvedHeater = shuttle_machine.attached_heater.resolve()
|
||||
if(resolvedHeater && !resolvedHeater.hasFuel(dist * shuttle_machine.fuel_use))
|
||||
continue
|
||||
resolvedHeater?.consumeFuel(dist * shuttle_machine.fuel_use)
|
||||
shuttle_machine.fireEngine()
|
||||
|
||||
/obj/machinery/computer/custom_shuttle/proc/SetTargetLocation(var/newTarget)
|
||||
if(!(newTarget in params2list(possible_destinations)))
|
||||
log_admin("[usr] attempted to href dock exploit on [src] with target location \"[newTarget]\"")
|
||||
message_admins("[usr] just attempted to href dock exploit on [src] with target location \"[newTarget]\"")
|
||||
return
|
||||
targetLocation = newTarget
|
||||
say("Shuttle route calculated.")
|
||||
return
|
||||
|
||||
/obj/machinery/computer/custom_shuttle/proc/Fly()
|
||||
if(!targetLocation)
|
||||
return
|
||||
var/obj/docking_port/mobile/linkedShuttle = SSshuttle.getShuttle(shuttleId)
|
||||
if(!linkedShuttle)
|
||||
return
|
||||
if(linkedShuttle.mode != SHUTTLE_IDLE)
|
||||
return
|
||||
if(!calculateStats(TRUE, 0, TRUE))
|
||||
return
|
||||
if(calculated_fuel_less_thrusters > 0)
|
||||
say("Warning, [calculated_fuel_less_thrusters] do not have enough fuel for this journey, engine output may be limitted.")
|
||||
if(calculated_speed < 1)
|
||||
say("Insufficient engine power, shuttle requires [calculated_mass / 10]kN of thrust.")
|
||||
return
|
||||
var/obj/docking_port/stationary/targetPort = SSshuttle.getDock(targetLocation)
|
||||
if(!targetPort)
|
||||
return
|
||||
var/dist = calculateDistance(targetPort)
|
||||
var/time = min(max(round(dist / calculated_speed), 10), 90)
|
||||
linkedShuttle.callTime = time * 10
|
||||
linkedShuttle.rechargeTime = calculated_cooldown
|
||||
//We need to find the direction of this console to the port
|
||||
linkedShuttle.port_direction = angle2dir(dir2angle(dir) - (dir2angle(linkedShuttle.dir)) + 180)
|
||||
linkedShuttle.preferred_direction = NORTH
|
||||
linkedShuttle.ignitionTime = CUSTOM_ENGINES_START_TIME
|
||||
linkedShuttle.count_engines()
|
||||
linkedShuttle.hyperspace_sound(HYPERSPACE_WARMUP)
|
||||
var/throwForce = clamp((calculated_speed / 2) - 5, 0, 10)
|
||||
linkedShuttle.movement_force = list("KNOCKDOWN" = calculated_speed > 5 ? 3 : 0, "THROW" = throwForce)
|
||||
if(!(targetLocation in params2list(possible_destinations)))
|
||||
log_admin("[usr] attempted to launch a shuttle that has been affected by href dock exploit on [src] with target location \"[targetLocation]\"")
|
||||
message_admins("[usr] attempted to launch a shuttle that has been affected by href dock exploit on [src] with target location \"[targetLocation]\"")
|
||||
return
|
||||
switch(SSshuttle.moveShuttle(shuttleId, targetLocation, 1))
|
||||
if(0)
|
||||
consumeFuel(dist)
|
||||
say("Shuttle departing. Please stand away from the doors.")
|
||||
if(1)
|
||||
to_chat(usr, "<span class='warning'>Invalid shuttle requested.</span>")
|
||||
else
|
||||
to_chat(usr, "<span class='notice'>Unable to comply.</span>")
|
||||
return
|
||||
|
||||
/obj/machinery/computer/custom_shuttle/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE)
|
||||
if(port && (shuttleId == initial(shuttleId) || override))
|
||||
linkShuttle(port.id)
|
||||
|
||||
//Custom shuttle docker locations
|
||||
/obj/machinery/computer/camera_advanced/shuttle_docker/custom
|
||||
name = "Shuttle Navigation Computer"
|
||||
desc = "Used to designate a precise transit location for private ships."
|
||||
lock_override = NONE
|
||||
whitelist_turfs = list(/turf/open/space,
|
||||
/turf/open/lava,
|
||||
/turf/open/floor/plating/beach,
|
||||
/turf/open/floor/plating/ashplanet,
|
||||
/turf/open/floor/plating/asteroid,
|
||||
/turf/open/floor/plating/lavaland_baseturf)
|
||||
jumpto_ports = list("whiteship_home" = 1)
|
||||
view_range = 12
|
||||
designate_time = 100
|
||||
circuit = /obj/item/circuitboard/computer/shuttle/docker
|
||||
|
||||
/obj/machinery/computer/camera_advanced/shuttle_docker/custom/Initialize()
|
||||
. = ..()
|
||||
GLOB.jam_on_wardec += src
|
||||
|
||||
/obj/machinery/computer/camera_advanced/shuttle_docker/custom/Destroy()
|
||||
GLOB.jam_on_wardec -= src
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/camera_advanced/shuttle_docker/custom/placeLandingSpot()
|
||||
if(!shuttleId)
|
||||
return //Only way this would happen is if someone else delinks the console while in use somehow
|
||||
var/obj/docking_port/mobile/M = SSshuttle.getShuttle(shuttleId)
|
||||
if(M?.mode != SHUTTLE_IDLE)
|
||||
to_chat(usr, "<span class='warning'>You cannot target locations while in transit.</span>")
|
||||
return
|
||||
..()
|
||||
|
||||
/obj/machinery/computer/camera_advanced/shuttle_docker/custom/attack_hand(mob/user)
|
||||
if(!shuttleId)
|
||||
to_chat(user, "<span class='warning'>You must link the console to a shuttle first.</span>")
|
||||
return
|
||||
return ..()
|
||||
|
||||
/obj/machinery/computer/camera_advanced/shuttle_docker/custom/proc/linkShuttle(var/new_id)
|
||||
shuttleId = new_id
|
||||
shuttlePortId = "shuttle[new_id]_custom"
|
||||
+124
-42
@@ -11,17 +11,31 @@
|
||||
|
||||
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
|
||||
anchored = TRUE
|
||||
//
|
||||
/// The identifier of the port or ship.
|
||||
/// This will be used in numerous other places like the console,
|
||||
/// stationary ports and whatnot to tell them your ship's mobile
|
||||
/// port can be used in these places, or the docking port is compatible, etc.
|
||||
var/id
|
||||
// this should point -away- from the dockingport door, ie towards the ship
|
||||
///Common standard is for this to point -away- from the dockingport door, ie towards the ship
|
||||
dir = NORTH
|
||||
var/width = 0 //size of covered area, perpendicular to dir
|
||||
var/height = 0 //size of covered area, parallel to dir
|
||||
var/dwidth = 0 //position relative to covered area, perpendicular to dir
|
||||
var/dheight = 0 //position relative to covered area, parallel to dir
|
||||
///size of covered area, perpendicular to dir. You shouldn't modify this for mobile dockingports, set automatically.
|
||||
var/width = 0
|
||||
///size of covered area, parallel to dir. You shouldn't modify this for mobile dockingports, set automatically.
|
||||
var/height = 0
|
||||
///position relative to covered area, perpendicular to dir. You shouldn't modify this for mobile dockingports, set automatically.
|
||||
var/dwidth = 0
|
||||
///position relative to covered area, parallel to dir. You shouldn't modify this for mobile dockingports, set automatically.
|
||||
var/dheight = 0
|
||||
|
||||
var/area_type
|
||||
var/hidden = FALSE //are we invisible to shuttle navigation computers?
|
||||
///are we invisible to shuttle navigation computers?
|
||||
var/hidden = FALSE
|
||||
|
||||
///Delete this port after ship fly off.
|
||||
var/delete_after = FALSE
|
||||
|
||||
/obj/docking_port/proc/get_save_vars()
|
||||
return list("pixel_x", "pixel_y", "dir", "name", "req_access", "req_access_txt", "piping_layer", "color", "icon_state", "pipe_color", "amount", "width", "height", "dwidth", "dheight")
|
||||
|
||||
//these objects are indestructible
|
||||
/obj/docking_port/Destroy(force)
|
||||
@@ -155,8 +169,6 @@
|
||||
/obj/docking_port/stationary
|
||||
name = "dock"
|
||||
|
||||
area_type = SHUTTLE_DEFAULT_UNDERLYING_AREA
|
||||
|
||||
var/last_dock_time
|
||||
|
||||
var/datum/map_template/shuttle/roundstart_template
|
||||
@@ -169,6 +181,9 @@
|
||||
id = "[SSshuttle.stationary.len]"
|
||||
if(name == "dock")
|
||||
name = "dock[SSshuttle.stationary.len]"
|
||||
if(!area_type)
|
||||
var/area/place = get_area(src)
|
||||
area_type = place?.type || SHUTTLE_DEFAULT_UNDERLYING_AREA // We might be created in nullspace
|
||||
|
||||
if(mapload)
|
||||
for(var/turf/T in return_turfs())
|
||||
@@ -183,6 +198,13 @@
|
||||
SSshuttle.stationary -= src
|
||||
. = ..()
|
||||
|
||||
/obj/docking_port/stationary/Moved(atom/oldloc, dir, forced)
|
||||
. = ..()
|
||||
if(area_type) // We already have one
|
||||
return
|
||||
var/area/newarea = get_area(src)
|
||||
area_type = newarea?.type
|
||||
|
||||
/obj/docking_port/stationary/proc/load_roundstart()
|
||||
if(json_key)
|
||||
var/sid = SSmapping.config.shuttles[json_key]
|
||||
@@ -235,16 +257,25 @@
|
||||
|
||||
var/list/shuttle_areas
|
||||
|
||||
var/timer //used as a timer (if you want time left to complete move, use timeLeft proc)
|
||||
///used as a timer (if you want time left to complete move, use timeLeft proc)
|
||||
var/timer
|
||||
var/last_timer_length
|
||||
///current shuttle mode
|
||||
var/mode = SHUTTLE_IDLE
|
||||
///time spent in transit (deciseconds). Should not be lower then 10 seconds without editing the animation of the hyperspace ripples.
|
||||
var/callTime = 100
|
||||
/// time spent "starting the engines". Also rate limits how often we try to reserve transit space if its ever full of transiting shuttles.
|
||||
var/ignitionTime = 55
|
||||
/// time spent after arrival before being able to begin ignition
|
||||
var/rechargeTime = 0
|
||||
/// time spent after transit 'landing' before actually arriving
|
||||
var/prearrivalTime = 0
|
||||
|
||||
var/mode = SHUTTLE_IDLE //current shuttle mode
|
||||
var/callTime = 100 //time spent in transit (deciseconds). Should not be lower then 10 seconds without editing the animation of the hyperspace ripples.
|
||||
var/ignitionTime = 55 // time spent "starting the engines". Also rate limits how often we try to reserve transit space if its ever full of transiting shuttles.
|
||||
|
||||
// The direction the shuttle prefers to travel in
|
||||
/// The direction the shuttle prefers to travel in, ie what direction
|
||||
/// the animation will cause it to appear to be traveling in
|
||||
var/preferred_direction = NORTH
|
||||
// And the angle from the front of the shuttle to the port
|
||||
/// relative direction of the docking port from the front of the shuttle
|
||||
/// NORTH is towards front, EAST would be starboard side, WEST port, etc.
|
||||
var/port_direction = NORTH
|
||||
|
||||
var/obj/docking_port/stationary/destination
|
||||
@@ -254,13 +285,16 @@
|
||||
|
||||
var/launch_status = NOLAUNCH
|
||||
|
||||
var/list/movement_force = list("KNOCKDOWN" = 3, "THROW" = 2)
|
||||
///Whether or not you want your ship to knock people down, and also whether it will throw them several tiles upon launching.
|
||||
var/list/movement_force = list("KNOCKDOWN" = 3, "THROW" = 0)
|
||||
|
||||
var/list/ripples = list()
|
||||
var/engine_coeff = 1 //current engine coeff
|
||||
var/current_engines = 0 //current engine power
|
||||
var/initial_engines = 0 //initial engine power
|
||||
var/can_move_docking_ports = FALSE //if this shuttle can move docking ports other than the one it is docked at
|
||||
var/engine_coeff = 1
|
||||
var/current_engines = 0
|
||||
var/initial_engines = 0
|
||||
var/list/engine_list = list()
|
||||
///if this shuttle can move docking ports other than the one it is docked at
|
||||
var/can_move_docking_ports = FALSE
|
||||
var/list/hidden_turfs = list()
|
||||
|
||||
/obj/docking_port/mobile/proc/register()
|
||||
@@ -308,14 +342,12 @@
|
||||
id = "[id][idnum]"
|
||||
if(name == initial(name))
|
||||
name = "[name] [idnum]"
|
||||
for(var/i in shuttle_areas)
|
||||
var/area/place = i
|
||||
for(var/obj/machinery/computer/shuttle/comp in place)
|
||||
comp.connect_to_shuttle(src, dock, idnum)
|
||||
for(var/obj/machinery/computer/camera_advanced/shuttle_docker/comp in place)
|
||||
comp.connect_to_shuttle(src, dock, idnum)
|
||||
for(var/obj/machinery/status_display/shuttle/sd in place)
|
||||
sd.connect_to_shuttle(src, dock, idnum)
|
||||
for(var/place in shuttle_areas)
|
||||
var/area/area = place
|
||||
area.connect_to_shuttle(src, dock, idnum, FALSE)
|
||||
for(var/each in place)
|
||||
var/atom/atom = each
|
||||
atom.connect_to_shuttle(src, dock, idnum, FALSE)
|
||||
|
||||
|
||||
//this is a hook for custom behaviour. Maybe at some point we could add checks to see if engines are intact
|
||||
@@ -423,7 +455,10 @@
|
||||
if(initiate_docking(S1) != DOCKING_SUCCESS)
|
||||
WARNING("shuttle \"[id]\" could not enter transit space. Docked at [S0 ? S0.id : "null"]. Transit dock [S1 ? S1.id : "null"].")
|
||||
else
|
||||
previous = S0
|
||||
if(S0.delete_after)
|
||||
qdel(S0, TRUE)
|
||||
else
|
||||
previous = S0
|
||||
else
|
||||
WARNING("shuttle \"[id]\" could not enter transit space. S0=[S0 ? S0.id : "null"] S1=[S1 ? S1.id : "null"]")
|
||||
|
||||
@@ -472,7 +507,7 @@
|
||||
if(M.mind && !istype(t, /turf/open/floor/plasteel/shuttle/red) && !istype(t, /turf/open/floor/mineral/plastitanium/red/brig))
|
||||
M.mind.force_escaped = TRUE
|
||||
// Ghostize them and put them in nullspace stasis (for stat & possession checks)
|
||||
M.notransform = TRUE
|
||||
M.mob_transforming = TRUE
|
||||
M.ghostize(FALSE)
|
||||
M.moveToNullspace()
|
||||
|
||||
@@ -536,7 +571,11 @@
|
||||
// If we can't dock or we don't have a transit slot, wait for 20 ds,
|
||||
// then try again
|
||||
switch(mode)
|
||||
if(SHUTTLE_CALL)
|
||||
if(SHUTTLE_CALL, SHUTTLE_PREARRIVAL)
|
||||
if(prearrivalTime && mode != SHUTTLE_PREARRIVAL)
|
||||
mode = SHUTTLE_PREARRIVAL
|
||||
setTimer(prearrivalTime)
|
||||
return
|
||||
var/error = initiate_docking(destination, preferred_direction)
|
||||
if(error && error & (DOCKING_NULL_DESTINATION | DOCKING_NULL_SOURCE))
|
||||
var/msg = "A mobile dock in transit exited initiate_docking() with an error. This is most likely a mapping problem: Error: [error], ([src]) ([previous][ADMIN_JMP(previous)] -> [destination][ADMIN_JMP(destination)])"
|
||||
@@ -547,6 +586,10 @@
|
||||
else if(error)
|
||||
setTimer(20)
|
||||
return
|
||||
if(rechargeTime)
|
||||
mode = SHUTTLE_RECHARGING
|
||||
setTimer(rechargeTime)
|
||||
return
|
||||
if(SHUTTLE_RECALL)
|
||||
if(initiate_docking(previous) != DOCKING_SUCCESS)
|
||||
setTimer(20)
|
||||
@@ -649,6 +692,10 @@
|
||||
return "ESC"
|
||||
if(SHUTTLE_STRANDED)
|
||||
return "ERR"
|
||||
if(SHUTTLE_RECHARGING)
|
||||
return "RCH"
|
||||
if(SHUTTLE_PREARRIVAL)
|
||||
return "LDN"
|
||||
return ""
|
||||
|
||||
// returns 5-letter timer string, used by status screens and mob status panel
|
||||
@@ -667,7 +714,7 @@
|
||||
|
||||
/obj/docking_port/mobile/proc/getStatusText()
|
||||
var/obj/docking_port/stationary/dockedAt = get_docked()
|
||||
|
||||
var/docked_at = dockedAt?.name || "unknown"
|
||||
if(istype(dockedAt, /obj/docking_port/stationary/transit))
|
||||
if (timeLeft() > 1 HOURS)
|
||||
return "hyperspace"
|
||||
@@ -678,8 +725,10 @@
|
||||
else
|
||||
dst = destination
|
||||
. = "transit towards [dst?.name || "unknown location"] ([getTimerStr()])"
|
||||
else if(mode == SHUTTLE_RECHARGING)
|
||||
return "[docked_at], recharging [getTimerStr()]"
|
||||
else
|
||||
return dockedAt?.name || "unknown"
|
||||
return docked_at
|
||||
|
||||
|
||||
/obj/docking_port/mobile/proc/getDbgStatusText()
|
||||
@@ -711,19 +760,47 @@
|
||||
return null
|
||||
|
||||
/obj/docking_port/mobile/proc/hyperspace_sound(phase, list/areas)
|
||||
var/s
|
||||
var/selected_sound
|
||||
switch(phase)
|
||||
if(HYPERSPACE_WARMUP)
|
||||
s = 'sound/effects/hyperspace_begin.ogg'
|
||||
selected_sound = "hyperspace_begin"
|
||||
if(HYPERSPACE_LAUNCH)
|
||||
s = 'sound/effects/hyperspace_progress.ogg'
|
||||
selected_sound = "hyperspace_progress"
|
||||
if(HYPERSPACE_END)
|
||||
s = 'sound/effects/hyperspace_end.ogg'
|
||||
selected_sound = "hyperspace_end"
|
||||
else
|
||||
CRASH("Invalid hyperspace sound phase: [phase]")
|
||||
for(var/A in areas)
|
||||
for(var/obj/machinery/door/E in A) //dumb, I know, but playing it on the engines doesn't do it justice
|
||||
playsound(E, s, 100, FALSE, max(width, height) - world.view)
|
||||
// This previously was played from each door at max volume, and was one of the worst things I had ever seen.
|
||||
// Now it's instead played from the nearest engine if close, or the first engine in the list if far since it doesn't really matter.
|
||||
// Or a door if for some reason the shuttle has no engine, fuck oh hi daniel fuck it
|
||||
var/range = (engine_coeff * max(width, height))
|
||||
var/long_range = range * 2.5
|
||||
var/atom/distant_source
|
||||
if(LAZYLEN(engine_list))
|
||||
distant_source = engine_list[1]
|
||||
else
|
||||
for(var/A in areas)
|
||||
distant_source = locate(/obj/machinery/door) in A
|
||||
if(distant_source)
|
||||
break
|
||||
|
||||
if(distant_source)
|
||||
for(var/mob/M in SSmobs.clients_by_zlevel[z])
|
||||
var/dist_far = get_dist(M, distant_source)
|
||||
if(dist_far <= long_range && dist_far > range)
|
||||
M.playsound_local(distant_source, "sound/effects/[selected_sound]_distance.ogg", 100, falloff = 20)
|
||||
else if(dist_far <= range)
|
||||
var/source
|
||||
if(engine_list.len == 0)
|
||||
source = distant_source
|
||||
else
|
||||
var/closest_dist = 10000
|
||||
for(var/obj/O in engine_list)
|
||||
var/dist_near = get_dist(M, O)
|
||||
if(dist_near < closest_dist)
|
||||
source = O
|
||||
closest_dist = dist_near
|
||||
M.playsound_local(source, "sound/effects/[selected_sound].ogg", 100, falloff = range / 2)
|
||||
|
||||
// Losing all initial engines should get you 2
|
||||
// Adding another set of engines at 0.5 time
|
||||
@@ -743,7 +820,12 @@
|
||||
var/area/shuttle/areaInstance = thing
|
||||
for(var/obj/structure/shuttle/engine/E in areaInstance.contents)
|
||||
if(!QDELETED(E))
|
||||
engine_list += E
|
||||
. += E.engine_power
|
||||
for(var/obj/machinery/shuttle/engine/E in areaInstance.contents)
|
||||
if(!QDELETED(E))
|
||||
engine_list += E
|
||||
. += E.thruster_active ? 1 : 0
|
||||
|
||||
// Double initial engines to get to 0.5 minimum
|
||||
// Lose all initial engines to get to 2
|
||||
@@ -768,7 +850,7 @@
|
||||
|
||||
/obj/docking_port/mobile/proc/in_flight()
|
||||
switch(mode)
|
||||
if(SHUTTLE_CALL,SHUTTLE_RECALL)
|
||||
if(SHUTTLE_CALL,SHUTTLE_RECALL,SHUTTLE_PREARRIVAL)
|
||||
return TRUE
|
||||
if(SHUTTLE_IDLE,SHUTTLE_IGNITING)
|
||||
return FALSE
|
||||
|
||||
@@ -0,0 +1,370 @@
|
||||
#define SHUTTLE_CREATOR_MAX_SIZE CONFIG_GET(number/max_shuttle_size)
|
||||
#define CUSTOM_SHUTTLE_LIMIT CONFIG_GET(number/max_shuttle_count)
|
||||
#define CARDINAL_DIRECTIONS_X list(1, 0, -1, 0)
|
||||
#define CARDINAL_DIRECTIONS_Y list(0, 1, 0, -1)
|
||||
|
||||
GLOBAL_VAR_INIT(custom_shuttle_count, 0) //The amount of custom shuttles created to prevent creating hundreds
|
||||
GLOBAL_LIST_EMPTY(custom_shuttle_machines) //Machines that require updating (Heaters, engines)
|
||||
|
||||
//============ Shuttle Creator Object ============
|
||||
/obj/item/shuttle_creator
|
||||
name = "Rapid Shuttle Designator"
|
||||
icon = 'icons/obj/tools.dmi'
|
||||
icon_state = "rsd"
|
||||
lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
|
||||
righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
|
||||
desc = "A device used to define the area required for custom ships. Uses bluespace crystals to create bluespace-capable ships."
|
||||
density = FALSE
|
||||
anchored = FALSE
|
||||
flags_1 = CONDUCT_1
|
||||
item_flags = NOBLUDGEON
|
||||
force = 0
|
||||
throwforce = 8
|
||||
throw_speed = 3
|
||||
throw_range = 5
|
||||
w_class = WEIGHT_CLASS_NORMAL
|
||||
req_access_txt = "11"
|
||||
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50)
|
||||
resistance_flags = FIRE_PROOF
|
||||
var/ready = TRUE
|
||||
//pre-designation
|
||||
var/override_max_shuttles = FALSE
|
||||
var/obj/machinery/computer/camera_advanced/shuttle_creator/internal_shuttle_creator
|
||||
//During designation
|
||||
var/overwritten_area = /area/space
|
||||
var/list/loggedTurfs = list()
|
||||
var/loggedOldArea
|
||||
var/recorded_shuttle_area
|
||||
var/datum/shuttle_creator_overlay_holder/overlay_holder
|
||||
//After designation
|
||||
var/linkedShuttleId
|
||||
|
||||
/obj/item/shuttle_creator/Initialize()
|
||||
. = ..()
|
||||
internal_shuttle_creator = new()
|
||||
internal_shuttle_creator.owner_rsd = src
|
||||
overlay_holder = new()
|
||||
|
||||
/obj/item/shuttle_creator/Destroy()
|
||||
. = ..()
|
||||
if(internal_shuttle_creator)
|
||||
internal_shuttle_creator.owner_rsd = null
|
||||
QDEL_NULL(internal_shuttle_creator)
|
||||
if(overlay_holder)
|
||||
QDEL_NULL(overlay_holder)
|
||||
|
||||
/obj/item/shuttle_creator/attack_self(mob/user)
|
||||
..()
|
||||
if(linkedShuttleId)
|
||||
return
|
||||
if(GLOB.custom_shuttle_count > CUSTOM_SHUTTLE_LIMIT && !override_max_shuttles)
|
||||
to_chat(user, "<span class='warning'>Too many shuttles have been created.</span>")
|
||||
message_admins("[ADMIN_FLW(user)] attempted to create a shuttle, however [CUSTOM_SHUTTLE_LIMIT] have already been created.")
|
||||
return
|
||||
if(!internal_shuttle_creator)
|
||||
return
|
||||
overlay_holder.add_client(user.client)
|
||||
internal_shuttle_creator.attack_hand(user)
|
||||
|
||||
/obj/item/shuttle_creator/afterattack(atom/target, mob/user, proximity_flag)
|
||||
. = ..()
|
||||
if(!ready)
|
||||
to_chat(user, "<span class='warning'>You need to define a shuttle area first.</span>")
|
||||
return
|
||||
if(!proximity_flag)
|
||||
return
|
||||
if(istype(target, /obj/machinery/computer/custom_shuttle))
|
||||
if(!linkedShuttleId)
|
||||
to_chat(user, "<span class='warning'>Error, no defined shuttle linked to device</span>")
|
||||
return
|
||||
var/obj/machinery/computer/custom_shuttle/console = target
|
||||
console.linkShuttle(linkedShuttleId)
|
||||
to_chat(user, "<span class='notice'>Console linked successfully!</span>")
|
||||
return
|
||||
else if(istype(target, /obj/machinery/computer/camera_advanced/shuttle_docker/custom))
|
||||
if(!linkedShuttleId)
|
||||
to_chat(user, "<span class='warning'>Error, no defined shuttle linked to device</span>")
|
||||
return
|
||||
var/obj/machinery/computer/camera_advanced/shuttle_docker/custom/console = target
|
||||
console.linkShuttle(linkedShuttleId)
|
||||
to_chat(user, "<span class='notice'>Console linked successfully!</span>")
|
||||
return
|
||||
to_chat(user, "<span class='warning'>The [src] bleeps. Select an airlock to create a docking port, or a valid machine to link.</span>")
|
||||
return
|
||||
|
||||
//=========== shuttle designation actions ============
|
||||
/obj/item/shuttle_creator/proc/calculate_bounds(obj/docking_port/mobile/port)
|
||||
if(!port || !istype(port, /obj/docking_port/mobile))
|
||||
return FALSE
|
||||
//Heights is the distance away from the port
|
||||
//width is the distance perpendicular to the port
|
||||
var/minX = INFINITY
|
||||
var/maxX = 0
|
||||
var/minY = INFINITY
|
||||
var/maxY = 0
|
||||
for(var/turf/T in loggedTurfs)
|
||||
minX = min(T.x, minX)
|
||||
maxX = max(T.x, maxX)
|
||||
minY = min(T.y, minY)
|
||||
maxY = max(T.y, maxY)
|
||||
//Make sure shuttle was actually found.
|
||||
if(maxX == INFINITY || maxY == INFINITY)
|
||||
return FALSE
|
||||
minX--
|
||||
minY--
|
||||
var/width = maxX - minX
|
||||
var/height = maxY - minY
|
||||
var/offset_x = port.x - minX
|
||||
var/offset_y = port.y - minY
|
||||
switch(port.dir) //Source: code/datums/shuttles.dm line 77 (14/03/2020) :)
|
||||
if(NORTH)
|
||||
port.width = width
|
||||
port.height = height
|
||||
port.dwidth = offset_x - 1
|
||||
port.dheight = offset_y - 1
|
||||
if(EAST)
|
||||
port.width = height
|
||||
port.height = width
|
||||
port.dwidth = height - offset_y
|
||||
port.dheight = offset_x - 1
|
||||
if(SOUTH)
|
||||
port.width = width
|
||||
port.height = height
|
||||
port.dwidth = width - offset_x
|
||||
port.dheight = height - offset_y
|
||||
if(WEST)
|
||||
port.width = height
|
||||
port.height = width
|
||||
port.dwidth = offset_y - 1
|
||||
port.dheight = width - offset_x
|
||||
return TRUE
|
||||
|
||||
//Go through all the all_turfs and check which direction doesn't have the shuttle
|
||||
/obj/item/shuttle_creator/proc/getNonShuttleDirection(turf/targetTurf)
|
||||
var/position = null
|
||||
if(!(get_offset_target_turf(targetTurf, 0, 1) in loggedTurfs))
|
||||
if(position != null)
|
||||
return null
|
||||
position = NORTH
|
||||
if(!(get_offset_target_turf(targetTurf, 0, -1) in loggedTurfs))
|
||||
if(position != null)
|
||||
return null
|
||||
position = SOUTH
|
||||
if(!(get_offset_target_turf(targetTurf, 1, 0) in loggedTurfs))
|
||||
if(position != null)
|
||||
return null
|
||||
position = EAST
|
||||
if(!(get_offset_target_turf(targetTurf, -1, 0) in loggedTurfs))
|
||||
if(position != null)
|
||||
return null
|
||||
position = WEST
|
||||
return position
|
||||
|
||||
/obj/item/shuttle_creator/proc/invertDir(var/input_dir)
|
||||
if(input_dir == NORTH)
|
||||
return SOUTH
|
||||
else if(input_dir == SOUTH)
|
||||
return NORTH
|
||||
else if(input_dir == EAST)
|
||||
return WEST
|
||||
else if(input_dir == WEST)
|
||||
return EAST
|
||||
return null
|
||||
|
||||
/obj/item/shuttle_creator/proc/shuttle_create_docking_port(atom/target, mob/user)
|
||||
|
||||
if(loggedTurfs.len == 0 || !recorded_shuttle_area)
|
||||
to_chat(user, "<span class='warning'>Invalid shuttle, restarting bluespace systems...</span>")
|
||||
return FALSE
|
||||
|
||||
var/datum/map_template/shuttle/new_shuttle = new /datum/map_template/shuttle()
|
||||
|
||||
var/obj/docking_port/mobile/port = new /obj/docking_port/mobile(get_turf(target))
|
||||
var/obj/docking_port/stationary/stationary_port = new /obj/docking_port/stationary(get_turf(target))
|
||||
port.callTime = 50
|
||||
port.dir = 1 //Point away from space.
|
||||
port.id = "custom_[GLOB.custom_shuttle_count]"
|
||||
linkedShuttleId = port.id
|
||||
port.ignitionTime = 25
|
||||
port.name = "Custom Shuttle"
|
||||
port.port_direction = 2
|
||||
port.preferred_direction = 4
|
||||
port.area_type = recorded_shuttle_area
|
||||
|
||||
stationary_port.area_type = overwritten_area
|
||||
|
||||
var/portDirection = getNonShuttleDirection(get_turf(port))
|
||||
var/invertedDir = invertDir(portDirection)
|
||||
if(!portDirection || !invertedDir)
|
||||
to_chat(usr, "<span class='warning'>Shuttle creation aborted, docking airlock must be on an external wall. Please select a new airlock.</span>")
|
||||
port.Destroy()
|
||||
stationary_port.Destroy()
|
||||
linkedShuttleId = null
|
||||
return FALSE
|
||||
port.dir = invertedDir
|
||||
port.port_direction = portDirection
|
||||
|
||||
if(!calculate_bounds(port))
|
||||
to_chat(usr, "<span class='warning'>Bluespace calculations failed, please select a new airlock.</span>")
|
||||
port.Destroy()
|
||||
stationary_port.Destroy()
|
||||
linkedShuttleId = null
|
||||
return FALSE
|
||||
|
||||
port.shuttle_areas = list()
|
||||
//var/list/all_turfs = port.return_ordered_turfs(port.x, port.y, port.z, port.dir)
|
||||
var/list/all_turfs = loggedTurfs
|
||||
for(var/i in 1 to all_turfs.len)
|
||||
var/turf/curT = all_turfs[i]
|
||||
var/area/cur_area = curT.loc
|
||||
//Add the area to the shuttle <3
|
||||
if(istype(cur_area, recorded_shuttle_area))
|
||||
if(istype(curT, /turf/open/space))
|
||||
continue
|
||||
if(length(curT.baseturfs) < 2)
|
||||
continue
|
||||
//Add the shuttle base shit to the shuttle
|
||||
curT.baseturfs.Insert(3, /turf/baseturf_skipover/shuttle)
|
||||
port.shuttle_areas[cur_area] = TRUE
|
||||
|
||||
port.linkup(new_shuttle, stationary_port)
|
||||
|
||||
port.movement_force = list("KNOCKDOWN" = 0, "THROW" = 0)
|
||||
port.initiate_docking(stationary_port)
|
||||
|
||||
port.mode = SHUTTLE_IDLE
|
||||
port.timer = 0
|
||||
|
||||
port.register()
|
||||
|
||||
icon_state = "rsd_used"
|
||||
|
||||
//Clear highlights
|
||||
overlay_holder.clear_highlights()
|
||||
GLOB.custom_shuttle_count ++
|
||||
message_admins("[ADMIN_LOOKUPFLW(user)] created a new shuttle with a [src] at [ADMIN_VERBOSEJMP(user)] ([GLOB.custom_shuttle_count] custom shuttles, limit is [CUSTOM_SHUTTLE_LIMIT])")
|
||||
log_game("[key_name(user)] created a new shuttle with a [src] at [AREACOORD(user)] ([GLOB.custom_shuttle_count] custom shuttles, limit is [CUSTOM_SHUTTLE_LIMIT])")
|
||||
return TRUE
|
||||
|
||||
/obj/item/shuttle_creator/proc/create_shuttle_area(mob/user)
|
||||
//Check to see if the user can make a new area to prevent spamming
|
||||
if(user)
|
||||
if(user.create_area_cooldown >= world.time)
|
||||
to_chat(user, "<span class='warning'>Smoke vents from the [src], maybe you should let it cooldown before using it again.</span>")
|
||||
return FALSE
|
||||
user.create_area_cooldown = world.time + 10
|
||||
if(!loggedTurfs)
|
||||
return FALSE
|
||||
if(!check_area(loggedTurfs, FALSE)) //Makes sure nothing (Shuttles) has moved into the area during creation
|
||||
return FALSE
|
||||
//Create the new area
|
||||
var/area/shuttle/custom/powered/newS
|
||||
var/area/oldA = loggedOldArea
|
||||
var/str = stripped_input(user, "Shuttle Name:", "Blueprint Editing", "", MAX_NAME_LEN)
|
||||
if(!str || !length(str))
|
||||
return FALSE
|
||||
if(length(str) > 50)
|
||||
to_chat(user, "<span class='warning'>The provided ship name is too long, blares the [src]</span>")
|
||||
return FALSE
|
||||
newS = new /area/shuttle/custom/powered()
|
||||
newS.setup(str)
|
||||
newS.set_dynamic_lighting()
|
||||
//Shuttles always have gravity
|
||||
newS.has_gravity = TRUE
|
||||
newS.requires_power = TRUE
|
||||
//Record the area for use when creating the docking port
|
||||
recorded_shuttle_area = newS
|
||||
|
||||
for(var/i in 1 to loggedTurfs.len)
|
||||
var/turf/turf_holder = loggedTurfs[i]
|
||||
var/area/old_area = turf_holder.loc
|
||||
newS.contents += turf_holder
|
||||
turf_holder.change_area(old_area, newS)
|
||||
|
||||
newS.reg_in_areas_in_z()
|
||||
|
||||
var/list/firedoors = oldA.firedoors
|
||||
for(var/door in firedoors)
|
||||
var/obj/machinery/door/firedoor/FD = door
|
||||
FD.CalculateAffectingAreas()
|
||||
return TRUE
|
||||
|
||||
//Checks an area to ensure that the turfs provided are valid to be made into a shuttle
|
||||
/obj/item/shuttle_creator/proc/check_area(list/turfs, addingTurfs = TRUE)
|
||||
if(!turfs)
|
||||
to_chat(usr, "<span class='warning'>Shuttles must be created in an airtight space, ensure that the shuttle is airtight, including corners.</span>")
|
||||
return FALSE
|
||||
if(turfs.len + (addingTurfs ? loggedTurfs.len : 0) > SHUTTLE_CREATOR_MAX_SIZE)
|
||||
to_chat(usr, "<span class='warning'>The [src]'s internal cooling system wizzes violently and a message appears on the screen, \"Caution, this device can only handle the creation of shuttles up to [SHUTTLE_CREATOR_MAX_SIZE] units in size. Please reduce your shuttle by [turfs.len-SHUTTLE_CREATOR_MAX_SIZE]. Sorry for the inconvinience\"</span>")
|
||||
return FALSE
|
||||
//Check to see if it's a valid shuttle
|
||||
for(var/i in 1 to turfs.len)
|
||||
var/area/place = get_area(turfs[i])
|
||||
//If any of the turfs are on station / not in space, a shuttle cannot be forced there
|
||||
if(!place)
|
||||
to_chat(usr, "<span class='warning'>You can't seem to overpower the bluespace harmonics in this location, try somewhere else.</span>")
|
||||
return FALSE
|
||||
if(istype(place, /area/space))
|
||||
overwritten_area = /area/space
|
||||
else if(istype(place, /area/lavaland/surface/outdoors))
|
||||
overwritten_area = /area/lavaland/surface/outdoors
|
||||
else
|
||||
to_chat(usr, "<span class='warning'>Caution, shuttle must not use any material connected to the station. Your shuttle is currenly overlapping with [place.name]</span>")
|
||||
return FALSE
|
||||
//Finally, check to see if the area is actually attached
|
||||
if(!LAZYLEN(loggedTurfs))
|
||||
return TRUE
|
||||
for(var/turf/T in turfs)
|
||||
if(turf_connected_to_saved_turfs(T))
|
||||
return TRUE
|
||||
CHECK_TICK
|
||||
to_chat(usr, "<span class='warning'>Caution, new areas of the shuttle must be connected to the other areas of the shuttle.</span>")
|
||||
return FALSE
|
||||
|
||||
/obj/item/shuttle_creator/proc/turf_connected_to_saved_turfs(turf/T)
|
||||
for(var/i in 1 to 4)
|
||||
var/turf/adjacentT = get_offset_target_turf(T, CARDINAL_DIRECTIONS_X[i], CARDINAL_DIRECTIONS_Y[i])
|
||||
if(adjacentT in loggedTurfs)
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
/obj/item/shuttle_creator/proc/turf_in_list(turf/T)
|
||||
return loggedTurfs.Find(T)
|
||||
|
||||
/obj/item/shuttle_creator/proc/add_single_turf(turf/T)
|
||||
if(!check_area(list(T)))
|
||||
return FALSE
|
||||
loggedTurfs |= T
|
||||
loggedOldArea = get_area(T)
|
||||
overlay_holder.highlight_turf(T)
|
||||
|
||||
/obj/item/shuttle_creator/proc/add_saved_area(mob/user)
|
||||
var/static/area_or_turf_fail_types = typecacheof(list(
|
||||
/turf/open/space,
|
||||
/area/shuttle
|
||||
))
|
||||
//Detect the turfs connected in the curerrent enclosed area
|
||||
var/list/turfs = detect_room(get_turf(user), area_or_turf_fail_types)
|
||||
if(!check_area(turfs))
|
||||
return FALSE
|
||||
loggedOldArea = get_area(get_turf(user))
|
||||
loggedTurfs |= turfs
|
||||
overlay_holder.highlight_area(turfs)
|
||||
//TODO READD THIS SHIT: icon_state = "rsd_used"
|
||||
to_chat(user, "<span class='notice'>You add the area into the buffer of the [src], you made add more areas or select an airlock to act as a docking port to complete the shuttle.</span>")
|
||||
return turfs
|
||||
|
||||
/obj/item/shuttle_creator/proc/remove_single_turf(turf/T)
|
||||
if(!turf_in_list(T))
|
||||
return
|
||||
loggedTurfs -= T
|
||||
loggedOldArea = get_area(T)
|
||||
overlay_holder.unhighlight_turf(T)
|
||||
|
||||
/obj/item/shuttle_creator/proc/reset_saved_area()
|
||||
overlay_holder.clear_highlights()
|
||||
loggedTurfs.Cut()
|
||||
to_chat(usr, "<span class='notice'>You reset the area buffer on the [src].</span>")
|
||||
|
||||
#undef CARDINAL_DIRECTIONS_X
|
||||
#undef CARDINAL_DIRECTIONS_Y
|
||||
@@ -0,0 +1,101 @@
|
||||
//============ Actions ============
|
||||
/datum/action/innate/shuttle_creator
|
||||
icon_icon = 'icons/mob/actions/actions_shuttle.dmi'
|
||||
var/mob/living/C
|
||||
var/mob/camera/aiEye/remote/shuttle_creation/remote_eye
|
||||
var/obj/item/shuttle_creator/shuttle_creator
|
||||
|
||||
/datum/action/innate/shuttle_creator/Activate()
|
||||
if(!target)
|
||||
return TRUE
|
||||
C = owner
|
||||
remote_eye = C.remote_control
|
||||
var/obj/machinery/computer/camera_advanced/shuttle_creator/internal_console = target
|
||||
shuttle_creator = internal_console.owner_rsd
|
||||
|
||||
//Add an area
|
||||
/datum/action/innate/shuttle_creator/designate_area
|
||||
name = "Designate Room"
|
||||
button_icon_state = "designate_area"
|
||||
|
||||
/datum/action/innate/shuttle_creator/designate_area/Activate()
|
||||
if(..())
|
||||
return
|
||||
shuttle_creator.add_saved_area(remote_eye)
|
||||
|
||||
//Add a single turf
|
||||
/datum/action/innate/shuttle_creator/designate_turf
|
||||
name = "Designate Turf"
|
||||
button_icon_state = "designate_turf"
|
||||
|
||||
/datum/action/innate/shuttle_creator/designate_turf/Activate()
|
||||
if(..())
|
||||
return
|
||||
var/turf/T = get_turf(remote_eye)
|
||||
if(istype(T, /turf/open/space))
|
||||
var/connectors_exist = FALSE
|
||||
for(var/obj/structure/lattice/lattice in T)
|
||||
connectors_exist = TRUE
|
||||
break
|
||||
if(!connectors_exist)
|
||||
to_chat(usr, "<span class='warning'>This turf requires support, build some catwalks or lattices.</span>")
|
||||
return
|
||||
if(!shuttle_creator.check_area(list(T)))
|
||||
return
|
||||
if(shuttle_creator.turf_in_list(T))
|
||||
return
|
||||
shuttle_creator.add_single_turf(T)
|
||||
|
||||
//Clear a single entire area
|
||||
/datum/action/innate/shuttle_creator/clear_turf
|
||||
name = "Clear Turf"
|
||||
button_icon_state = "clear_turf"
|
||||
|
||||
/datum/action/innate/shuttle_creator/clear_turf/Activate()
|
||||
if(..())
|
||||
return
|
||||
shuttle_creator.remove_single_turf(get_turf(remote_eye))
|
||||
|
||||
//Clear the entire area
|
||||
/datum/action/innate/shuttle_creator/reset
|
||||
name = "Reset Buffer"
|
||||
button_icon_state = "clear_area"
|
||||
|
||||
/datum/action/innate/shuttle_creator/reset/Activate()
|
||||
if(..())
|
||||
return
|
||||
shuttle_creator.reset_saved_area()
|
||||
|
||||
//Finish the shuttle
|
||||
/datum/action/innate/shuttle_creator/airlock
|
||||
name = "Select Docking Airlock"
|
||||
button_icon_state = "select_airlock"
|
||||
|
||||
/datum/action/innate/shuttle_creator/airlock/Activate()
|
||||
if(..())
|
||||
return
|
||||
var/turf/T = get_turf(remote_eye)
|
||||
for(var/obj/machinery/door/airlock/A in T)
|
||||
if(get_area(A) != shuttle_creator.loggedOldArea)
|
||||
to_chat(C, "<span class='warning'>Caution, airlock must be on the shuttle to function as a dock.</span>")
|
||||
return
|
||||
if(shuttle_creator.linkedShuttleId)
|
||||
return
|
||||
if(GLOB.custom_shuttle_count > CUSTOM_SHUTTLE_LIMIT)
|
||||
to_chat(C, "<span class='warning'>Shuttle limit reached, sorry.</span>")
|
||||
return
|
||||
if(shuttle_creator.loggedTurfs.len > SHUTTLE_CREATOR_MAX_SIZE)
|
||||
to_chat(C, "<span class='warning'>This shuttle is too large!</span>")
|
||||
return
|
||||
if(!shuttle_creator.getNonShuttleDirection(T))
|
||||
to_chat(C, "<span class='warning'>Docking port must be on an external wall, with only 1 side exposed to space.</span>")
|
||||
return
|
||||
if(!shuttle_creator.create_shuttle_area(C))
|
||||
return
|
||||
if(shuttle_creator.shuttle_create_docking_port(A, C))
|
||||
to_chat(C, "<span class='notice'>Shuttle created!</span>")
|
||||
//Remove eye control
|
||||
var/obj/machinery/computer/camera_advanced/shuttle_creator/internal_console = target
|
||||
internal_console.remove_eye_control()
|
||||
qdel(internal_console)
|
||||
return
|
||||
@@ -0,0 +1,93 @@
|
||||
//============The internal camera console used for designating the area=============
|
||||
/obj/machinery/computer/camera_advanced/shuttle_creator
|
||||
name = "internal shuttle creator console"
|
||||
desc = "You should not have access to this, please report this as a bug"
|
||||
networks = list()
|
||||
var/obj/item/shuttle_creator/owner_rsd
|
||||
var/datum/action/innate/shuttle_creator/designate_area/area_action = new
|
||||
var/datum/action/innate/shuttle_creator/designate_turf/turf_action = new
|
||||
var/datum/action/innate/shuttle_creator/clear_turf/clear_turf_action = new
|
||||
var/datum/action/innate/shuttle_creator/reset/reset_action = new
|
||||
var/datum/action/innate/shuttle_creator/airlock/airlock_action = new
|
||||
|
||||
/obj/machinery/computer/camera_advanced/shuttle_creator/check_eye(mob/user)
|
||||
if(user.eye_blind || user.incapacitated())
|
||||
user.unset_machine()
|
||||
|
||||
/obj/machinery/computer/camera_advanced/shuttle_creator/CreateEye()
|
||||
eyeobj = new /mob/camera/aiEye/remote/shuttle_creation(get_turf(owner_rsd))
|
||||
eyeobj.origin = src
|
||||
eyeobj.use_static = USE_STATIC_NONE
|
||||
|
||||
/obj/machinery/computer/camera_advanced/shuttle_creator/is_operational()
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/computer/camera_advanced/shuttle_creator/can_interact(mob/user)
|
||||
if(!isliving(user))
|
||||
return FALSE
|
||||
var/mob/living/L = user
|
||||
if(L.incapacitated())
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/obj/machinery/computer/camera_advanced/shuttle_creator/GrantActions(mob/living/user)
|
||||
..(user)
|
||||
eyeobj.invisibility = SEE_INVISIBLE_LIVING
|
||||
if(area_action)
|
||||
area_action.target = src
|
||||
area_action.Grant(user)
|
||||
actions += area_action
|
||||
if(turf_action)
|
||||
turf_action.target = src
|
||||
turf_action.Grant(user)
|
||||
actions += turf_action
|
||||
if(clear_turf_action)
|
||||
clear_turf_action.target = src
|
||||
clear_turf_action.Grant(user)
|
||||
actions += clear_turf_action
|
||||
if(reset_action)
|
||||
reset_action.target = src
|
||||
reset_action.Grant(user)
|
||||
actions += reset_action
|
||||
if(airlock_action)
|
||||
airlock_action.target = src
|
||||
airlock_action.Grant(user)
|
||||
actions += airlock_action
|
||||
|
||||
/obj/machinery/computer/camera_advanced/shuttle_creator/remove_eye_control(mob/living/user)
|
||||
. = ..()
|
||||
owner_rsd.overlay_holder.remove_client()
|
||||
eyeobj.invisibility = INVISIBILITY_MAXIMUM
|
||||
if(user.client)
|
||||
user.client.images -= eyeobj.user_image
|
||||
|
||||
/obj/machinery/computer/camera_advanced/shuttle_creator/attack_hand(mob/user)
|
||||
if(!is_operational()) //you cant use broken machine you chumbis
|
||||
return
|
||||
if(current_user)
|
||||
to_chat(user, "The console is already in use!")
|
||||
return
|
||||
var/mob/living/L = user
|
||||
if(!can_use(user))
|
||||
return
|
||||
if(!eyeobj)
|
||||
CreateEye()
|
||||
if(!eyeobj.eye_initialized)
|
||||
var/camera_location = get_turf(owner_rsd)
|
||||
if(camera_location)
|
||||
eyeobj.eye_initialized = TRUE
|
||||
give_eye_control(L)
|
||||
eyeobj.setLoc(camera_location)
|
||||
var/mob/camera/aiEye/remote/shuttle_creation/shuttle_eye = eyeobj
|
||||
shuttle_eye.source_turf = get_turf(user)
|
||||
else
|
||||
user.unset_machine()
|
||||
else
|
||||
var/camera_location = get_turf(owner_rsd)
|
||||
var/mob/camera/aiEye/remote/shuttle_creation/eye = eyeobj
|
||||
give_eye_control(L)
|
||||
if(camera_location)
|
||||
eye.source_turf = camera_location
|
||||
eyeobj.setLoc(camera_location)
|
||||
else
|
||||
eyeobj.setLoc(eyeobj.loc)
|
||||
@@ -0,0 +1,54 @@
|
||||
//===============Camera Eye================
|
||||
/mob/camera/aiEye/remote/shuttle_creation
|
||||
name = "shuttle holo-drone"
|
||||
icon = 'icons/obj/mining.dmi'
|
||||
icon_state = "construction_drone"
|
||||
visible_icon = FALSE
|
||||
acceleration = 0
|
||||
var/turf/source_turf
|
||||
var/max_range = 12
|
||||
|
||||
/mob/camera/aiEye/remote/shuttle_creation/Initialize()
|
||||
. = ..()
|
||||
setLoc(get_turf(source_turf))
|
||||
|
||||
/mob/camera/aiEye/remote/shuttle_creation/update_remote_sight(mob/living/user)
|
||||
user.sight = BLIND|SEE_TURFS
|
||||
user.lighting_alpha = LIGHTING_PLANE_ALPHA_INVISIBLE
|
||||
user.sync_lighting_plane_alpha()
|
||||
return TRUE
|
||||
|
||||
/mob/camera/aiEye/remote/shuttle_creation/relaymove(mob/user, direct)
|
||||
dir = direct //This camera eye is visible as a drone, and needs to keep the dir updated
|
||||
var/initial = initial(sprint)
|
||||
var/max_sprint = 50
|
||||
|
||||
if(cooldown && cooldown < world.timeofday) // 3 seconds
|
||||
sprint = initial
|
||||
|
||||
for(var/i = 0; i < max(sprint, initial); i += 20)
|
||||
var/turf/step = get_turf(get_step(src, direct))
|
||||
if(step && can_move_to(step))
|
||||
setLoc(step)
|
||||
|
||||
cooldown = world.timeofday + 5
|
||||
if(acceleration)
|
||||
sprint = min(sprint + 0.5, max_sprint)
|
||||
else
|
||||
sprint = initial
|
||||
|
||||
/mob/camera/aiEye/remote/shuttle_creation/proc/can_move_to(var/turf/T)
|
||||
var/origin_x = source_turf.x
|
||||
var/origin_y = source_turf.y
|
||||
var/change_X = abs(origin_x - T.x)
|
||||
var/change_Y = abs(origin_y - T.y)
|
||||
return (change_X < max_range && change_Y < max_range)
|
||||
|
||||
/mob/camera/aiEye/remote/shuttle_creation/setLoc(T)
|
||||
..()
|
||||
if(eye_user?.client)
|
||||
eye_user.client.images -= user_image
|
||||
var/image/I = image(icon, loc, icon_state, FLY_LAYER, dir)
|
||||
I.plane = MASSIVE_OBJ_LAYER
|
||||
user_image = I
|
||||
eye_user.client.images += user_image
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Manages the overlays for the shuttle creator drone.
|
||||
*/
|
||||
|
||||
/datum/shuttle_creator_overlay_holder
|
||||
var/client/holder
|
||||
var/list/images = list()
|
||||
var/list/turfs = list()
|
||||
|
||||
/datum/shuttle_creator_overlay_holder/proc/add_client(client/C)
|
||||
holder = C
|
||||
holder.images += images
|
||||
|
||||
/datum/shuttle_creator_overlay_holder/proc/remove_client()
|
||||
holder.images -= images
|
||||
holder = null
|
||||
|
||||
/datum/shuttle_creator_overlay_holder/proc/clear_highlights()
|
||||
if(holder)
|
||||
holder.images -= images
|
||||
images.Cut()
|
||||
turfs.Cut()
|
||||
|
||||
/datum/shuttle_creator_overlay_holder/proc/create_hightlight(turf/T)
|
||||
if(T in turfs)
|
||||
return
|
||||
var/image/I = image('icons/turf/overlays.dmi', T, "greenOverlay")
|
||||
I.plane = ABOVE_LIGHTING_PLANE
|
||||
images += I
|
||||
holder.images += I
|
||||
turfs += T
|
||||
|
||||
/datum/shuttle_creator_overlay_holder/proc/remove_hightlight(turf/T)
|
||||
if(!(T in turfs))
|
||||
return
|
||||
turfs -= T
|
||||
holder.images -= images
|
||||
for(var/image/I in images)
|
||||
if(get_turf(I) != T)
|
||||
continue
|
||||
images -= I
|
||||
holder.images += images
|
||||
|
||||
/datum/shuttle_creator_overlay_holder/proc/highlight_area(list/turfs)
|
||||
for(var/turf/T in turfs)
|
||||
highlight_turf(T)
|
||||
|
||||
/datum/shuttle_creator_overlay_holder/proc/highlight_turf(turf/T)
|
||||
create_hightlight(T)
|
||||
|
||||
/datum/shuttle_creator_overlay_holder/proc/unhighlight_turf(turf/T)
|
||||
remove_hightlight(T)
|
||||
@@ -0,0 +1,39 @@
|
||||
/obj/item/shuttle_route_optimisation
|
||||
name = "Route Optimisation Upgrade"
|
||||
desc = "Used on a custom shuttle control console to calculate more efficient routes."
|
||||
icon = 'icons/obj/module.dmi'
|
||||
icon_state = "shuttledisk"
|
||||
force = 0
|
||||
throwforce = 0
|
||||
throw_speed = 1
|
||||
throw_range = 7
|
||||
density = FALSE
|
||||
anchored = FALSE
|
||||
item_flags = NOBLUDGEON
|
||||
var/upgrade_amount = 0.8
|
||||
|
||||
/obj/item/shuttle_route_optimisation/hyperlane
|
||||
name = "Bluespace Hyperlane Calculator"
|
||||
desc = "Used on a custom shuttle control console to allow for the following of bluespace hyperlanes, increasing the efficiency of the shuttle."
|
||||
icon_state = "shuttledisk_better"
|
||||
upgrade_amount = 0.6
|
||||
|
||||
/obj/item/shuttle_route_optimisation/void
|
||||
name = "Voidspace Route Calculator"
|
||||
desc = "Used on a custom shuttle control console to allow it to navigate into voidspace, making the routes almost instant."
|
||||
icon_state = "shuttledisk_void"
|
||||
upgrade_amount = 0.2
|
||||
|
||||
/obj/item/shuttle_route_optimisation/attack_obj(obj/O, mob/living/user)
|
||||
. = ..()
|
||||
if(!istype(O, /obj/machinery/computer))
|
||||
return
|
||||
if(!istype(O, /obj/machinery/computer/custom_shuttle))
|
||||
to_chat(user, "<span class='warning'>This upgrade only works on a custom shuttle flight console.</span>")
|
||||
return
|
||||
if (!user.transferItemToLoc(src, get_turf(O)))
|
||||
return
|
||||
var/obj/machinery/computer/custom_shuttle/link_comp = O
|
||||
link_comp.distance_multiplier = clamp(link_comp.distance_multiplier, 0, upgrade_amount)
|
||||
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
|
||||
to_chat(usr, "<span class='notice'>You insert the disk into the flight computer, allowing for routes to be [upgrade_amount]x the original distance.</span>")
|
||||
@@ -101,6 +101,10 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list(
|
||||
if(!SSshuttle.shoppinglist.len)
|
||||
return
|
||||
|
||||
var/list/obj/miscboxes = list() //miscboxes are combo boxes that contain all goody orders grouped
|
||||
var/list/misc_order_num = list() //list of strings of order numbers, so that the manifest can show all orders in a box
|
||||
var/list/misc_contents = list() //list of lists of items that each box will contain
|
||||
|
||||
var/list/empty_turfs = list()
|
||||
for(var/place in shuttle_areas)
|
||||
var/area/shuttle/shuttle_area = place
|
||||
@@ -117,10 +121,13 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list(
|
||||
break
|
||||
|
||||
var/price = SO.pack.cost
|
||||
if(SO.applied_coupon)
|
||||
price *= (1 - SO.applied_coupon.discount_pct_off)
|
||||
var/datum/bank_account/D
|
||||
if(SO.paying_account) //Someone paid out of pocket
|
||||
D = SO.paying_account
|
||||
price *= 1.1 //TODO make this customizable by the quartermaster
|
||||
if(!SO.pack.goody)
|
||||
price *= 1.1 //TODO make this customizable by the quartermaster
|
||||
else
|
||||
D = cargo_budget
|
||||
if(D)
|
||||
@@ -136,14 +143,46 @@ GLOBAL_LIST_INIT(cargo_shuttle_leave_behind_typecache, typecacheof(list(
|
||||
value += SO.pack.cost
|
||||
SSshuttle.shoppinglist -= SO
|
||||
SSshuttle.orderhistory += SO
|
||||
QDEL_NULL(SO.applied_coupon)
|
||||
|
||||
if(SO.pack.goody) //goody means it gets piled in the miscbox
|
||||
if(SO.paying_account)
|
||||
if(!miscboxes.len || !miscboxes[D.account_holder]) //if there's no miscbox for this person
|
||||
miscboxes[D.account_holder] = new /obj/item/storage/lockbox/order(pick_n_take(empty_turfs))
|
||||
var/obj/item/storage/lockbox/order/our_box = miscboxes[D.account_holder]
|
||||
our_box.buyer_account = SO.paying_account
|
||||
miscboxes[D.account_holder].name = "small items case - purchased by [D.account_holder]"
|
||||
misc_contents[D.account_holder] = list()
|
||||
for (var/item in SO.pack.contains)
|
||||
misc_contents[D.account_holder] += item
|
||||
misc_order_num[D.account_holder] = "[misc_order_num[D.account_holder]]#[SO.id] "
|
||||
else //No private payment, so we just stuff it all into a generic crate
|
||||
if(!miscboxes.len || !miscboxes["Cargo"])
|
||||
miscboxes["Cargo"] = new /obj/structure/closet/secure_closet/goodies(pick_n_take(empty_turfs))
|
||||
miscboxes["Cargo"].name = "small items closet"
|
||||
misc_contents["Cargo"] = list()
|
||||
miscboxes["Cargo"].req_access = list()
|
||||
for (var/item in SO.pack.contains)
|
||||
misc_contents["Cargo"] += item
|
||||
//new item(miscboxes["Cargo"])
|
||||
if(SO.pack.access)
|
||||
miscboxes["Cargo"].req_access += SO.pack.access
|
||||
misc_order_num["Cargo"] = "[misc_order_num["Cargo"]]#[SO.id] "
|
||||
else
|
||||
SO.generate(pick_n_take(empty_turfs))
|
||||
|
||||
SO.generate(pick_n_take(empty_turfs))
|
||||
SSblackbox.record_feedback("nested tally", "cargo_imports", 1, list("[SO.pack.cost]", "[SO.pack.name]"))
|
||||
investigate_log("Order #[SO.id] ([SO.pack.name], placed by [key_name(SO.orderer_ckey)]), paid by [D.account_holder] has shipped.", INVESTIGATE_CARGO)
|
||||
if(SO.pack.dangerous)
|
||||
message_admins("\A [SO.pack.name] ordered by [ADMIN_LOOKUPFLW(SO.orderer_ckey)], paid by [D.account_holder] has shipped.")
|
||||
purchases++
|
||||
|
||||
for(var/I in miscboxes)
|
||||
var/datum/supply_order/SO = new/datum/supply_order()
|
||||
SO.id = misc_order_num[I]
|
||||
SO.generateCombo(miscboxes[I], I, misc_contents[I])
|
||||
qdel(SO)
|
||||
|
||||
investigate_log("[purchases] orders in this shipment, worth [value] credits. [cargo_budget.account_balance] credits left.", INVESTIGATE_CARGO)
|
||||
|
||||
/obj/docking_port/mobile/supply/proc/sell()
|
||||
|
||||
Reference in New Issue
Block a user