Ported Basic Overmap Functionality

- Ports the overmap, ships, sectors, and "landable" ships from baystation.
- Ports necessary computers to control ships and overmap shuttles.
- Shims missing machine and computer functionality pending future enhancements.
- Includes required new sprites and sounds.
This commit is contained in:
Leshana
2020-03-10 22:20:17 -04:00
parent 86c435f4b7
commit 9cbdf184ff
39 changed files with 2064 additions and 555 deletions

View File

@@ -29,6 +29,7 @@
#define MINIMUM_AIR_TO_SUSPEND (MOLES_CELLSTANDARD * MINIMUM_AIR_RATIO_TO_SUSPEND) // Minimum amount of air that has to move before a group processing can be suspended #define MINIMUM_AIR_TO_SUSPEND (MOLES_CELLSTANDARD * MINIMUM_AIR_RATIO_TO_SUSPEND) // Minimum amount of air that has to move before a group processing can be suspended
#define MINIMUM_MOLES_DELTA_TO_MOVE (MOLES_CELLSTANDARD * MINIMUM_AIR_RATIO_TO_SUSPEND) // Either this must be active #define MINIMUM_MOLES_DELTA_TO_MOVE (MOLES_CELLSTANDARD * MINIMUM_AIR_RATIO_TO_SUSPEND) // Either this must be active
#define MINIMUM_TEMPERATURE_TO_MOVE (T20C + 100) // or this (or both, obviously) #define MINIMUM_TEMPERATURE_TO_MOVE (T20C + 100) // or this (or both, obviously)
#define MINIMUM_PRESSURE_DIFFERENCE_TO_SUSPEND (MINIMUM_AIR_TO_SUSPEND*R_IDEAL_GAS_EQUATION*T20C)/CELL_VOLUME // Minimum pressure difference between zones to suspend
#define MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND 0.012 // Minimum temperature difference before group processing is suspended. #define MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND 0.012 // Minimum temperature difference before group processing is suspended.
#define MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND 4 #define MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND 4

View File

@@ -38,6 +38,7 @@
#define CONNECT_TYPE_SUPPLY 2 #define CONNECT_TYPE_SUPPLY 2
#define CONNECT_TYPE_SCRUBBER 4 #define CONNECT_TYPE_SCRUBBER 4
#define CONNECT_TYPE_HE 8 #define CONNECT_TYPE_HE 8
#define CONNECT_TYPE_FUEL 16 // TODO - Implement this! Its piping so better ask Leshana
// We are based on the three named layers of supply, regular, and scrubber. // We are based on the three named layers of supply, regular, and scrubber.
#define PIPING_LAYER_SUPPLY 1 #define PIPING_LAYER_SUPPLY 1

View File

@@ -11,6 +11,11 @@ var/global/defer_powernet_rebuild = 0 // True if net rebuild will be called
#define DOOR_CRUSH_DAMAGE 20 #define DOOR_CRUSH_DAMAGE 20
#define ALIEN_SELECT_AFK_BUFFER 1 // How many minutes that a person can be AFK before not being allowed to be an alien. #define ALIEN_SELECT_AFK_BUFFER 1 // How many minutes that a person can be AFK before not being allowed to be an alien.
// Constants for machine's use_power
#define USE_POWER_OFF 0 // No continuous power use
#define USE_POWER_IDLE 1 // Machine is using power at its idle power level
#define USE_POWER_ACTIVE 2 // Machine is using power at its active power level
// Channel numbers for power. // Channel numbers for power.
#define EQUIP 1 #define EQUIP 1
#define LIGHT 2 #define LIGHT 2

View File

@@ -9,6 +9,11 @@
#define SLANDMARK_FLAG_AUTOSET 1 // If set, will set base area and turf type to same as where it was spawned at #define SLANDMARK_FLAG_AUTOSET 1 // If set, will set base area and turf type to same as where it was spawned at
#define SLANDMARK_FLAG_ZERO_G 2 // Zero-G shuttles moved here will lose gravity unless the area has ambient gravity. #define SLANDMARK_FLAG_ZERO_G 2 // Zero-G shuttles moved here will lose gravity unless the area has ambient gravity.
// Overmap landable shuttles (/obj/effect/overmap/visitable/ship/landable on a /datum/shuttle/autodock/overmap)
#define SHIP_STATUS_LANDED 1 // Ship is at any other shuttle landmark.
#define SHIP_STATUS_TRANSIT 2 // Ship is at it's shuttle datum's transition shuttle landmark.
#define SHIP_STATUS_OVERMAP 3 // Ship is at its "overmap" shuttle landmark (allowed to move on overmap now)
// Ferry shuttle location constants // Ferry shuttle location constants
#define FERRY_LOCATION_STATION 0 #define FERRY_LOCATION_STATION 0
#define FERRY_LOCATION_OFFSITE 1 #define FERRY_LOCATION_OFFSITE 1

View File

@@ -206,6 +206,20 @@ proc/listclearnulls(list/list)
result = first - second result = first - second
return result return result
/*
Two lists may be different (A!=B) even if they have the same elements.
This actually tests if they have the same entries and values.
*/
/proc/same_entries(var/list/first, var/list/second)
if(!islist(first) || !islist(second))
return 0
if(length(first) != length(second))
return 0
for(var/entry in first)
if(!(entry in second) || (first[entry] != second[entry]))
return 0
return 1
/* /*
* Returns list containing entries that are in either list but not both. * Returns list containing entries that are in either list but not both.
* If skipref = 1, repeated elements are treated as one. * If skipref = 1, repeated elements are treated as one.

View File

@@ -15,7 +15,6 @@ SUBSYSTEM_DEF(shuttles)
flags = SS_KEEP_TIMING|SS_NO_TICK_CHECK flags = SS_KEEP_TIMING|SS_NO_TICK_CHECK
runlevels = RUNLEVEL_GAME|RUNLEVEL_POSTGAME runlevels = RUNLEVEL_GAME|RUNLEVEL_POSTGAME
// TODO OVERMAP - These two are unused for now
var/overmap_halted = FALSE // Whether ships can move on the overmap; used for adminbus. var/overmap_halted = FALSE // Whether ships can move on the overmap; used for adminbus.
var/list/ships = list() // List of all ships. var/list/ships = list() // List of all ships.
@@ -99,14 +98,13 @@ SUBSYSTEM_DEF(shuttles)
registered_shuttle_landmarks[shuttle_landmark_tag] = shuttle_landmark registered_shuttle_landmarks[shuttle_landmark_tag] = shuttle_landmark
last_landmark_registration_time = world.time last_landmark_registration_time = world.time
// TODO - Uncomment once overmap sectors are ported var/obj/effect/overmap/visitable/O = landmarks_still_needed[shuttle_landmark_tag]
//var/obj/effect/overmap/visitable/O = landmarks_still_needed[shuttle_landmark_tag] if(O) //These need to be added to sectors, which we handle.
//if(O) //These need to be added to sectors, which we handle. try_add_landmark_tag(shuttle_landmark_tag, O)
// try_add_landmark_tag(shuttle_landmark_tag, O) landmarks_still_needed -= shuttle_landmark_tag
// landmarks_still_needed -= shuttle_landmark_tag else if(istype(shuttle_landmark, /obj/effect/shuttle_landmark/automatic)) //These find their sector automatically
//else if(istype(shuttle_landmark, /obj/effect/shuttle_landmark/automatic)) //These find their sector automatically O = map_sectors["[shuttle_landmark.z]"]
// O = map_sectors["[shuttle_landmark.z]"] O ? O.add_landmark(shuttle_landmark, shuttle_landmark.shuttle_restricted) : (landmarks_awaiting_sector += shuttle_landmark)
// O ? O.add_landmark(shuttle_landmark, shuttle_landmark.shuttle_restricted) : (landmarks_awaiting_sector += shuttle_landmark)
/datum/controller/subsystem/shuttles/proc/get_landmark(var/shuttle_landmark_tag) /datum/controller/subsystem/shuttles/proc/get_landmark(var/shuttle_landmark_tag)
return registered_shuttle_landmarks[shuttle_landmark_tag] return registered_shuttle_landmarks[shuttle_landmark_tag]
@@ -114,39 +112,37 @@ SUBSYSTEM_DEF(shuttles)
//Checks if the given sector's landmarks have initialized; if so, registers them with the sector, if not, marks them for assignment after they come in. //Checks if the given sector's landmarks have initialized; if so, registers them with the sector, if not, marks them for assignment after they come in.
//Also adds automatic landmarks that were waiting on their sector to spawn. //Also adds automatic landmarks that were waiting on their sector to spawn.
/datum/controller/subsystem/shuttles/proc/initialize_sector(obj/effect/overmap/visitable/given_sector) /datum/controller/subsystem/shuttles/proc/initialize_sector(obj/effect/overmap/visitable/given_sector)
return // TODO - Uncomment once overmap sectors are ported given_sector.populate_sector_objects() // This is a late init operation that sets up the sector's map_z and does non-overmap-related init tasks.
// given_sector.populate_sector_objects() // This is a late init operation that sets up the sector's map_z and does non-overmap-related init tasks.
// for(var/landmark_tag in given_sector.initial_generic_waypoints) for(var/landmark_tag in given_sector.initial_generic_waypoints)
// if(!try_add_landmark_tag(landmark_tag, given_sector)) if(!try_add_landmark_tag(landmark_tag, given_sector))
// landmarks_still_needed[landmark_tag] = given_sector // Landmark isn't registered yet, queue it to be added once it is. landmarks_still_needed[landmark_tag] = given_sector // Landmark isn't registered yet, queue it to be added once it is.
// for(var/shuttle_name in given_sector.initial_restricted_waypoints) for(var/shuttle_name in given_sector.initial_restricted_waypoints)
// for(var/landmark_tag in given_sector.initial_restricted_waypoints[shuttle_name]) for(var/landmark_tag in given_sector.initial_restricted_waypoints[shuttle_name])
// if(!try_add_landmark_tag(landmark_tag, given_sector)) if(!try_add_landmark_tag(landmark_tag, given_sector))
// landmarks_still_needed[landmark_tag] = given_sector // Landmark isn't registered yet, queue it to be added once it is. landmarks_still_needed[landmark_tag] = given_sector // Landmark isn't registered yet, queue it to be added once it is.
// var/landmarks_to_check = landmarks_awaiting_sector.Copy() var/landmarks_to_check = landmarks_awaiting_sector.Copy()
// for(var/thing in landmarks_to_check) for(var/thing in landmarks_to_check)
// var/obj/effect/shuttle_landmark/automatic/landmark = thing var/obj/effect/shuttle_landmark/automatic/landmark = thing
// if(landmark.z in given_sector.map_z) if(landmark.z in given_sector.map_z)
// given_sector.add_landmark(landmark, landmark.shuttle_restricted) given_sector.add_landmark(landmark, landmark.shuttle_restricted)
// landmarks_awaiting_sector -= landmark landmarks_awaiting_sector -= landmark
// TODO - Uncomment once overmap sectors are ported // Attempts to add a landmark instance with a sector (returns false if landmark isn't registered yet)
//// Attempts to add a landmark instance with a sector (returns false if landmark isn't registered yet) /datum/controller/subsystem/shuttles/proc/try_add_landmark_tag(landmark_tag, obj/effect/overmap/visitable/given_sector)
///datum/controller/subsystem/shuttles/proc/try_add_landmark_tag(landmark_tag, obj/effect/overmap/visitable/given_sector) var/obj/effect/shuttle_landmark/landmark = get_landmark(landmark_tag)
// var/obj/effect/shuttle_landmark/landmark = get_landmark(landmark_tag) if(!landmark)
// if(!landmark) return
// return
// if(landmark.landmark_tag in given_sector.initial_generic_waypoints) if(landmark.landmark_tag in given_sector.initial_generic_waypoints)
// given_sector.add_landmark(landmark) given_sector.add_landmark(landmark)
// . = 1 . = 1
// for(var/shuttle_name in given_sector.initial_restricted_waypoints) for(var/shuttle_name in given_sector.initial_restricted_waypoints)
// if(landmark.landmark_tag in given_sector.initial_restricted_waypoints[shuttle_name]) if(landmark.landmark_tag in given_sector.initial_restricted_waypoints[shuttle_name])
// given_sector.add_landmark(landmark, shuttle_name) given_sector.add_landmark(landmark, shuttle_name)
// . = 1 . = 1
/datum/controller/subsystem/shuttles/proc/initialize_shuttle(var/shuttle_type) /datum/controller/subsystem/shuttles/proc/initialize_shuttle(var/shuttle_type)
var/datum/shuttle/shuttle = shuttle_type var/datum/shuttle/shuttle = shuttle_type
@@ -170,13 +166,13 @@ SUBSYSTEM_DEF(shuttles)
error("Shuttle [S] was unable to find mothership [mothership]!") error("Shuttle [S] was unable to find mothership [mothership]!")
// Admin command to halt/resume overmap // Admin command to halt/resume overmap
// /datum/controller/subsystem/shuttles/proc/toggle_overmap(new_setting) /datum/controller/subsystem/shuttles/proc/toggle_overmap(new_setting)
// if(overmap_halted == new_setting) if(overmap_halted == new_setting)
// return return
// overmap_halted = !overmap_halted overmap_halted = !overmap_halted
// for(var/ship in ships) for(var/ship in ships)
// var/obj/effect/overmap/visitable/ship/ship_effect = ship var/obj/effect/overmap/visitable/ship/ship_effect = ship
// overmap_halted ? ship_effect.halt() : ship_effect.unhalt() overmap_halted ? ship_effect.halt() : ship_effect.unhalt()
/datum/controller/subsystem/shuttles/stat_entry() /datum/controller/subsystem/shuttles/stat_entry()
..("Shuttles:[process_shuttles.len]/[shuttles.len], Ships:[ships.len], L:[registered_shuttle_landmarks.len][overmap_halted ? ", HALT" : ""]") ..("Shuttles:[process_shuttles.len]/[shuttles.len], Ships:[ships.len], L:[registered_shuttle_landmarks.len][overmap_halted ? ", HALT" : ""]")

View File

@@ -9,6 +9,9 @@
/atom/proc/recursive_dir_set(var/atom/a, var/old_dir, var/new_dir) /atom/proc/recursive_dir_set(var/atom/a, var/old_dir, var/new_dir)
set_dir(new_dir) set_dir(new_dir)
/datum/proc/qdel_self()
qdel(src)
/proc/register_all_movement(var/event_source, var/listener) /proc/register_all_movement(var/event_source, var/listener)
GLOB.moved_event.register(event_source, listener, /atom/movable/proc/recursive_move) GLOB.moved_event.register(event_source, listener, /atom/movable/proc/recursive_move)
GLOB.dir_set_event.register(event_source, listener, /atom/proc/recursive_dir_set) GLOB.dir_set_event.register(event_source, listener, /atom/proc/recursive_dir_set)

View File

@@ -328,6 +328,9 @@ var/list/global/tank_gauge_cache = list()
/obj/item/weapon/tank/remove_air(amount) /obj/item/weapon/tank/remove_air(amount)
return air_contents.remove(amount) return air_contents.remove(amount)
/obj/item/weapon/tank/proc/remove_air_by_flag(flag, amount)
return air_contents.remove_by_flag(flag, amount)
/obj/item/weapon/tank/return_air() /obj/item/weapon/tank/return_air()
return air_contents return air_contents

View File

@@ -0,0 +1,14 @@
// We don't actually have a skills system, so return max skill for everything.
/mob/proc/get_skill_value(skill_path)
return SKILL_EXPERT
// A generic way of modifying success probabilities via skill values. Higher factor means skills have more effect. fail_chance is the chance at SKILL_NONE.
/mob/proc/skill_fail_chance(skill_path, fail_chance, no_more_fail = SKILL_EXPERT, factor = 1)
var/points = get_skill_value(skill_path)
if(points >= no_more_fail)
return 0
else
return fail_chance * 2 ** (factor*(SKILL_BASIC - points))
return FALSE // We don't actually have a skills system, so never fail.

View File

@@ -53,6 +53,12 @@ Changes desitnation area depending on current sector ship is in.
Currently updating is called in attack_hand(), until a better place is found. Currently updating is called in attack_hand(), until a better place is found.
Currently no modifications were made to interface to display availability of landing area in sector. Currently no modifications were made to interface to display availability of landing area in sector.
*************************************************************
Landable Ships
*************************************************************
Ship - Vessel that can move around on the overmap. It's entire z-level(s) "move" conceptually.
Shuttles - Vessel that can jump to shuttle landmarks. Its areas move by transition_turfs.
Landable Ship - Vessel that can do both. Sits at a special shuttle landmark for overmap movement mode.
************************************************************* *************************************************************
Guide to how make new sector Guide to how make new sector

View File

@@ -1,9 +1,19 @@
//Zlevel where overmap objects should be
#define OVERMAP_ZLEVEL 1
//How far from the edge of overmap zlevel could randomly placed objects spawn //How far from the edge of overmap zlevel could randomly placed objects spawn
#define OVERMAP_EDGE 7 #define OVERMAP_EDGE 2
#define SHIP_SIZE_TINY 1
#define SHIP_SIZE_SMALL 2
#define SHIP_SIZE_LARGE 3
//multipliers for max_speed to find 'slow' and 'fast' speeds for the ship
#define SHIP_SPEED_SLOW 1/(40 SECONDS)
#define SHIP_SPEED_FAST 3/(20 SECONDS)// 15 speed
#define OVERMAP_WEAKNESS_NONE 0
#define OVERMAP_WEAKNESS_FIRE 1
#define OVERMAP_WEAKNESS_EMP 2
#define OVERMAP_WEAKNESS_MINING 4
#define OVERMAP_WEAKNESS_EXPLOSIVE 8
//Dimension of overmap (squares 4 lyfe) //Dimension of overmap (squares 4 lyfe)
var/global/list/map_sectors = list() var/global/list/map_sectors = list()
@@ -17,6 +27,7 @@ var/global/list/map_sectors = list()
/turf/unsimulated/map /turf/unsimulated/map
icon = 'icons/turf/space.dmi' icon = 'icons/turf/space.dmi'
icon_state = "map" icon_state = "map"
initialized = FALSE // TODO - Fix unsimulated turf initialization so this override is not necessary!
/turf/unsimulated/map/edge /turf/unsimulated/map/edge
opacity = 1 opacity = 1
@@ -48,11 +59,7 @@ var/global/list/map_sectors = list()
I.pixel_x = 5*i - 2 I.pixel_x = 5*i - 2
if(x == global.using_map.overmap_size) if(x == global.using_map.overmap_size)
I.pixel_x = 5*i + 2 I.pixel_x = 5*i + 2
overlays += I add_overlay(I)
//list used to track which zlevels are being 'moved' by the proc below //list used to track which zlevels are being 'moved' by the proc below
var/list/moving_levels = list() var/list/moving_levels = list()
@@ -71,21 +78,20 @@ proc/toggle_move_stars(zlevel, direction)
if(!direction) if(!direction)
gen_dir = null gen_dir = null
if (moving_levels["zlevel"] != gen_dir) if (moving_levels["[zlevel]"] != gen_dir)
moving_levels["zlevel"] = gen_dir moving_levels["[zlevel]"] = gen_dir
for(var/x = 1 to world.maxx)
for(var/y = 1 to world.maxy)
var/turf/space/T = locate(x,y,zlevel)
if (istype(T))
if(!gen_dir)
T.icon_state = "[((T.x + T.y) ^ ~(T.x * T.y) + T.z) % 25]"
else
T.icon_state = "speedspace_[gen_dir]_[rand(1,15)]"
for(var/atom/movable/AM in T)
if (!AM.anchored)
AM.throw_at(get_step(T,reverse_direction(direction)), 5, 1)
var/list/spaceturfs = block(locate(1, 1, zlevel), locate(world.maxx, world.maxy, zlevel))
for(var/turf/space/T in spaceturfs)
if(!gen_dir)
T.icon_state = initial(T.icon_state)
else
T.icon_state = "speedspace_[gen_dir]_[rand(1,15)]"
for(var/atom/movable/AM in T)
if (AM.simulated && !AM.anchored)
AM.throw_at(get_step(T,reverse_direction(direction)), 5, 1)
CHECK_TICK
CHECK_TICK
/* /*
//list used to cache empty zlevels to avoid nedless map bloat //list used to cache empty zlevels to avoid nedless map bloat
var/list/cached_space = list() var/list/cached_space = list()

View File

@@ -21,11 +21,9 @@
if(known) if(known)
//layer = ABOVE_LIGHTING_LAYER //layer = ABOVE_LIGHTING_LAYER
plane = PLANE_LIGHTING_ABOVE plane = PLANE_LIGHTING_ABOVE
// TODO - Leshana HELM for(var/obj/machinery/computer/ship/helm/H in global.machines)
// for(var/obj/machinery/computer/ship/helm/H in global.machines) H.get_known_sectors()
// H.get_known_sectors()
/*
TODO - Leshana - No need for this, we don't have skyboxes
/obj/effect/overmap/Crossed(var/obj/effect/overmap/visitable/other) /obj/effect/overmap/Crossed(var/obj/effect/overmap/visitable/other)
if(istype(other)) if(istype(other))
for(var/obj/effect/overmap/visitable/O in loc) for(var/obj/effect/overmap/visitable/O in loc)
@@ -36,4 +34,3 @@ TODO - Leshana - No need for this, we don't have skyboxes
SSskybox.rebuild_skyboxes(other.map_z) SSskybox.rebuild_skyboxes(other.map_z)
for(var/obj/effect/overmap/visitable/O in loc) for(var/obj/effect/overmap/visitable/O in loc)
SSskybox.rebuild_skyboxes(O.map_z) SSskybox.rebuild_skyboxes(O.map_z)
*/

View File

@@ -0,0 +1,179 @@
#define waypoint_sector(waypoint) map_sectors["[waypoint.z]"]
/datum/shuttle/autodock/overmap
warmup_time = 10
var/range = 0 //how many overmap tiles can shuttle go, for picking destinations and returning.
var/fuel_consumption = 0 //Amount of moles of gas consumed per trip; If zero, then shuttle is magic and does not need fuel
var/list/obj/structure/fuel_port/fuel_ports //the fuel ports of the shuttle (but usually just one)
var/obj/effect/overmap/visitable/ship/landable/myship //my overmap ship object
category = /datum/shuttle/autodock/overmap
var/skill_needed = SKILL_BASIC
var/operator_skill = SKILL_BASIC
/datum/shuttle/autodock/overmap/New(var/_name, var/obj/effect/shuttle_landmark/start_waypoint)
..(_name, start_waypoint)
refresh_fuel_ports_list()
/datum/shuttle/autodock/overmap/Destroy()
. = ..()
myship = null
/datum/shuttle/autodock/overmap/proc/refresh_fuel_ports_list() //loop through all
fuel_ports = list()
for(var/area/A in shuttle_area)
for(var/obj/structure/fuel_port/fuel_port_in_area in A)
fuel_port_in_area.parent_shuttle = src
fuel_ports += fuel_port_in_area
/datum/shuttle/autodock/overmap/fuel_check()
if(!src.try_consume_fuel()) //insufficient fuel
for(var/area/A in shuttle_area)
for(var/mob/living/M in A)
M.show_message("<spawn class='warning'>You hear the shuttle engines sputter... perhaps it doesn't have enough fuel?", 1,
"<spawn class='warning'>The shuttle shakes but fails to take off.", 2)
return 0 //failure!
return 1 //sucess, continue with launch
/datum/shuttle/autodock/overmap/proc/can_go()
if(!next_location)
return FALSE
if(moving_status == SHUTTLE_INTRANSIT)
return FALSE //already going somewhere, current_location may be an intransit location instead of in a sector
var/our_sector = waypoint_sector(current_location)
if(!our_sector && myship?.landmark && next_location == myship.landmark)
return TRUE //We're not on the overmap yet (admin spawned probably), and we're trying to hook up with our openspace sector
return get_dist(our_sector, waypoint_sector(next_location)) <= range
/datum/shuttle/autodock/overmap/can_launch()
return ..() && can_go()
/datum/shuttle/autodock/overmap/can_force()
return ..() && can_go()
/datum/shuttle/autodock/overmap/get_travel_time()
var/distance_mod = get_dist(waypoint_sector(current_location),waypoint_sector(next_location))
var/skill_mod = 0.2*(skill_needed - operator_skill)
return move_time * (1 + distance_mod + skill_mod)
/datum/shuttle/autodock/overmap/process_launch()
if(prob(10*max(0, skill_needed - operator_skill)))
var/places = get_possible_destinations()
var/place = pick(places)
set_destination(places[place])
..()
/datum/shuttle/autodock/overmap/proc/set_destination(var/obj/effect/shuttle_landmark/A)
if(A != current_location)
next_location = A
/datum/shuttle/autodock/overmap/proc/get_possible_destinations()
var/list/res = list()
var/our_sector = waypoint_sector(current_location)
if(!our_sector && myship?.landmark)
res["Perform Test Jump"] = myship.landmark
return res //We're not on the overmap, maybe an admin spawned us on a non-sector map. We're broken until we connect to our space z-level.
for (var/obj/effect/overmap/visitable/S in range(get_turf(our_sector), range))
var/list/waypoints = S.get_waypoints(name)
for(var/obj/effect/shuttle_landmark/LZ in waypoints)
if(LZ.is_valid(src))
res["[waypoints[LZ]] - [LZ.name]"] = LZ
return res
/datum/shuttle/autodock/overmap/get_location_name()
if(moving_status == SHUTTLE_INTRANSIT)
return "In transit"
return "[waypoint_sector(current_location)] - [current_location]"
/datum/shuttle/autodock/overmap/get_destination_name()
if(!next_location)
return "None"
return "[waypoint_sector(next_location)] - [next_location]"
/datum/shuttle/autodock/overmap/proc/try_consume_fuel() //returns 1 if sucessful, returns 0 if error (like insufficient fuel)
if(!fuel_consumption)
return 1 //shuttles with zero fuel consumption are magic and can always launch
if(!fuel_ports.len)
return 0 //Nowhere to get fuel from
var/list/obj/item/weapon/tank/fuel_tanks = list()
for(var/obj/structure/FP in fuel_ports) //loop through fuel ports and assemble list of all fuel tanks
var/obj/item/weapon/tank/FT = locate() in FP
if(FT)
fuel_tanks += FT
if(!fuel_tanks.len)
return 0 //can't launch if you have no fuel TANKS in the ports
var/total_flammable_gas_moles = 0
for(var/obj/item/weapon/tank/FT in fuel_tanks)
total_flammable_gas_moles += FT.air_contents.get_by_flag(XGM_GAS_FUEL)
if(total_flammable_gas_moles < fuel_consumption) //not enough fuel
return 0
// We are going to succeed if we got to here, so start consuming that fuel
var/fuel_to_consume = fuel_consumption
for(var/obj/item/weapon/tank/FT in fuel_tanks) //loop through tanks, consume their fuel one by one
var/fuel_available = FT.air_contents.get_by_flag(XGM_GAS_FUEL)
if(!fuel_available) // Didn't even have fuel.
continue
if(fuel_available >= fuel_to_consume)
FT.remove_air_by_flag(XGM_GAS_FUEL, fuel_to_consume)
return 1 //ALL REQUIRED FUEL HAS BEEN CONSUMED, GO FOR LAUNCH!
else //this tank doesn't have enough to launch shuttle by itself, so remove all its fuel, then continue loop
fuel_to_consume -= fuel_available
FT.remove_air_by_flag(XGM_GAS_FUEL, fuel_available)
/obj/structure/fuel_port
name = "fuel port"
desc = "The fuel input port of the shuttle. Holds one fuel tank. Use a crowbar to open and close it."
icon = 'icons/turf/shuttle_parts.dmi'
icon_state = "fuel_port"
density = 0
anchored = 1
var/icon_closed = "fuel_port"
var/icon_empty = "fuel_port_empty"
var/icon_full = "fuel_port_full"
var/opened = 0
var/parent_shuttle
/obj/structure/fuel_port/Initialize()
. = ..()
new /obj/item/weapon/tank/phoron(src)
/obj/structure/fuel_port/attack_hand(mob/user as mob)
if(!opened)
to_chat(user, "<spawn class='notice'>The door is secured tightly. You'll need a crowbar to open it.")
return
else if(contents.len > 0)
user.put_in_hands(contents[1])
update_icon()
/obj/structure/fuel_port/update_icon()
if(opened)
if(contents.len > 0)
icon_state = icon_full
else
icon_state = icon_empty
else
icon_state = icon_closed
..()
/obj/structure/fuel_port/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(W.is_crowbar())
if(opened)
to_chat(user, "<spawn class='notice'>You tightly shut \the [src] door.")
playsound(src.loc, 'sound/effects/locker_close.ogg', 25, 0, -3)
opened = 0
else
to_chat(user, "<spawn class='notice'>You open up \the [src] door.")
playsound(src.loc, 'sound/effects/locker_open.ogg', 15, 1, -3)
opened = 1
else if(istype(W,/obj/item/weapon/tank))
if(!opened)
to_chat(user, "<spawn class='warning'>\The [src] door is still closed!")
return
if(contents.len == 0)
user.unEquip(W, src)
update_icon()
// Walls hide stuff inside them, but we want to be visible.
/obj/structure/fuel_port/hide()
return

View File

@@ -50,9 +50,11 @@
//This is called later in the init order by SSshuttles to populate sector objects. Importantly for subtypes, shuttles will be created by then. //This is called later in the init order by SSshuttles to populate sector objects. Importantly for subtypes, shuttles will be created by then.
/obj/effect/overmap/visitable/proc/populate_sector_objects() /obj/effect/overmap/visitable/proc/populate_sector_objects()
// TODO - Leshana - Implement /obj/effect/overmap/visitable/proc/get_areas()
///obj/effect/overmap/visitable/proc/get_areas() . = list()
// return get_filtered_areas(list(/proc/area_belongs_to_zlevels = map_z)) for(var/area/A)
if (A.z in map_z)
. += A
/obj/effect/overmap/visitable/proc/find_z_levels() /obj/effect/overmap/visitable/proc/find_z_levels()
map_z = GetConnectedZlevels(z) map_z = GetConnectedZlevels(z)
@@ -117,7 +119,7 @@
return 1 return 1
testing("Building overmap...") testing("Building overmap...")
world.maxz++ world.increment_max_z()
global.using_map.overmap_z = world.maxz global.using_map.overmap_z = world.maxz
testing("Putting overmap on [global.using_map.overmap_z]") testing("Putting overmap on [global.using_map.overmap_z]")

View File

@@ -0,0 +1,104 @@
/*
**
** HELLO! DON'T COPY THINGS FROM HERE - READ THIS!
**
** The ship machines/computers ported from baystation expect certain procs and infrastruture that we don't have.
** I /could/ just port those computers to our code, but I actually *like* that infrastructure. But I
** don't have time (yet) to implement it fully in our codebase, so I'm shimming it here experimentally as a test
** bed for later implementing it on /obj/machinery and /obj/machinery/computer for everything. ~Leshana (March 2020)
*/
//
// Power
//
// This will have this machine have its area eat this much power next tick, and not afterwards. Do not use for continued power draw.
/obj/machinery/proc/use_power_oneoff(var/amount, var/chan = -1)
return use_power(amount, chan)
// Change one of the power consumption vars
/obj/machinery/proc/change_power_consumption(new_power_consumption, use_power_mode = USE_POWER_IDLE)
switch(use_power_mode)
if(USE_POWER_IDLE)
idle_power_usage = new_power_consumption
if(USE_POWER_ACTIVE)
active_power_usage = new_power_consumption
// No need to do anything else in our power scheme.
// Defining directly here to avoid conflicts with existing set_broken procs in our codebase that behave differently.
/obj/machinery/atmospherics/unary/engine/proc/set_broken(var/new_state, var/cause)
if(!(stat & BROKEN) == !new_state)
return // Nothing changed
stat ^= BROKEN
update_icon()
//
// Compoenents
//
/obj/machinery/proc/total_component_rating_of_type(var/part_type)
. = 0
for(var/thing in component_parts)
if(istype(thing, part_type))
var/obj/item/weapon/stock_parts/part = thing
. += part.rating
// Now isn't THIS a cool idea?
// for(var/path in uncreated_component_parts)
// if(ispath(path, part_type))
// var/obj/item/weapon/stock_parts/comp = path
// . += initial(comp.rating) * uncreated_component_parts[path]
//
// Skills
//
/obj/machinery/computer/ship
var/core_skill = /datum/skill/devices //The skill used for skill checks for this machine (mostly so subtypes can use different skills).
//
// Topic
//
/obj/machinery/computer/ship/proc/DefaultTopicState()
return global.default_state
/obj/machinery/computer/ship/Topic(var/href, var/href_list = list(), var/datum/topic_state/state)
if((. = ..()))
return
state = state || DefaultTopicState() || global.default_state
if(CanUseTopic(usr, state, href_list) == STATUS_INTERACTIVE)
CouldUseTopic(usr)
return OnTopic(usr, href_list, state)
CouldNotUseTopic(usr)
return TRUE
/obj/machinery/computer/ship/proc/OnTopic(var/mob/user, var/href_list, var/datum/topic_state/state)
return TOPIC_NOACTION
//
// Interaction
//
// If you want to have interface interactions handled for you conveniently, use this.
// Return TRUE for handled.
// If you perform direct interactions in here, you are responsible for ensuring that full interactivity checks have been made (i.e CanInteract).
// The checks leading in to here only guarantee that the user should be able to view a UI.
/obj/machinery/computer/ship/proc/interface_interact(var/mob/user)
ui_interact(user)
return TRUE
/obj/machinery/computer/ship/attack_ai(mob/user)
if(CanUseTopic(user, DefaultTopicState()) > STATUS_CLOSE)
return interface_interact(user)
// After a recent rework this should mostly be safe.
/obj/machinery/computer/ship/attack_ghost(mob/user)
interface_interact(user)
// If you don't call parent in this proc, you must make all appropriate checks yourself.
// If you do, you must respect the return value.
/obj/machinery/computer/ship/attack_hand(mob/user)
if((. = ..()))
return
if(CanUseTopic(user, DefaultTopicState()) > STATUS_CLOSE)
return interface_interact(user)

View File

@@ -1,46 +1,24 @@
//Engine control and monitoring console //Engine control and monitoring console
/obj/machinery/computer/engines /obj/machinery/computer/ship/engines
name = "engine control console" name = "engine control console"
icon_keyboard = "tech_key" icon_keyboard = "tech_key"
icon_screen = "id" icon_screen = "engines"
var/state = "status" var/display_state = "status"
var/list/engines = list()
var/obj/effect/map/ship/linked
/obj/machinery/computer/engines/Initialize() /obj/machinery/computer/ship/engines/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
. = ..()
linked = map_sectors["[z]"]
if (linked)
if (!linked.eng_control)
linked.eng_control = src
testing("Engines console at level [z] found a corresponding overmap object '[linked.name]'.")
else
testing("Engines console at level [z] was unable to find a corresponding overmap object.")
for(var/datum/ship_engine/E in engines)
if (E.zlevel == z && !(E in engines))
engines += E
/obj/machinery/computer/engines/attack_hand(var/mob/user as mob)
if(..())
user.unset_machine()
return
if(!isAI(user))
user.set_machine(src)
ui_interact(user)
/obj/machinery/computer/engines/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
if(!linked) if(!linked)
display_reconnect_dialog(user, "ship control systems")
return return
var/data[0] var/data[0]
data["state"] = state data["state"] = display_state
data["global_state"] = linked.engines_state
data["global_limit"] = round(linked.thrust_limit*100)
var/total_thrust = 0
var/list/enginfo[0] var/list/enginfo[0]
for(var/datum/ship_engine/E in engines) for(var/datum/ship_engine/E in linked.engines)
var/list/rdata[0] var/list/rdata[0]
rdata["eng_type"] = E.name rdata["eng_type"] = E.name
rdata["eng_on"] = E.is_on() rdata["eng_on"] = E.is_on()
@@ -48,54 +26,70 @@
rdata["eng_thrust_limiter"] = round(E.get_thrust_limit()*100) rdata["eng_thrust_limiter"] = round(E.get_thrust_limit()*100)
rdata["eng_status"] = E.get_status() rdata["eng_status"] = E.get_status()
rdata["eng_reference"] = "\ref[E]" rdata["eng_reference"] = "\ref[E]"
total_thrust += E.get_thrust()
enginfo.Add(list(rdata)) enginfo.Add(list(rdata))
data["engines_info"] = enginfo data["engines_info"] = enginfo
data["total_thrust"] = total_thrust
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui) if (!ui)
ui = new(user, src, ui_key, "engines_control.tmpl", "[linked.name] Engines Control", 380, 530) ui = new(user, src, ui_key, "engines_control.tmpl", "[linked.name] Engines Control", 390, 530)
ui.set_initial_data(data) ui.set_initial_data(data)
ui.open() ui.open()
ui.set_auto_update(1) ui.set_auto_update(1)
/obj/machinery/computer/engines/Topic(href, href_list) /obj/machinery/computer/ship/engines/OnTopic(var/mob/user, var/list/href_list, state)
if(..()) if(..())
return 1 return ..()
if(href_list["state"]) if(href_list["state"])
state = href_list["state"] display_state = href_list["state"]
return TOPIC_REFRESH
if(href_list["global_toggle"])
linked.engines_state = !linked.engines_state
for(var/datum/ship_engine/E in linked.engines)
if(linked.engines_state == !E.is_on())
E.toggle()
return TOPIC_REFRESH
if(href_list["set_global_limit"])
var/newlim = input("Input new thrust limit (0..100%)", "Thrust limit", linked.thrust_limit*100) as num
if(!CanInteract(user, state))
return TOPIC_NOACTION
linked.thrust_limit = CLAMP(newlim/100, 0, 1)
for(var/datum/ship_engine/E in linked.engines)
E.set_thrust_limit(linked.thrust_limit)
return TOPIC_REFRESH
if(href_list["global_limit"])
linked.thrust_limit = CLAMP(linked.thrust_limit + text2num(href_list["global_limit"]), 0, 1)
for(var/datum/ship_engine/E in linked.engines)
E.set_thrust_limit(linked.thrust_limit)
return TOPIC_REFRESH
if(href_list["engine"]) if(href_list["engine"])
if(href_list["set_limit"]) if(href_list["set_limit"])
var/datum/ship_engine/E = locate(href_list["engine"]) var/datum/ship_engine/E = locate(href_list["engine"])
var/newlim = input("Input new thrust limit (0..100)", "Thrust limit", E.get_thrust_limit()) as num var/newlim = input("Input new thrust limit (0..100)", "Thrust limit", E.get_thrust_limit()) as num
if(!CanInteract(user, state))
return
var/limit = CLAMP(newlim/100, 0, 1) var/limit = CLAMP(newlim/100, 0, 1)
if(E) if(istype(E))
E.set_thrust_limit(limit) E.set_thrust_limit(limit)
return TOPIC_REFRESH
if(href_list["limit"]) if(href_list["limit"])
var/datum/ship_engine/E = locate(href_list["engine"]) var/datum/ship_engine/E = locate(href_list["engine"])
var/limit = CLAMP(E.get_thrust_limit() + text2num(href_list["limit"]), 0, 1) var/limit = CLAMP(E.get_thrust_limit() + text2num(href_list["limit"]), 0, 1)
if(E) if(istype(E))
E.set_thrust_limit(limit) E.set_thrust_limit(limit)
return TOPIC_REFRESH
if(href_list["toggle"]) if(href_list["toggle"])
var/datum/ship_engine/E = locate(href_list["engine"]) var/datum/ship_engine/E = locate(href_list["engine"])
if(E) if(istype(E))
E.toggle() E.toggle()
return TOPIC_REFRESH
add_fingerprint(usr) return TOPIC_REFRESH
updateUsrDialog() return TOPIC_NOACTION
/obj/machinery/computer/engines/proc/burn()
if(engines.len == 0)
return 0
var/res = 0
for(var/datum/ship_engine/E in engines)
res |= E.burn()
return res
/obj/machinery/computer/engines/proc/get_total_thrust()
for(var/datum/ship_engine/E in engines)
. += E.get_thrust()

View File

@@ -1,151 +1,188 @@
/obj/machinery/computer/helm // LEGACY_RECORD_STRUCTURE(all_waypoints, waypoint)
GLOBAL_LIST_EMPTY(all_waypoints)
/datum/computer_file/data/waypoint
var/list/fields
filetype = "WPT"
/datum/computer_file/data/waypoint/New()
..()
fields = list()
GLOB.all_waypoints.Add(src)
/datum/computer_file/data/waypoint/Destroy()
. = ..()
GLOB.all_waypoints.Remove(src);
// End LEGACY_RECORD_STRUCTURE(all_waypoints, waypoint)
/obj/machinery/computer/ship/helm
name = "helm control console" name = "helm control console"
icon_keyboard = "med_key" icon_keyboard = "teleport_key"
icon_screen = "id" icon_screen = "helm"
var/state = "status" light_color = "#7faaff"
var/obj/effect/map/ship/linked //connected overmap object core_skill = /datum/skill/pilot
var/autopilot = 0 var/autopilot = 0
var/manual_control = 0
var/list/known_sectors = list() var/list/known_sectors = list()
var/dx //desitnation var/dx //desitnation
var/dy //coordinates var/dy //coordinates
var/speedlimit = 1/(20 SECONDS) //top speed for autopilot, 5
var/accellimit = 0.001 //manual limiter for acceleration
req_one_access = list(access_pilot)
/obj/machinery/computer/helm/Initialize() /obj/machinery/computer/ship/helm/Initialize()
. = ..() . = ..()
linked = map_sectors["[z]"] get_known_sectors()
if (linked)
if(!linked.nav_control)
linked.nav_control = src
testing("Helm console at level [z] found a corresponding overmap object '[linked.name]'.")
else
testing("Helm console at level [z] was unable to find a corresponding overmap object.")
for(var/level in map_sectors) /obj/machinery/computer/ship/helm/proc/get_known_sectors()
var/obj/effect/map/sector/S = map_sectors["[level]"] var/area/overmap/map = locate() in world
if (istype(S) && S.always_known) for(var/obj/effect/overmap/visitable/sector/S in map)
var/datum/data/record/R = new() if (S.known)
var/datum/computer_file/data/waypoint/R = new()
R.fields["name"] = S.name R.fields["name"] = S.name
R.fields["x"] = S.x R.fields["x"] = S.x
R.fields["y"] = S.y R.fields["y"] = S.y
known_sectors += R known_sectors[S.name] = R
/obj/machinery/computer/helm/process() /obj/machinery/computer/ship/helm/process()
..() ..()
if (autopilot && dx && dy) if (autopilot && dx && dy)
var/turf/T = locate(dx,dy,1) var/turf/T = locate(dx,dy,global.using_map.overmap_z)
if(linked.loc == T) if(linked.loc == T)
if(linked.is_still()) if(linked.is_still())
autopilot = 0 autopilot = 0
else else
linked.decelerate() linked.decelerate()
var/brake_path = linked.get_brake_path()
if(get_dist(linked.loc, T) > brake_path)
linked.accelerate(get_dir(linked.loc, T))
else else
linked.decelerate() var/brake_path = linked.get_brake_path()
var/direction = get_dir(linked.loc, T)
var/acceleration = min(linked.get_acceleration(), accellimit)
var/speed = linked.get_speed()
var/heading = linked.get_heading()
// Destination is current grid or speedlimit is exceeded
if ((get_dist(linked.loc, T) <= brake_path) || speed > speedlimit)
linked.decelerate()
// Heading does not match direction
else if (heading & ~direction)
linked.accelerate(turn(heading & ~direction, 180), accellimit)
// All other cases, move toward direction
else if (speed + acceleration <= speedlimit)
linked.accelerate(direction, accellimit)
linked.operator_skill = null//if this is on you can't dodge meteors
return return
/obj/machinery/computer/helm/relaymove(var/mob/user, direction) /obj/machinery/computer/ship/helm/relaymove(var/mob/user, direction)
if(manual_control && linked) if(viewing_overmap(user) && linked)
linked.relaymove(user,direction) if(prob(user.skill_fail_chance(/datum/skill/pilot, 50, linked.skill_needed, factor = 1)))
direction = turn(direction,pick(90,-90))
linked.relaymove(user, direction, accellimit)
return 1 return 1
/obj/machinery/computer/helm/check_eye(var/mob/user as mob) /obj/machinery/computer/ship/helm/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
if (!manual_control)
return -1
if (!get_dist(user, src) > 1 || user.blinded || !linked )
return -1
return 0
/obj/machinery/computer/helm/attack_hand(var/mob/user as mob)
if(..())
user.unset_machine()
manual_control = 0
return
if(!isAI(user))
user.set_machine(src)
if(linked)
user.reset_view(linked)
ui_interact(user)
/obj/machinery/computer/helm/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
if(!linked)
return
var/data[0] var/data[0]
data["state"] = state
data["sector"] = linked.current_sector ? linked.current_sector.name : "Deep Space" if(!linked)
data["sector_info"] = linked.current_sector ? linked.current_sector.desc : "Not Available" display_reconnect_dialog(user, "helm")
data["s_x"] = linked.x else
data["s_y"] = linked.y var/turf/T = get_turf(linked)
data["dest"] = dy && dx var/obj/effect/overmap/visitable/sector/current_sector = locate() in T
data["d_x"] = dx
data["d_y"] = dy
data["speed"] = linked.get_speed()
data["accel"] = round(linked.get_acceleration())
data["heading"] = linked.get_heading() ? dir2angle(linked.get_heading()) : 0
data["autopilot"] = autopilot
data["manual_control"] = manual_control
var/list/locations[0] data["sector"] = current_sector ? current_sector.name : "Deep Space"
for (var/datum/data/record/R in known_sectors) data["sector_info"] = current_sector ? current_sector.desc : "Not Available"
var/list/rdata[0] data["landed"] = linked.get_landed_info()
rdata["name"] = R.fields["name"] data["s_x"] = linked.x
rdata["x"] = R.fields["x"] data["s_y"] = linked.y
rdata["y"] = R.fields["y"] data["dest"] = dy && dx
rdata["reference"] = "\ref[R]" data["d_x"] = dx
locations.Add(list(rdata)) data["d_y"] = dy
data["speedlimit"] = speedlimit ? speedlimit*1000 : "Halted"
data["accel"] = min(round(linked.get_acceleration()*1000, 0.01),accellimit*1000)
data["heading"] = linked.get_heading_degrees()
data["autopilot"] = autopilot
data["manual_control"] = viewing_overmap(user)
data["canburn"] = linked.can_burn()
data["accellimit"] = accellimit*1000
data["locations"] = locations var/speed = round(linked.get_speed()*1000, 0.01)
if(linked.get_speed() < SHIP_SPEED_SLOW)
speed = "<span class='good'>[speed]</span>"
if(linked.get_speed() > SHIP_SPEED_FAST)
speed = "<span class='average'>[speed]</span>"
data["speed"] = speed
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) if(linked.get_speed())
if (!ui) data["ETAnext"] = "[round(linked.ETA()/10)] seconds"
ui = new(user, src, ui_key, "helm.tmpl", "[linked.name] Helm Control", 380, 530) else
ui.set_initial_data(data) data["ETAnext"] = "N/A"
ui.open()
ui.set_auto_update(1)
/obj/machinery/computer/helm/Topic(href, href_list) var/list/locations[0]
for (var/key in known_sectors)
var/datum/computer_file/data/waypoint/R = known_sectors[key]
var/list/rdata[0]
rdata["name"] = R.fields["name"]
rdata["x"] = R.fields["x"]
rdata["y"] = R.fields["y"]
rdata["reference"] = "\ref[R]"
locations.Add(list(rdata))
data["locations"] = locations
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "helm.tmpl", "[linked.name] Helm Control", 565, 545)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
/obj/machinery/computer/ship/helm/OnTopic(var/mob/user, var/list/href_list, state)
if(..()) if(..())
return 1 return TOPIC_HANDLED
if (!linked) if(!linked)
return return TOPIC_HANDLED
if (href_list["add"]) if (href_list["add"])
var/datum/data/record/R = new() var/datum/computer_file/data/waypoint/R = new()
var/sec_name = input("Input naviation entry name", "New navigation entry", "Sector #[known_sectors.len]") as text var/sec_name = input("Input naviation entry name", "New navigation entry", "Sector #[known_sectors.len]") as text
if(!CanInteract(user,state))
return TOPIC_NOACTION
if(!sec_name) if(!sec_name)
sec_name = "Sector #[known_sectors.len]" sec_name = "Sector #[known_sectors.len]"
R.fields["name"] = sec_name R.fields["name"] = sec_name
if(sec_name in known_sectors)
to_chat(user, "<span class='warning'>Sector with that name already exists, please input a different name.</span>")
return TOPIC_REFRESH
switch(href_list["add"]) switch(href_list["add"])
if("current") if("current")
R.fields["x"] = linked.x R.fields["x"] = linked.x
R.fields["y"] = linked.y R.fields["y"] = linked.y
if("new") if("new")
var/newx = input("Input new entry x coordinate", "Coordinate input", linked.x) as num var/newx = input("Input new entry x coordinate", "Coordinate input", linked.x) as num
R.fields["x"] = CLAMP(newx, 1, world.maxx) if(!CanInteract(user,state))
return TOPIC_REFRESH
var/newy = input("Input new entry y coordinate", "Coordinate input", linked.y) as num var/newy = input("Input new entry y coordinate", "Coordinate input", linked.y) as num
if(!CanInteract(user,state))
return TOPIC_NOACTION
R.fields["x"] = CLAMP(newx, 1, world.maxx)
R.fields["y"] = CLAMP(newy, 1, world.maxy) R.fields["y"] = CLAMP(newy, 1, world.maxy)
known_sectors += R known_sectors[sec_name] = R
if (href_list["remove"]) if (href_list["remove"])
var/datum/data/record/R = locate(href_list["remove"]) var/datum/computer_file/data/waypoint/R = locate(href_list["remove"])
known_sectors.Remove(R) if(R)
known_sectors.Remove(R.fields["name"])
qdel(R)
if (href_list["setx"]) if (href_list["setx"])
var/newx = input("Input new destiniation x coordinate", "Coordinate input", dx) as num|null var/newx = input("Input new destiniation x coordinate", "Coordinate input", dx) as num|null
if(!CanInteract(user,state))
return
if (newx) if (newx)
dx = CLAMP(newx, 1, world.maxx) dx = CLAMP(newx, 1, world.maxx)
if (href_list["sety"]) if (href_list["sety"])
var/newy = input("Input new destiniation y coordinate", "Coordinate input", dy) as num|null var/newy = input("Input new destiniation y coordinate", "Coordinate input", dy) as num|null
if(!CanInteract(user,state))
return
if (newy) if (newy)
dy = CLAMP(newy, 1, world.maxy) dy = CLAMP(newy, 1, world.maxy)
@@ -157,9 +194,20 @@
dx = 0 dx = 0
dy = 0 dy = 0
if (href_list["speedlimit"])
var/newlimit = input("Input new speed limit for autopilot (0 to brake)", "Autopilot speed limit", speedlimit*1000) as num|null
if(newlimit)
speedlimit = CLAMP(newlimit/1000, 0, 100)
if (href_list["accellimit"])
var/newlimit = input("Input new acceleration limit", "Acceleration limit", accellimit*1000) as num|null
if(newlimit)
accellimit = max(newlimit/1000, 0)
if (href_list["move"]) if (href_list["move"])
var/ndir = text2num(href_list["move"]) var/ndir = text2num(href_list["move"])
linked.relaymove(usr, ndir) if(prob(user.skill_fail_chance(/datum/skill/pilot, 50, linked.skill_needed, factor = 1)))
ndir = turn(ndir,pick(90,-90))
linked.relaymove(user, ndir, accellimit)
if (href_list["brake"]) if (href_list["brake"])
linked.decelerate() linked.decelerate()
@@ -168,10 +216,71 @@
autopilot = !autopilot autopilot = !autopilot
if (href_list["manual"]) if (href_list["manual"])
manual_control = !manual_control viewing_overmap(user) ? unlook(user) : look(user)
if (href_list["state"]) add_fingerprint(user)
state = href_list["state"]
add_fingerprint(usr)
updateUsrDialog() updateUsrDialog()
/obj/machinery/computer/ship/navigation
name = "navigation console"
icon_keyboard = "generic_key"
icon_screen = "helm"
/obj/machinery/computer/ship/navigation/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
if(!linked)
display_reconnect_dialog(user, "Navigation")
return
var/data[0]
var/turf/T = get_turf(linked)
var/obj/effect/overmap/visitable/sector/current_sector = locate() in T
data["sector"] = current_sector ? current_sector.name : "Deep Space"
data["sector_info"] = current_sector ? current_sector.desc : "Not Available"
data["s_x"] = linked.x
data["s_y"] = linked.y
data["speed"] = round(linked.get_speed()*1000, 0.01)
data["accel"] = round(linked.get_acceleration()*1000, 0.01)
data["heading"] = linked.get_heading_degrees()
data["viewing"] = viewing_overmap(user)
if(linked.get_speed())
data["ETAnext"] = "[round(linked.ETA()/10)] seconds"
else
data["ETAnext"] = "N/A"
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "nav.tmpl", "[linked.name] Navigation Screen", 380, 530)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
/obj/machinery/computer/ship/navigation/OnTopic(var/mob/user, var/list/href_list)
if(..())
return TOPIC_HANDLED
if (!linked)
return TOPIC_NOACTION
if (href_list["viewing"])
viewing_overmap(user) ? unlook(user) : look(user)
return TOPIC_REFRESH
/obj/machinery/computer/ship/navigation/telescreen //little hacky but it's only used on one ship so it should be okay
icon_state = "tele_nav"
icon_keyboard = null
icon_screen = null
density = 0
/obj/machinery/computer/ship/navigation/telescreen/update_icon()
if(stat & NOPOWER || stat & BROKEN)
icon_state = "tele_off"
set_light(0)
else
icon_state = "tele_nav"
set_light(light_range_on, light_power_on)
..()

View File

@@ -0,0 +1,226 @@
/obj/machinery/computer/ship/sensors
name = "sensors console"
icon_keyboard = "teleport_key"
icon_screen = "teleport"
light_color = "#77fff8"
extra_view = 4
var/obj/machinery/shipsensors/sensors
/obj/machinery/computer/ship/sensors/attempt_hook_up(obj/effect/overmap/visitable/ship/sector)
if(!(. = ..()))
return
find_sensors()
/obj/machinery/computer/ship/sensors/proc/find_sensors()
if(!linked)
return
for(var/obj/machinery/shipsensors/S in global.machines)
if(linked.check_ownership(S))
sensors = S
break
/obj/machinery/computer/ship/sensors/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
if(!linked)
display_reconnect_dialog(user, "sensors")
return
var/data[0]
data["viewing"] = viewing_overmap(user)
if(sensors)
data["on"] = sensors.use_power
data["range"] = sensors.range
data["health"] = sensors.health
data["max_health"] = sensors.max_health
data["heat"] = sensors.heat
data["critical_heat"] = sensors.critical_heat
if(sensors.health == 0)
data["status"] = "DESTROYED"
else if(!sensors.powered())
data["status"] = "NO POWER"
else if(!sensors.in_vacuum())
data["status"] = "VACUUM SEAL BROKEN"
else
data["status"] = "OK"
var/list/contacts = list()
for(var/obj/effect/overmap/O in view(7,linked))
if(linked == O)
continue
if(!O.scannable)
continue
var/bearing = round(90 - ATAN2(O.x - linked.x, O.y - linked.y),5)
if(bearing < 0)
bearing += 360
contacts.Add(list(list("name"=O.name, "ref"="\ref[O]", "bearing"=bearing)))
if(contacts.len)
data["contacts"] = contacts
else
data["status"] = "MISSING"
data["range"] = "N/A"
data["on"] = 0
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "shipsensors.tmpl", "[linked.name] Sensors Control", 420, 530, src)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
/obj/machinery/computer/ship/sensors/OnTopic(var/mob/user, var/list/href_list, state)
if(..())
return TOPIC_HANDLED
if (!linked)
return TOPIC_NOACTION
if (href_list["viewing"])
if(user && !isAI(user))
viewing_overmap(user) ? unlook(user) : look(user)
return TOPIC_REFRESH
if (href_list["link"])
find_sensors()
return TOPIC_REFRESH
if(sensors)
if (href_list["range"])
var/nrange = input("Set new sensors range", "Sensor range", sensors.range) as num|null
if(!CanInteract(user,state))
return TOPIC_NOACTION
if (nrange)
sensors.set_range(CLAMP(nrange, 1, world.view))
return TOPIC_REFRESH
if (href_list["toggle"])
sensors.toggle()
return TOPIC_REFRESH
if (href_list["scan"])
var/obj/effect/overmap/O = locate(href_list["scan"])
if(istype(O) && !QDELETED(O) && (O in view(7,linked)))
playsound(loc, "sound/machines/dotprinter.ogg", 30, 1)
new/obj/item/weapon/paper/(get_turf(src), O.get_scan_data(user), "paper (Sensor Scan - [O])")
return TOPIC_HANDLED
/obj/machinery/computer/ship/sensors/process()
..()
if(!linked)
return
if(sensors && sensors.use_power && sensors.powered())
var/sensor_range = round(sensors.range*1.5) + 1
linked.set_light(sensor_range + 0.5, 4)
else
linked.set_light(0)
/obj/machinery/shipsensors
name = "sensors suite"
desc = "Long range gravity scanner with various other sensors, used to detect irregularities in surrounding space. Can only run in vacuum to protect delicate quantum BS elements."
icon = 'icons/obj/stationobjs.dmi'
icon_state = "sensors"
anchored = 1
var/max_health = 200
var/health = 200
var/critical_heat = 50 // sparks and takes damage when active & above this heat
var/heat_reduction = 1.5 // mitigates this much heat per tick
var/heat = 0
var/range = 1
idle_power_usage = 5000
/obj/machinery/shipsensors/attackby(obj/item/weapon/W, mob/user)
var/damage = max_health - health
if(damage && istype(W, /obj/item/weapon/weldingtool))
var/obj/item/weapon/weldingtool/WT = W
if(!WT.isOn())
return
if(WT.remove_fuel(0,user))
to_chat(user, "<span class='notice'>You start repairing the damage to [src].</span>")
playsound(src, 'sound/items/Welder.ogg', 100, 1)
if(do_after(user, max(5, damage / 5), src) && WT && WT.isOn())
to_chat(user, "<span class='notice'>You finish repairing the damage to [src].</span>")
take_damage(-damage)
else
to_chat(user, "<span class='notice'>You need more welding fuel to complete this task.</span>")
return
return
..()
/obj/machinery/shipsensors/proc/in_vacuum()
var/turf/T=get_turf(src)
if(istype(T))
var/datum/gas_mixture/environment = T.return_air()
if(environment && environment.return_pressure() > MINIMUM_PRESSURE_DIFFERENCE_TO_SUSPEND)
return 0
return 1
/obj/machinery/shipsensors/update_icon()
if(use_power)
icon_state = "sensors"
else
icon_state = "sensors_off"
..()
/obj/machinery/shipsensors/examine(mob/user)
. = ..()
if(health <= 0)
to_chat(user, "\The [src] is wrecked.")
else if(health < max_health * 0.25)
to_chat(user, "<span class='danger'>\The [src] looks like it's about to break!</span>")
else if(health < max_health * 0.5)
to_chat(user, "<span class='danger'>\The [src] looks seriously damaged!</span>")
else if(health < max_health * 0.75)
to_chat(user, "\The [src] shows signs of damage!")
/obj/machinery/shipsensors/bullet_act(var/obj/item/projectile/Proj)
take_damage(Proj.get_structure_damage())
..()
/obj/machinery/shipsensors/proc/toggle()
if(!use_power && (health == 0 || !in_vacuum()))
return // No turning on if broken or misplaced.
if(!use_power) //need some juice to kickstart
use_power_oneoff(idle_power_usage*5)
update_use_power(!use_power)
update_icon()
/obj/machinery/shipsensors/process()
if(use_power) //can't run in non-vacuum
if(!in_vacuum())
toggle()
if(heat > critical_heat)
src.visible_message("<span class='danger'>\The [src] violently spews out sparks!</span>")
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread
s.set_up(3, 1, src)
s.start()
take_damage(rand(10,50))
toggle()
heat += idle_power_usage/15000
if (heat > 0)
heat = max(0, heat - heat_reduction)
/obj/machinery/shipsensors/power_change()
. = ..()
if(use_power && !powered())
toggle()
/obj/machinery/shipsensors/proc/set_range(nrange)
range = nrange
change_power_consumption(1500 * (range**2), USE_POWER_IDLE) //Exponential increase, also affects speed of overheating
/obj/machinery/shipsensors/emp_act(severity)
if(!use_power)
return
take_damage(20/severity)
toggle()
/obj/machinery/shipsensors/take_damage(value)
health = min(max(health - value, 0),max_health)
if(use_power && health == 0)
toggle()
/obj/machinery/shipsensors/weak
heat_reduction = 0.2
desc = "Miniturized gravity scanner with various other sensors, used to detect irregularities in surrounding space. Can only run in vacuum to protect delicate quantum BS elements."

View File

@@ -0,0 +1,99 @@
/*
While these computers can be placed anywhere, they will only function if placed on either a non-space, non-shuttle turf
with an /obj/effect/overmap/visitable/ship present elsewhere on that z level, or else placed in a shuttle area with an /obj/effect/overmap/visitable/ship
somewhere on that shuttle. Subtypes of these can be then used to perform ship overmap movement functions.
*/
/obj/machinery/computer/ship
var/obj/effect/overmap/visitable/ship/linked
var/list/viewers // Weakrefs to mobs in direct-view mode.
var/extra_view = 0 // how much the view is increased by when the mob is in overmap mode.
// A late init operation called in SSshuttles, used to attach the thing to the right ship.
/obj/machinery/computer/ship/proc/attempt_hook_up(obj/effect/overmap/visitable/ship/sector)
if(!istype(sector))
return
if(sector.check_ownership(src))
linked = sector
return 1
/obj/machinery/computer/ship/proc/sync_linked()
var/obj/effect/overmap/visitable/ship/sector = map_sectors["[z]"]
if(!sector)
return
return attempt_hook_up_recursive(sector)
/obj/machinery/computer/ship/proc/attempt_hook_up_recursive(obj/effect/overmap/visitable/ship/sector)
if(attempt_hook_up(sector))
return sector
for(var/obj/effect/overmap/visitable/ship/candidate in sector)
if((. = .(candidate)))
return
/obj/machinery/computer/ship/proc/display_reconnect_dialog(var/mob/user, var/flavor)
var/datum/browser/popup = new (user, "[src]", "[src]")
popup.set_content("<center><strong><font color = 'red'>Error</strong></font><br>Unable to connect to [flavor].<br><a href='?src=\ref[src];sync=1'>Reconnect</a></center>")
popup.open()
// In computer_shims for now - we had to define it.
// /obj/machinery/computer/ship/interface_interact(var/mob/user)
// ui_interact(user)
// return TRUE
/obj/machinery/computer/ship/OnTopic(var/mob/user, var/list/href_list)
if(..())
return TOPIC_HANDLED
if(href_list["sync"])
sync_linked()
return TOPIC_REFRESH
if(href_list["close"])
unlook(user)
user.unset_machine()
return TOPIC_HANDLED
return TOPIC_NOACTION
// Management of mob view displacement. look to shift view to the ship on the overmap; unlook to shift back.
/obj/machinery/computer/ship/proc/look(var/mob/user)
if(linked)
user.reset_view(linked)
if(user.client)
user.client.view = world.view + extra_view
GLOB.moved_event.register(user, src, /obj/machinery/computer/ship/proc/unlook)
// TODO GLOB.stat_set_event.register(user, src, /obj/machinery/computer/ship/proc/unlook)
LAZYDISTINCTADD(viewers, weakref(user))
/obj/machinery/computer/ship/proc/unlook(var/mob/user)
user.reset_view()
if(user.client)
user.client.view = world.view
GLOB.moved_event.unregister(user, src, /obj/machinery/computer/ship/proc/unlook)
// TODO GLOB.stat_set_event.unregister(user, src, /obj/machinery/computer/ship/proc/unlook)
LAZYREMOVE(viewers, weakref(user))
/obj/machinery/computer/ship/proc/viewing_overmap(mob/user)
return (weakref(user) in viewers)
/obj/machinery/computer/ship/CouldNotUseTopic(mob/user)
. = ..()
unlook(user)
/obj/machinery/computer/ship/CouldUseTopic(mob/user)
. = ..()
if(viewing_overmap(user))
look(user)
/obj/machinery/computer/ship/check_eye(var/mob/user)
if (!get_dist(user, src) > 1 || user.blinded || !linked )
unlook(user)
return -1
else
return 0
/obj/machinery/computer/ship/sensors/Destroy()
sensors = null
if(LAZYLEN(viewers))
for(var/weakref/W in viewers)
var/M = W.resolve()
if(M)
unlook(M)
. = ..()

View File

@@ -1,139 +1,45 @@
//Shuttle controller computer for shuttles going between sectors //Shuttle controller computer for shuttles going between sectors
/datum/shuttle/ferry/var/range = 0 //how many overmap tiles can shuttle go, for picking destinatiosn and returning.
/obj/machinery/computer/shuttle_control/explore /obj/machinery/computer/shuttle_control/explore
name = "exploration shuttle console" name = "general shuttle control console"
shuttle_tag = "Exploration" ui_template = "shuttle_control_console_exploration.tmpl"
req_access = list()
var/landing_type //area for shuttle ship-side
var/obj/effect/map/destination //current destination
var/obj/effect/map/home //current destination
/obj/machinery/computer/shuttle_control/explore/Initialize() /obj/machinery/computer/shuttle_control/explore/get_ui_data(var/datum/shuttle/autodock/overmap/shuttle)
. = ..() . = ..()
home = map_sectors["[z]"] if(istype(shuttle))
shuttle_tag = "[shuttle_tag]-[z]" var/total_gas = 0
if(!shuttle_controller.shuttles[shuttle_tag]) for(var/obj/structure/fuel_port/FP in shuttle.fuel_ports) //loop through fuel ports
var/datum/shuttle/ferry/shuttle = new() var/obj/item/weapon/tank/fuel_tank = locate() in FP
shuttle.warmup_time = 10 if(fuel_tank)
shuttle.area_station = locate(landing_type) total_gas += fuel_tank.air_contents.total_moles
shuttle.area_offsite = shuttle.area_station
shuttle_controller.shuttles[shuttle_tag] = shuttle
shuttle_controller.process_shuttles += shuttle
testing("Exploration shuttle '[shuttle_tag]' at z-level [z] successfully added.")
//Sets destination to new sector. Can be null. var/fuel_span = "good"
/obj/machinery/computer/shuttle_control/explore/proc/update_destination(var/obj/effect/map/D) if(total_gas < shuttle.fuel_consumption * 2)
destination = D fuel_span = "bad"
if(destination && shuttle_controller.shuttles[shuttle_tag])
var/datum/shuttle/ferry/shuttle = shuttle_controller.shuttles[shuttle_tag]
shuttle.area_offsite = destination.shuttle_landing
testing("Shuttle controller [shuttle_tag] now sends shuttle to [destination]")
shuttle_controller.shuttles[shuttle_tag] = shuttle
//Gets all sectors with landing zones in shuttle's range . += list(
/obj/machinery/computer/shuttle_control/explore/proc/get_possible_destinations() "destination_name" = shuttle.get_destination_name(),
var/list/res = list() "can_pick" = shuttle.moving_status == SHUTTLE_IDLE,
var/datum/shuttle/ferry/shuttle = shuttle_controller.shuttles[shuttle_tag] "fuel_usage" = shuttle.fuel_consumption * 100,
for (var/obj/effect/map/S in orange(shuttle.range, home)) "remaining_fuel" = round(total_gas, 0.01) * 100,
if(S.shuttle_landing) "fuel_span" = fuel_span
res += S )
return res
//Checks if current destination is still reachable /obj/machinery/computer/shuttle_control/explore/handle_topic_href(var/datum/shuttle/autodock/overmap/shuttle, var/list/href_list)
/obj/machinery/computer/shuttle_control/explore/proc/check_destination() if(ismob(usr))
var/datum/shuttle/ferry/shuttle = shuttle_controller.shuttles[shuttle_tag] var/mob/user = usr
return shuttle && destination && get_dist(home, destination) <= shuttle.range shuttle.operator_skill = user.get_skill_value(/datum/skill/pilot)
/obj/machinery/computer/shuttle_control/explore/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) if((. = ..()) != null)
var/data[0]
var/datum/shuttle/ferry/shuttle = shuttle_controller.shuttles[shuttle_tag]
if (!istype(shuttle))
return
//If we are already there, or can't reach place anymore, reset destination
if(!shuttle.location && !check_destination())
destination = null
//check if shuttle can fly at all
var/can_go = !isnull(destination)
var/current_destination = destination ? destination.name : "None"
//shuttle doesn't need destination set to return home, as long as it's in range.
if(shuttle.location)
current_destination = "Return"
var/area/offsite = shuttle.area_offsite
var/obj/effect/map/cur_loc = map_sectors["[offsite.z]"]
can_go = (get_dist(home,cur_loc) <= shuttle.range)
//disable picking locations if there are none, or shuttle is already off-site
var/list/possible_d = get_possible_destinations()
var/can_pick = !shuttle.location && possible_d.len
var/shuttle_state
switch(shuttle.moving_status)
if(SHUTTLE_IDLE) shuttle_state = "idle"
if(SHUTTLE_WARMUP) shuttle_state = "warmup"
if(SHUTTLE_INTRANSIT) shuttle_state = "in_transit"
var/shuttle_status
switch (shuttle.process_state)
if(IDLE_STATE)
if (shuttle.in_use)
shuttle_status = "Busy."
else if (!shuttle.location)
shuttle_status = "Standing-by at station."
else
shuttle_status = "Standing-by at offsite location."
if(WAIT_LAUNCH, FORCE_LAUNCH)
shuttle_status = "Shuttle has received command and will depart shortly."
if(WAIT_ARRIVE)
shuttle_status = "Proceeding to destination."
if(WAIT_FINISH)
shuttle_status = "Arriving at destination now."
data = list(
"destination_name" = current_destination,
"can_pick" = can_pick,
"shuttle_status" = shuttle_status,
"shuttle_state" = shuttle_state,
"has_docking" = shuttle.docking_controller? 1 : 0,
"docking_status" = shuttle.docking_controller? shuttle.docking_controller.get_docking_status() : null,
"docking_override" = shuttle.docking_controller? shuttle.docking_controller.override_enabled : null,
"can_launch" = can_go && shuttle.can_launch(),
"can_cancel" = can_go && shuttle.can_cancel(),
"can_force" = can_go && shuttle.can_force(),
)
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "shuttle_control_console_exploration.tmpl", "[shuttle_tag] Shuttle Control", 470, 310)
ui.set_initial_data(data)
ui.open()
ui.set_auto_update(1)
/obj/machinery/computer/shuttle_control/explore/Topic(href, href_list)
if(..())
return 1
usr.set_machine(src)
src.add_fingerprint(usr)
var/datum/shuttle/ferry/shuttle = shuttle_controller.shuttles[shuttle_tag]
if (!istype(shuttle))
return return
if(href_list["pick"]) if(href_list["pick"])
var/obj/effect/map/self = map_sectors["[z]"] var/list/possible_d = shuttle.get_possible_destinations()
if(self) var/D
var/list/possible_d = get_possible_destinations() if(possible_d.len)
var/obj/effect/map/D D = input("Choose shuttle destination", "Shuttle Destination") as null|anything in possible_d
if(possible_d.len) else
D = input("Choose shuttle destination", "Shuttle Destination") as null|anything in possible_d to_chat(usr,"<span class='warning'>No valid landing sites in range.</span>")
update_destination(D) possible_d = shuttle.get_possible_destinations()
if(CanInteract(usr, global.default_state) && (D in possible_d))
if(href_list["move"]) shuttle.set_destination(possible_d[D])
shuttle.launch(src) return TOPIC_REFRESH
if(href_list["force"])
shuttle.force_launch(src)
else if(href_list["cancel"])
shuttle.cancel_launch(src)

View File

@@ -3,58 +3,43 @@
var/list/ship_engines = list() var/list/ship_engines = list()
/datum/ship_engine /datum/ship_engine
var/name = "ship engine" var/name = "ship engine"
var/obj/machinery/engine //actual engine object var/obj/machinery/holder //actual engine object
var/zlevel = 0
/datum/ship_engine/New(var/obj/machinery/holder) /datum/ship_engine/New(var/obj/machinery/_holder)
engine = holder ..()
zlevel = holder.z holder = _holder
for(var/obj/machinery/computer/engines/E in machines) ship_engines += src
if (E.z == zlevel && !(src in E.engines))
E.engines += src
break
//Tries to fire the engine. If successfull, returns 1 /datum/ship_engine/proc/can_burn()
return 0
//Tries to fire the engine. Returns thrust
/datum/ship_engine/proc/burn() /datum/ship_engine/proc/burn()
if(!engine) return 0
die()
return 1
//Returns status string for this engine //Returns status string for this engine
/datum/ship_engine/proc/get_status() /datum/ship_engine/proc/get_status()
if(!engine)
die()
return "All systems nominal" return "All systems nominal"
/datum/ship_engine/proc/get_thrust() /datum/ship_engine/proc/get_thrust()
if(!engine) return 1
die()
return 100
//Sets thrust limiter, a number between 0 and 1 //Sets thrust limiter, a number between 0 and 1
/datum/ship_engine/proc/set_thrust_limit(var/new_limit) /datum/ship_engine/proc/set_thrust_limit(var/new_limit)
if(!engine)
die()
return 1 return 1
/datum/ship_engine/proc/get_thrust_limit() /datum/ship_engine/proc/get_thrust_limit()
if(!engine)
die()
return 1 return 1
/datum/ship_engine/proc/is_on() /datum/ship_engine/proc/is_on()
if(!engine)
die()
return 1 return 1
/datum/ship_engine/proc/toggle() /datum/ship_engine/proc/toggle()
if(!engine)
die()
return 1 return 1
/datum/ship_engine/proc/die() /datum/ship_engine/Destroy()
for(var/obj/machinery/computer/engines/E in machines) ship_engines -= src
if (E.z == zlevel) for(var/obj/effect/overmap/visitable/ship/S in SSshuttles.ships)
E.engines -= src S.engines -= src
break holder = null
qdel(src) . = ..()

View File

@@ -0,0 +1,218 @@
//Gas nozzle engine
/datum/ship_engine/gas_thruster
name = "gas thruster"
var/obj/machinery/atmospherics/unary/engine/nozzle
/datum/ship_engine/gas_thruster/New(var/obj/machinery/_holder)
..()
nozzle = _holder
/datum/ship_engine/gas_thruster/Destroy()
nozzle = null
. = ..()
/datum/ship_engine/gas_thruster/get_status()
return nozzle.get_status()
/datum/ship_engine/gas_thruster/get_thrust()
return nozzle.get_thrust()
/datum/ship_engine/gas_thruster/burn()
return nozzle.burn()
/datum/ship_engine/gas_thruster/set_thrust_limit(var/new_limit)
nozzle.thrust_limit = new_limit
/datum/ship_engine/gas_thruster/get_thrust_limit()
return nozzle.thrust_limit
/datum/ship_engine/gas_thruster/is_on()
if(nozzle.use_power && nozzle.operable())
if(nozzle.next_on > world.time)
return -1
else
return 1
return 0
/datum/ship_engine/gas_thruster/toggle()
if(nozzle.use_power)
nozzle.update_use_power(USE_POWER_OFF)
else
if(nozzle.blockage)
if(nozzle.check_blockage())
return
nozzle.update_use_power(USE_POWER_IDLE)
if(nozzle.stat & NOPOWER)//try again
nozzle.power_change()
if(nozzle.is_on())//if everything is in working order, start booting!
nozzle.next_on = world.time + nozzle.boot_time
/datum/ship_engine/gas_thruster/can_burn()
return nozzle.is_on() && nozzle.check_fuel()
//Actual thermal nozzle engine object
/obj/machinery/atmospherics/unary/engine
name = "rocket nozzle"
desc = "Simple rocket nozzle, expelling gas at hypersonic velocities to propell the ship."
icon = 'icons/turf/shuttle_parts.dmi'
icon_state = "nozzle"
opacity = 1
density = 1
can_atmos_pass = ATMOS_PASS_NO
connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_FUEL
// construct_state = /decl/machine_construction/default/panel_closed
// maximum_component_parts = list(/obj/item/weapon/stock_parts = 6)//don't want too many, let upgraded component shine
// uncreated_component_parts = list(/obj/item/weapon/stock_parts/power/apc/buildable = 1)
use_power = USE_POWER_OFF
power_channel = EQUIP
idle_power_usage = 21600 //6 Wh per tick for default 2 capacitor. Gives them a reason to turn it off, really to nerf backup battery
var/datum/ship_engine/gas_thruster/controller
var/thrust_limit = 1 //Value between 1 and 0 to limit the resulting thrust
var/volume_per_burn = 15 //20 litres(with bin)
var/charge_per_burn = 36000 //10Wh for default 2 capacitor, chews through that battery power! Makes a trade off of fuel efficient vs energy efficient
var/boot_time = 35
var/next_on
var/blockage
/obj/machinery/atmospherics/unary/engine/CanPass(atom/movable/mover, turf/target, height=0, air_group=0)
return 0
/obj/machinery/atmospherics/unary/engine/Initialize()
. = ..()
controller = new(src)
update_nearby_tiles(need_rebuild=1)
for(var/ship in SSshuttles.ships)
var/obj/effect/overmap/visitable/ship/S = ship
if(S.check_ownership(src))
S.engines |= controller
if(dir != S.fore_dir)
set_broken(TRUE)
break
/obj/machinery/atmospherics/unary/engine/Destroy()
QDEL_NULL(controller)
update_nearby_tiles()
. = ..()
/obj/machinery/atmospherics/unary/engine/proc/get_status()
. = list()
.+= "Location: [get_area(src)]."
if(stat & NOPOWER)
.+= "<span class='average'>Insufficient power to operate.</span>"
if(!check_fuel())
.+= "<span class='average'>Insufficient fuel for a burn.</span>"
if(stat & BROKEN)
.+= "<span class='average'>Inoperable engine configuration.</span>"
if(blockage)
.+= "<span class='average'>Obstruction of airflow detected.</span>"
.+= "Propellant total mass: [round(air_contents.get_mass(),0.01)] kg."
.+= "Propellant used per burn: [round(air_contents.get_mass() * volume_per_burn * thrust_limit / air_contents.volume,0.01)] kg."
.+= "Propellant pressure: [round(air_contents.return_pressure()/1000,0.1)] MPa."
. = jointext(.,"<br>")
/obj/machinery/atmospherics/unary/engine/power_change()
. = ..()
if(stat & NOPOWER)
update_use_power(USE_POWER_OFF)
/obj/machinery/atmospherics/unary/engine/proc/is_on()
return use_power && operable() && (next_on < world.time)
/obj/machinery/atmospherics/unary/engine/proc/check_fuel()
return air_contents.total_moles > 5 // minimum fuel usage is five moles, for EXTREMELY hot mix or super low pressure
/obj/machinery/atmospherics/unary/engine/proc/get_thrust()
if(!is_on() || !check_fuel())
return 0
var/used_part = volume_per_burn * thrust_limit / air_contents.volume
. = calculate_thrust(air_contents, used_part)
return
/obj/machinery/atmospherics/unary/engine/proc/check_blockage()
blockage = FALSE
var/exhaust_dir = reverse_direction(dir)
var/turf/A = get_step(src, exhaust_dir)
var/turf/B = A
while(isturf(A) && !(istype(A, /turf/space) || isopenspace(A)))
if((B.c_airblock(A)) & AIR_BLOCKED)
blockage = TRUE
break
B = A
A = get_step(A, exhaust_dir)
return blockage
/obj/machinery/atmospherics/unary/engine/proc/burn()
if(!is_on())
return 0
if(!check_fuel() || (0 < use_power_oneoff(charge_per_burn)) || check_blockage())
audible_message(src,"<span class='warning'>[src] coughs once and goes silent!</span>")
update_use_power(USE_POWER_OFF)
return 0
var/datum/gas_mixture/removed = air_contents.remove_ratio(volume_per_burn * thrust_limit / air_contents.volume)
if(!removed)
return 0
. = calculate_thrust(removed)
playsound(loc, 'sound/machines/thruster.ogg', 100 * thrust_limit, 0, world.view * 4, 0.1)
if(network)
network.update = 1
var/exhaust_dir = reverse_direction(dir)
var/turf/T = get_step(src,exhaust_dir)
if(T)
T.assume_air(removed)
new/obj/effect/engine_exhaust(T, exhaust_dir, air_contents.check_combustability() && air_contents.temperature >= PHORON_MINIMUM_BURN_TEMPERATURE)
/obj/machinery/atmospherics/unary/engine/proc/calculate_thrust(datum/gas_mixture/propellant, used_part = 1)
return round(sqrt(propellant.get_mass() * used_part * sqrt(air_contents.return_pressure()/200)),0.1)
/obj/machinery/atmospherics/unary/engine/RefreshParts()
..()
//allows them to upgrade the max limit of fuel intake (which only gives diminishing returns) for increase in max thrust but massive reduction in fuel economy
var/bin_upgrade = 5 * CLAMP(total_component_rating_of_type(/obj/item/weapon/stock_parts/matter_bin), 0, 6)//5 litre per rank
volume_per_burn = bin_upgrade ? initial(volume_per_burn) + bin_upgrade : 2 //Penalty missing part: 10% fuel use, no thrust
boot_time = bin_upgrade ? initial(boot_time) - bin_upgrade : initial(boot_time) * 2
//energy cost - thb all of this is to limit the use of back up batteries
var/energy_upgrade = CLAMP(total_component_rating_of_type(/obj/item/weapon/stock_parts/capacitor), 0.1, 6)
charge_per_burn = initial(charge_per_burn) / energy_upgrade
change_power_consumption(initial(idle_power_usage) / energy_upgrade, USE_POWER_IDLE)
//Exhaust effect
/obj/effect/engine_exhaust
name = "engine exhaust"
icon = 'icons/effects/effects.dmi'
icon_state = "smoke"
light_color = "#ed9200"
anchored = 1
/obj/effect/engine_exhaust/New(var/turf/nloc, var/ndir, var/flame)
..(nloc)
if(flame)
icon_state = "exhaust"
nloc.hotspot_expose(1000,125)
set_light(0.5, 3)
set_dir(ndir)
QDEL_IN(src, 20)
/obj/item/weapon/circuitboard/unary_atmos/engine //why don't we move this elsewhere?
name = T_BOARD("gas thruster")
icon_state = "mcontroller"
build_path = /obj/machinery/atmospherics/unary/engine
origin_tech = list(TECH_POWER = 1, TECH_ENGINEERING = 2)
req_components = list(
/obj/item/stack/cable_coil = 30,
/obj/item/pipe = 2,
/obj/item/weapon/stock_parts/matter_bin = 1,
/obj/item/weapon/stock_parts/capacitor = 2)
// Not Implemented - Variant that pulls power from cables. Too complicated without bay's power components.
// /obj/machinery/atmospherics/unary/engine/terminal
// base_type = /obj/machinery/atmospherics/unary/engine
// stock_part_presets = list(/decl/stock_part_preset/terminal_setup)
// uncreated_component_parts = list(/obj/item/weapon/stock_parts/power/terminal/buildable = 1)

View File

@@ -0,0 +1,86 @@
/datum/ship_engine/ion
name = "ion thruster"
var/obj/machinery/ion_engine/thruster
/datum/ship_engine/ion/New(var/obj/machinery/_holder)
..()
thruster = _holder
/datum/ship_engine/ion/Destroy()
thruster = null
. = ..()
/datum/ship_engine/ion/get_status()
return thruster.get_status()
/datum/ship_engine/ion/get_thrust()
return thruster.get_thrust()
/datum/ship_engine/ion/burn()
return thruster.burn()
/datum/ship_engine/ion/set_thrust_limit(var/new_limit)
thruster.thrust_limit = new_limit
/datum/ship_engine/ion/get_thrust_limit()
return thruster.thrust_limit
/datum/ship_engine/ion/is_on()
return thruster.on && thruster.powered()
/datum/ship_engine/ion/toggle()
thruster.on = !thruster.on
/datum/ship_engine/ion/can_burn()
return thruster.on && thruster.powered()
/obj/machinery/ion_engine
name = "ion propulsion device"
desc = "An advanced ion propulsion device, using energy and minutes amount of gas to generate thrust."
icon = 'icons/turf/shuttle_parts.dmi'
icon_state = "nozzle"
power_channel = ENVIRON
idle_power_usage = 100
anchored = TRUE
// construct_state = /decl/machine_construction/default/panel_closed
var/datum/ship_engine/ion/controller
var/thrust_limit = 1
var/on = 1
var/burn_cost = 750
var/generated_thrust = 2.5
/obj/machinery/ion_engine/Initialize()
. = ..()
controller = new(src)
/obj/machinery/ion_engine/Destroy()
QDEL_NULL(controller)
. = ..()
/obj/machinery/ion_engine/proc/get_status()
. = list()
.+= "Location: [get_area(src)]."
if(!powered())
.+= "Insufficient power to operate."
. = jointext(.,"<br>")
/obj/machinery/ion_engine/proc/burn()
if(!on && !powered())
return 0
use_power_oneoff(burn_cost)
. = thrust_limit * generated_thrust
/obj/machinery/ion_engine/proc/get_thrust()
return thrust_limit * generated_thrust * on
/obj/item/weapon/circuitboard/engine/ion
name = T_BOARD("ion propulsion device")
board_type = "machine"
icon_state = "mcontroller"
build_path = /obj/machinery/ion_engine
origin_tech = list(TECH_POWER = 1, TECH_ENGINEERING = 2)
req_components = list(
/obj/item/stack/cable_coil = 2,
/obj/item/weapon/stock_parts/matter_bin = 1,
/obj/item/weapon/stock_parts/capacitor = 2)

View File

@@ -0,0 +1,173 @@
// These come with shuttle functionality. Need to be assigned a (unique) shuttle datum name.
// Mapping location doesn't matter, so long as on a map loaded at the same time as the shuttle areas.
// Multiz shuttles currently not supported. Non-autodock shuttles currently not supported.
/obj/effect/overmap/visitable/ship/landable
var/shuttle // Name of associated shuttle. Must be autodock.
var/obj/effect/shuttle_landmark/ship/landmark // Record our open space landmark for easy reference.
var/multiz = 0 // Index of multi-z levels, starts at 0
var/status = SHIP_STATUS_LANDED
icon_state = "shuttle"
moving_state = "shuttle_moving"
/obj/effect/overmap/visitable/ship/landable/Destroy()
GLOB.shuttle_moved_event.unregister(SSshuttles.shuttles[shuttle], src)
return ..()
/obj/effect/overmap/visitable/ship/landable/can_burn()
if(status != SHIP_STATUS_OVERMAP)
return 0
return ..()
/obj/effect/overmap/visitable/ship/landable/burn()
if(status != SHIP_STATUS_OVERMAP)
return 0
return ..()
/obj/effect/overmap/visitable/ship/landable/check_ownership(obj/object)
var/datum/shuttle/shuttle_datum = SSshuttles.shuttles[shuttle]
if(!shuttle_datum)
return
var/list/areas = shuttle_datum.find_childfree_areas()
if(get_area(object) in areas)
return 1
// We autobuild our z levels.
/obj/effect/overmap/visitable/ship/landable/find_z_levels()
for(var/i = 0 to multiz)
world.increment_max_z()
map_z += world.maxz
var/turf/center_loc = locate(round(world.maxx/2), round(world.maxy/2), world.maxz)
landmark = new (center_loc, shuttle)
add_landmark(landmark, shuttle)
var/visitor_dir = fore_dir
for(var/landmark_name in list("FORE", "PORT", "AFT", "STARBOARD"))
var/turf/visitor_turf = get_ranged_target_turf(center_loc, visitor_dir, round(min(world.maxx/4, world.maxy/4)))
var/obj/effect/shuttle_landmark/visiting_shuttle/visitor_landmark = new (visitor_turf, landmark, landmark_name)
add_landmark(visitor_landmark)
visitor_dir = turn(visitor_dir, 90)
if(multiz)
new /obj/effect/landmark/map_data(center_loc, (multiz + 1))
/obj/effect/overmap/visitable/ship/landable/get_areas()
var/datum/shuttle/shuttle_datum = SSshuttles.shuttles[shuttle]
if(!shuttle_datum)
return list()
return shuttle_datum.find_childfree_areas()
/obj/effect/overmap/visitable/ship/landable/populate_sector_objects()
..()
var/datum/shuttle/shuttle_datum = SSshuttles.shuttles[shuttle]
if(istype(shuttle_datum,/datum/shuttle/autodock/overmap))
var/datum/shuttle/autodock/overmap/oms = shuttle_datum
oms.myship = src
GLOB.shuttle_moved_event.register(shuttle_datum, src, .proc/on_shuttle_jump)
on_landing(landmark, shuttle_datum.current_location) // We "land" at round start to properly place ourselves on the overmap.
/obj/effect/shuttle_landmark/ship
name = "Open Space"
landmark_tag = "ship"
flags = SLANDMARK_FLAG_AUTOSET | SLANDMARK_FLAG_ZERO_G
var/shuttle_name
var/list/visitors // landmark -> visiting shuttle stationed there
/obj/effect/shuttle_landmark/ship/Initialize(mapload, shuttle_name)
landmark_tag += "_[shuttle_name]"
src.shuttle_name = shuttle_name
. = ..()
/obj/effect/shuttle_landmark/ship/Destroy()
var/obj/effect/overmap/visitable/ship/landable/ship = map_sectors["[z]"]
if(istype(ship) && ship.landmark == src)
ship.landmark = null
. = ..()
/obj/effect/shuttle_landmark/ship/cannot_depart(datum/shuttle/shuttle)
if(LAZYLEN(visitors))
return "Grappled by other shuttle; cannot manouver."
/obj/effect/shuttle_landmark/visiting_shuttle
flags = SLANDMARK_FLAG_AUTOSET | SLANDMARK_FLAG_ZERO_G
var/obj/effect/shuttle_landmark/ship/core_landmark
/obj/effect/shuttle_landmark/visiting_shuttle/Initialize(mapload, obj/effect/shuttle_landmark/ship/master, _name)
core_landmark = master
name = _name
landmark_tag = master.shuttle_name + _name
GLOB.destroyed_event.register(master, src, /datum/proc/qdel_self)
. = ..()
/obj/effect/shuttle_landmark/visiting_shuttle/Destroy()
GLOB.destroyed_event.unregister(core_landmark, src)
LAZYREMOVE(core_landmark.visitors, src)
core_landmark = null
. = ..()
/obj/effect/shuttle_landmark/visiting_shuttle/is_valid(datum/shuttle/shuttle)
. = ..()
if(!.)
return
var/datum/shuttle/boss_shuttle = SSshuttles.shuttles[core_landmark.shuttle_name]
if(boss_shuttle.current_location != core_landmark)
return FALSE // Only available when our governing shuttle is in space.
if(shuttle == boss_shuttle) // Boss shuttle only lands on main landmark
return FALSE
/obj/effect/shuttle_landmark/visiting_shuttle/shuttle_arrived(datum/shuttle/shuttle)
LAZYSET(core_landmark.visitors, src, shuttle)
GLOB.shuttle_moved_event.register(shuttle, src, .proc/shuttle_left)
/obj/effect/shuttle_landmark/visiting_shuttle/proc/shuttle_left(datum/shuttle/shuttle, obj/effect/shuttle_landmark/old_landmark, obj/effect/shuttle_landmark/new_landmark)
if(old_landmark == src)
GLOB.shuttle_moved_event.unregister(shuttle, src)
LAZYREMOVE(core_landmark.visitors, src)
/obj/effect/overmap/visitable/ship/landable/proc/on_shuttle_jump(datum/shuttle/given_shuttle, obj/effect/shuttle_landmark/from, obj/effect/shuttle_landmark/into)
if(given_shuttle != SSshuttles.shuttles[shuttle])
return
var/datum/shuttle/autodock/auto = given_shuttle
if(into == auto.landmark_transition)
status = SHIP_STATUS_TRANSIT
on_takeoff(from, into)
return
if(into == landmark)
status = SHIP_STATUS_OVERMAP
on_takeoff(from, into)
return
status = SHIP_STATUS_LANDED
on_landing(from, into)
/obj/effect/overmap/visitable/ship/landable/proc/on_landing(obj/effect/shuttle_landmark/from, obj/effect/shuttle_landmark/into)
var/obj/effect/overmap/visitable/target = map_sectors["[into.z]"]
var/datum/shuttle/shuttle_datum = SSshuttles.shuttles[shuttle]
if(into.landmark_tag == shuttle_datum.motherdock) // If our motherdock is a landable ship, it won't be found properly here so we need to find it manually.
for(var/obj/effect/overmap/visitable/ship/landable/landable in SSshuttles.ships)
if(landable.shuttle == shuttle_datum.mothershuttle)
target = landable
break
if(!target || target == src)
return
forceMove(target)
halt()
/obj/effect/overmap/visitable/ship/landable/proc/on_takeoff(obj/effect/shuttle_landmark/from, obj/effect/shuttle_landmark/into)
if(!isturf(loc))
forceMove(get_turf(loc))
unhalt()
/obj/effect/overmap/visitable/ship/landable/get_landed_info()
switch(status)
if(SHIP_STATUS_LANDED)
var/obj/effect/overmap/visitable/location = loc
if(istype(loc, /obj/effect/overmap/visitable/sector))
return "Landed on \the [location.name]. Use secondary thrust to get clear before activating primary engines."
if(istype(loc, /obj/effect/overmap/visitable/ship))
return "Docked with \the [location.name]. Use secondary thrust to get clear before activating primary engines."
return "Docked with an unknown object."
if(SHIP_STATUS_TRANSIT)
return "Maneuvering under secondary thrust."
if(SHIP_STATUS_OVERMAP)
return "In open space."

View File

@@ -1,116 +1,234 @@
/obj/effect/map/ship #define SHIP_MOVE_RESOLUTION 0.00001
#define MOVING(speed) abs(speed) >= min_speed
#define SANITIZE_SPEED(speed) SIGN(speed) * CLAMP(abs(speed), 0, max_speed)
#define CHANGE_SPEED_BY(speed_var, v_diff) \
v_diff = SANITIZE_SPEED(v_diff);\
if(!MOVING(speed_var + v_diff)) \
{speed_var = 0};\
else \
{speed_var = SANITIZE_SPEED((speed_var + v_diff)/(1 + speed_var*v_diff/(max_speed ** 2)))}
// Uses Lorentzian dynamics to avoid going too fast.
/obj/effect/overmap/visitable/ship
name = "generic ship" name = "generic ship"
desc = "Space faring vessel." desc = "Space faring vessel."
icon_state = "sheet-sandstone" icon_state = "ship"
var/vessel_mass = 9000 //tonnes, random number var/moving_state = "ship_moving"
var/default_delay = 60
var/list/speed = list(0,0)
var/last_burn = 0
var/list/last_movement = list(0,0)
var/fore_dir = NORTH
var/rotate = 1 //For proc rotate
var/obj/effect/map/current_sector var/vessel_mass = 10000 //tonnes, arbitrary number, affects acceleration provided by engines
var/obj/machinery/computer/helm/nav_control var/vessel_size = SHIP_SIZE_LARGE //arbitrary number, affects how likely are we to evade meteors
var/obj/machinery/computer/engines/eng_control var/max_speed = 1/(1 SECOND) //"speed of light" for the ship, in turfs/tick.
var/min_speed = 1/(2 MINUTES) // Below this, we round speed to 0 to avoid math errors.
/obj/effect/map/ship/Initialize() var/list/speed = list(0,0) //speed in x,y direction
var/last_burn = 0 //worldtime when ship last acceleated
var/burn_delay = 1 SECOND //how often ship can do burns
var/list/last_movement = list(0,0) //worldtime when ship last moved in x,y direction
var/fore_dir = NORTH //what dir ship flies towards for purpose of moving stars effect procs
var/list/engines = list()
var/engines_state = 0 //global on/off toggle for all engines
var/thrust_limit = 1 //global thrust limit for all engines, 0..1
var/halted = 0 //admin halt or other stop.
var/skill_needed = SKILL_ADEPT //piloting skill needed to steer it without going in random dir
var/operator_skill
/obj/effect/overmap/visitable/ship/Initialize()
. = ..() . = ..()
for(var/obj/machinery/computer/engines/E in machines) min_speed = round(min_speed, SHIP_MOVE_RESOLUTION)
if (E.z == map_z) max_speed = round(max_speed, SHIP_MOVE_RESOLUTION)
eng_control = E SSshuttles.ships += src
break
for(var/obj/machinery/computer/helm/H in machines)
if (H.z == map_z)
nav_control = H
break
START_PROCESSING(SSobj, src) START_PROCESSING(SSobj, src)
/obj/effect/map/ship/relaymove(mob/user, direction) /obj/effect/overmap/visitable/ship/Destroy()
accelerate(direction) STOP_PROCESSING(SSobj, src)
SSshuttles.ships -= src
. = ..()
/obj/effect/map/ship/proc/is_still() /obj/effect/overmap/visitable/ship/relaymove(mob/user, direction, accel_limit)
return !(speed[1] || speed[2]) accelerate(direction, accel_limit)
operator_skill = user.get_skill_value(/datum/skill/pilot)
/obj/effect/map/ship/proc/get_acceleration() /obj/effect/overmap/visitable/ship/proc/is_still()
return eng_control.get_total_thrust()/vessel_mass return !MOVING(speed[1]) && !MOVING(speed[2])
/obj/effect/map/ship/proc/get_speed() /obj/effect/overmap/visitable/ship/get_scan_data(mob/user)
return round(sqrt(speed[1]*speed[1] + speed[2]*speed[2])) . = ..()
if(!is_still())
. += "<br>Heading: [get_heading_degrees()], speed [get_speed() * 1000]"
/obj/effect/map/ship/proc/get_heading() //Projected acceleration based on information from engines
/obj/effect/overmap/visitable/ship/proc/get_acceleration()
return round(get_total_thrust()/get_vessel_mass(), SHIP_MOVE_RESOLUTION)
//Does actual burn and returns the resulting acceleration
/obj/effect/overmap/visitable/ship/proc/get_burn_acceleration()
return round(burn() / get_vessel_mass(), SHIP_MOVE_RESOLUTION)
/obj/effect/overmap/visitable/ship/proc/get_vessel_mass()
. = vessel_mass
for(var/obj/effect/overmap/visitable/ship/ship in src)
. += ship.get_vessel_mass()
/obj/effect/overmap/visitable/ship/proc/get_speed()
return round(sqrt(speed[1] ** 2 + speed[2] ** 2), SHIP_MOVE_RESOLUTION)
// Get heading in BYOND dir bits
/obj/effect/overmap/visitable/ship/proc/get_heading()
var/res = 0 var/res = 0
if(speed[1]) if(MOVING(speed[1]))
if(speed[1] > 0) if(speed[1] > 0)
res |= EAST res |= EAST
else else
res |= WEST res |= WEST
if(speed[2]) if(MOVING(speed[2]))
if(speed[2] > 0) if(speed[2] > 0)
res |= NORTH res |= NORTH
else else
res |= SOUTH res |= SOUTH
return res return res
/obj/effect/map/ship/proc/adjust_speed(n_x, n_y) // Get heading in degrees (like a compass heading)
speed[1] = CLAMP(speed[1] + n_x, -default_delay, default_delay) /obj/effect/overmap/visitable/ship/proc/get_heading_degrees()
speed[2] = CLAMP(speed[2] + n_y, -default_delay, default_delay) return (ATAN2(speed[2], speed[1]) + 360) % 360 // Yes ATAN2(y, x) is correct to get clockwise degrees
if(is_still())
toggle_move_stars(map_z)
else
toggle_move_stars(map_z, fore_dir)
/obj/effect/map/ship/proc/can_burn() /obj/effect/overmap/visitable/ship/proc/adjust_speed(n_x, n_y)
if (!eng_control) CHANGE_SPEED_BY(speed[1], n_x)
return 0 CHANGE_SPEED_BY(speed[2], n_y)
if (world.time < last_burn + 10) for(var/zz in map_z)
return 0 if(is_still())
if (!eng_control.burn()) toggle_move_stars(zz)
return 0 else
return 1 toggle_move_stars(zz, fore_dir)
update_icon()
/obj/effect/map/ship/proc/get_brake_path() /obj/effect/overmap/visitable/ship/proc/get_brake_path()
if(!get_acceleration()) if(!get_acceleration())
return INFINITY return INFINITY
return get_speed()/get_acceleration() if(is_still())
return 0
if(!burn_delay)
return 0
if(!get_speed())
return 0
var/num_burns = get_speed()/get_acceleration() + 2 //some padding in case acceleration drops form fuel usage
var/burns_per_grid = 1/ (burn_delay * get_speed())
return round(num_burns/burns_per_grid)
#define SIGN(X) (X == 0 ? 0 : (X > 0 ? 1 : -1)) /obj/effect/overmap/visitable/ship/proc/decelerate()
/obj/effect/map/ship/proc/decelerate() if(((speed[1]) || (speed[2])) && can_burn())
if(!is_still() && can_burn())
if (speed[1]) if (speed[1])
adjust_speed(-SIGN(speed[1]) * min(get_acceleration(),abs(speed[1])), 0) adjust_speed(-SIGN(speed[1]) * min(get_burn_acceleration(),abs(speed[1])), 0)
if (speed[2]) if (speed[2])
adjust_speed(0, -SIGN(speed[2]) * min(get_acceleration(),abs(speed[2]))) adjust_speed(0, -SIGN(speed[2]) * min(get_burn_acceleration(),abs(speed[2])))
last_burn = world.time last_burn = world.time
/obj/effect/map/ship/proc/accelerate(direction) /obj/effect/overmap/visitable/ship/proc/accelerate(direction, accel_limit)
if(can_burn()) if(can_burn())
last_burn = world.time last_burn = world.time
var/acceleration = min(get_burn_acceleration(), accel_limit)
if(direction & EAST) if(direction & EAST)
adjust_speed(get_acceleration(), 0) adjust_speed(acceleration, 0)
if(direction & WEST) if(direction & WEST)
adjust_speed(-get_acceleration(), 0) adjust_speed(-acceleration, 0)
if(direction & NORTH) if(direction & NORTH)
adjust_speed(0, get_acceleration()) adjust_speed(0, acceleration)
if(direction & SOUTH) if(direction & SOUTH)
adjust_speed(0, -get_acceleration()) adjust_speed(0, -acceleration)
/obj/effect/overmap/visitable/ship/process()
/obj/effect/map/ship/proc/rotate(var/direction) if(!halted && !is_still())
var/matrix/M = matrix()
M.Turn(dir2angle(direction))
src.transform = M //Rotate ship
/obj/effect/map/ship/process()
if(!is_still())
var/list/deltas = list(0,0) var/list/deltas = list(0,0)
for(var/i=1, i<=2, i++) for(var/i=1, i<=2, i++)
if(speed[i] && world.time > last_movement[i] + default_delay - abs(speed[i])) if(MOVING(speed[i]) && world.time > last_movement[i] + 1/abs(speed[i]))
deltas[i] = speed[i] > 0 ? 1 : -1 deltas[i] = SIGN(speed[i])
last_movement[i] = world.time last_movement[i] = world.time
var/turf/newloc = locate(x + deltas[1], y + deltas[2], z) var/turf/newloc = locate(x + deltas[1], y + deltas[2], z)
if(newloc) if(newloc)
Move(newloc) Move(newloc)
if(rotate) handle_wraparound()
rotate(get_heading()) update_icon()
/obj/effect/overmap/visitable/ship/update_icon()
if(!is_still())
icon_state = moving_state
dir = get_heading()
else
icon_state = initial(icon_state)
..()
/obj/effect/overmap/visitable/ship/proc/burn()
for(var/datum/ship_engine/E in engines)
. += E.burn()
/obj/effect/overmap/visitable/ship/proc/get_total_thrust()
for(var/datum/ship_engine/E in engines)
. += E.get_thrust()
/obj/effect/overmap/visitable/ship/proc/can_burn()
if(halted)
return 0
if (world.time < last_burn + burn_delay)
return 0
for(var/datum/ship_engine/E in engines)
. |= E.can_burn()
//deciseconds to next step
/obj/effect/overmap/visitable/ship/proc/ETA()
. = INFINITY
for(var/i=1, i<=2, i++)
if(MOVING(speed[i]))
. = min(last_movement[i] - world.time + 1/abs(speed[i]), .)
. = max(.,0)
/obj/effect/overmap/visitable/ship/proc/handle_wraparound()
var/nx = x
var/ny = y
var/low_edge = 1
var/high_edge = global.using_map.overmap_size - 1
if((dir & WEST) && x == low_edge)
nx = high_edge
else if((dir & EAST) && x == high_edge)
nx = low_edge
if((dir & SOUTH) && y == low_edge)
ny = high_edge
else if((dir & NORTH) && y == high_edge)
ny = low_edge
if((x == nx) && (y == ny))
return //we're not flying off anywhere
var/turf/T = locate(nx,ny,z)
if(T)
forceMove(T)
/obj/effect/overmap/visitable/ship/proc/halt()
adjust_speed(-speed[1], -speed[2])
halted = 1
/obj/effect/overmap/visitable/ship/proc/unhalt()
if(!SSshuttles.overmap_halted)
halted = 0
/obj/effect/overmap/visitable/ship/Bump(var/atom/A)
if(istype(A,/turf/unsimulated/map/edge))
handle_wraparound()
..()
/obj/effect/overmap/visitable/ship/proc/get_helm_skill()//delete this mover operator skill to overmap obj
return operator_skill
/obj/effect/overmap/visitable/ship/populate_sector_objects()
..()
for(var/obj/machinery/computer/ship/S in global.machines)
S.attempt_hook_up(src)
for(var/datum/ship_engine/E in ship_engines)
if(check_ownership(E.holder))
engines |= E
/obj/effect/overmap/visitable/ship/proc/get_landed_info()
return "This ship cannot land."
#undef MOVING
#undef SANITIZE_SPEED
#undef CHANGE_SPEED_BY

View File

@@ -121,7 +121,7 @@
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open) ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui) if (!ui)
ui = new(user, src, ui_key, ui_template, "[shuttle_tag] Shuttle Control", 470, 310) ui = new(user, src, ui_key, ui_template, "[shuttle_tag] Shuttle Control", 470, 360)
ui.set_initial_data(data) ui.set_initial_data(data)
ui.open() ui.open()
ui.set_auto_update(1) ui.set_auto_update(1)

View File

@@ -277,6 +277,12 @@
return removed return removed
//Returns the amount of gas that has the given flag, in moles
/datum/gas_mixture/proc/get_by_flag(flag)
. = 0
for(var/g in gas)
if(gas_data.flags[g] & flag)
. += gas[g]
//Copies gas and temperature from another gas_mixture. //Copies gas and temperature from another gas_mixture.
/datum/gas_mixture/proc/copy_from(const/datum/gas_mixture/sample) /datum/gas_mixture/proc/copy_from(const/datum/gas_mixture/sample)
@@ -478,3 +484,7 @@
gasmix.multiply(gasmix.volume) gasmix.multiply(gasmix.volume)
return 1 return 1
/datum/gas_mixture/proc/get_mass()
for(var/g in gas)
. += gas[g] * gas_data.molar_mass[g] * group_multiplier

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -1,8 +1,35 @@
<div class="item"> <div class="item">
{{:helper.link('Overall status', 'note', {'state' :'status'}, null, data.state == 'status' ? 'selected' : null)}} {{:helper.link('Overall info', 'note', {'state' :'status'}, null, data.state == 'status' ? 'selected' : null)}}
{{:helper.link('Details', 'note', {'state' : 'engines'}, null, data.state == 'engines' ? 'selected' : null)}} {{:helper.link('Details', 'note', {'state' : 'engines'}, null, data.state == 'engines' ? 'selected' : null)}}
</div> </div>
<div class="item">
<div class='item'>
<div class="itemLabel">
<span class='average'>Global controls:</span>
</div>
<div class="itemContent">
{{:helper.link(data.global_state ? 'Shut all down' : 'Power all up', 'power', {'global_toggle' : 1}, null, data.global_state ? 'selected' : null)}}
</div>
</div>
<div class='item'>
<div class="itemLabel">
<span class='average'>Volume limit:</span>
</div>
<div class="itemContent">
{{:helper.link('', 'circle-plus', { 'global_limit' : 0.1}, null, null)}}
{{:helper.link(data.global_limit+'%', null, { 'set_global_limit' : 1 }, null, null)}}
{{:helper.link('', 'circle-minus', { 'global_limit' : -0.1}, null, null)}}
</div>
</div>
<div class='item'>
<div class="itemLabel">
<span class='average'>Total thrust:</span>
</div>
<div class="itemContent">
<span class='white'>{{:data.total_thrust}}</span>
</div>
</div>
</div>
{{if data.state == "engines"}} {{if data.state == "engines"}}
{{if data.engines_info}} {{if data.engines_info}}
{{for data.engines_info}} {{for data.engines_info}}
@@ -11,9 +38,8 @@
<span class='white'>Engine #{{:(index + 1)}}:</span> <span class='white'>Engine #{{:(index + 1)}}:</span>
</div> </div>
<div class="itemContent"> <div class="itemContent">
{{:helper.link(value.eng_on ? 'Shutdown' : 'Power up', 'power', { 'toggle' : 1, 'engine' : value.eng_reference }, null, value.eng_on ? 'selected' : null)}} {{:helper.link(value.eng_on ? 'Shutdown' : 'Power up', 'power', { 'toggle' : 1, 'engine' : value.eng_reference }, null, value.eng_on ? value.eng_on == 1 ? 'linkOn' : 'yellowButton' : null)}}
</div> </div>
</div>
<div class='statusDisplay'> <div class='statusDisplay'>
<div class='item'> <div class='item'>
<div class="itemLabel"> <div class="itemLabel">
@@ -28,7 +54,7 @@
<span class='average'>Status:</span> <span class='average'>Status:</span>
</div> </div>
<div class="itemContent"> <div class="itemContent">
<span class='{{:value.eng_on ? 'good' : 'bad'}}'>{{:value.eng_on ? 'Online' : 'Offline'}}</span><br> <span class='{{:value.eng_on ? value.eng_on == 1 ? 'good' : 'average' : 'bad'}}'>{{:value.eng_on ? value.eng_on == 1 ? 'Online' : 'Booting' : 'Offline'}}</span><br>
<span class='white'>{{:value.eng_status}}</span> <span class='white'>{{:value.eng_status}}</span>
</div> </div>
</div> </div>
@@ -42,7 +68,7 @@
</div> </div>
<div class='item'> <div class='item'>
<div class="itemLabel"> <div class="itemLabel">
<span class='average'>Thrust limit:</span> <span class='average'>Volume limit:</span>
</div> </div>
<div class="itemContent"> <div class="itemContent">
{{:helper.link('', 'circle-plus', { 'limit' : 0.1, 'engine' : value.eng_reference }, null, null)}} {{:helper.link('', 'circle-plus', { 'limit' : 0.1, 'engine' : value.eng_reference }, null, null)}}
@@ -63,14 +89,14 @@
<span class='white'>Engine #{{:(index + 1)}}:</span> <span class='white'>Engine #{{:(index + 1)}}:</span>
</div> </div>
<div class="itemContent"> <div class="itemContent">
{{:helper.link(value.eng_on ? 'Shutdown' : 'Power up', 'power', { 'toggle' : 1, 'engine' : value.eng_reference }, null, value.eng_on ? 'selected' : null)}} {{:helper.link(value.eng_on ? 'Shutdown' : 'Power up', 'power', { 'toggle' : 1, 'engine' : value.eng_reference }, null, value.eng_on ? value.eng_on == 1 ? 'linkOn' : 'yellowButton' : null)}}
</div> </div>
</div> </div>
<div class='item'> <div class='item'>
<div class="itemLabel"> <div class="itemLabel">
<span class='average'>Thrust:</span> <span class='average'>Thrust:</span>
<br> <br>
<span class='average'>Thrust limit:</span> <span class='average'>Volume limit:</span>
</div> </div>
<div class="itemContent"> <div class="itemContent">
<span class='white'>{{:value.eng_thrust}}</span> <span class='white'>{{:value.eng_thrust}}</span>

View File

@@ -1,114 +1,159 @@
<div style="float:left;width:50%">
<h3>Sector information</h3>
<div class='block'> <div style="float:left;width:45%;">
{{:data.sector}} <fieldset style="min-height:180px;background-color: #202020;">
<br> <legend style="text-align:center">Flight data</legend>
<span class='average'>Coordinates:</span> {{:data.s_x}} : {{:data.s_y}} <div class='item'>
<br> <div class="itemLabelWider">
<span class='average'>Additional information:</span> {{:data.sector_info}} ETA to next grid:
</div> </div>
<div style="float:right">
{{:data.ETAnext}}
</div>
</div>
<div class='item'>
<div class="itemLabelWider">
Speed:
</div>
<div style="float:right">
{{:data.speed}} Gm/h
</div>
</div>
<div class='item'>
<div class="itemLabelWider">
Acceleration:
</div>
<div style="float:right">
{{:data.accel}} Gm/h
</div>
</div>
<div class='item'>
<div class="itemLabelWider">
Heading:
</div>
<div style="float:right">
{{:data.heading}}&deg;
</div>
</div>
<div class='item'>
<div class="itemLabelWider">
Acceleration limiter:
</div>
<div style="float:right">
{{:helper.link(data.accellimit, null, { 'accellimit' : 1}, null, null)}} Gm/h
</div>
</div>
</fieldset>
</div> </div>
<div style="float:right;width:50%"> <div style="float:left;width:25%">
<h3>Flight data</h3> <fieldset style="min-height:180px;background-color: #202020;">
<div class='block'> <legend style="text-align:center">Manual control</legend>
<div class='item'>
<div class="itemLabel">
<span class='average'>Speed:</span>
</div>
<div style="float:right">
{{:data.speed}}
</div>
</div>
<div class='item'>
<div class="itemLabel">
<span class='average'>Acceleration:</span>
</div>
<div style="float:right">
{{:data.accel}}
</div>
</div>
<div class='item'>
<div class="itemLabel">
<span class='average'>Heading:</span>
</div>
<div style="float:right">
{{:data.heading}}
</div>
</div>
</div>
</div>
<h3>Manual control</h3>
<div class='block'>
<div class='item'> <div class='item'>
<div class="itemLabel"> <div class='item'>
<div class='item'> {{:helper.link('', 'triangle-1-nw', { 'move' : 9 }, data.canburn ? null : 'disabled', null)}}
{{:helper.link('', 'triangle-1-nw', { 'move' : 9 }, null, null)}} {{:helper.link('', 'triangle-1-n', { 'move' : 1 }, data.canburn ? null : 'disabled', null)}}
{{:helper.link('', 'triangle-1-n', { 'move' : 1 }, null, null)}} {{:helper.link('', 'triangle-1-ne', { 'move' : 5 }, data.canburn ? null : 'disabled', null)}}
{{:helper.link('', 'triangle-1-ne', { 'move' : 5 }, null, null)}} </div>
</div> <div class='item'>
<div class='item'> {{:helper.link('', 'triangle-1-w', { 'move' : 8 }, data.canburn ? null : 'disabled', null)}}
{{:helper.link('', 'triangle-1-w', { 'move' : 8 }, null, null)}} {{:helper.link('', 'circle-close', { 'brake' : 1 }, data.canburn ? null : 'disabled', null)}}
{{:helper.link('', 'circle-close', { 'brake' : 1 }, null, null)}} {{:helper.link('', 'triangle-1-e', { 'move' : 4 }, data.canburn ? null : 'disabled', null)}}
{{:helper.link('', 'triangle-1-e', { 'move' : 4 }, null, null)}} </div>
</div> <div class='item'>
<div class='item'> {{:helper.link('', 'triangle-1-sw', { 'move' : 10 }, data.canburn ? null : 'disabled', null)}}
{{:helper.link('', 'triangle-1-sw', { 'move' : 10 }, null, null)}} {{:helper.link('', 'triangle-1-s', { 'move' : 2 }, data.canburn ? null : 'disabled', null)}}
{{:helper.link('', 'triangle-1-s', { 'move' : 2 }, null, null)}} {{:helper.link('', 'triangle-1-se', { 'move' : 6 }, data.canburn ? null : 'disabled', null)}}
{{:helper.link('', 'triangle-1-se', { 'move' : 6 }, null, null)}}
</div>
</div> </div>
<div class="itemContent"> <div class='item'>
<div class='item'> <span class='white'>Direct control</span>
<span class='white'>Direct control</span> <br>
{{:helper.link(data.manual_control ? 'Engaged' : 'Disengaged', 'shuffle', { 'manual' : 1 }, data.manual_control ? 'selected' : null, null)}} {{:helper.link(data.manual_control ? 'Engaged' : 'Disengaged', 'shuffle', { 'manual' : 1 }, null, data.manual_control ? 'selected' : null)}}
</div>
</div> </div>
</div> </div>
</fieldset>
</div> </div>
<div class='item'> <div style="float:left;width:30%">
<div class="itemLabel"> <fieldset style="min-height:180px;background-color: #202020;">
<h3>Autopilot</h3> <legend style="text-align:center">Autopilot</legend>
<div class='item'>
<div class="itemLabelWide">
Target:
</div>
<div class="itemContent">
{{if data.dest}}
{{:helper.link(data.d_x, null, { 'setx' : 1 }, null, null)}} {{:helper.link(data.d_y, null, { 'sety' : 1 }, null, null)}}
{{else}}
{{:helper.link('None', null, { 'sety' : 1, 'setx' : 1 }, null, null)}}
{{/if}}
</div>
</div> </div>
<div class="itemContent" style="padding-top: 10px;"> <div class='item'>
<div class="itemLabelWide">
Speed limit:
</div>
<div class="itemContent">
{{:helper.link(data.speedlimit, null, { 'speedlimit' : 1 }, null, null)}} Gm/h
</div>
</div>
<div class="item">
{{:helper.link(data.autopilot ? 'Engaged' : 'Disengaged', 'gear', { 'apilot' : 1 }, data.dest ? null : 'disabled', data.autopilot ? 'selected' : null)}} {{:helper.link(data.autopilot ? 'Engaged' : 'Disengaged', 'gear', { 'apilot' : 1 }, data.dest ? null : 'disabled', data.autopilot ? 'selected' : null)}}
</div> </div>
</div> </fieldset>
<div class='item'>
<div style="float:left;width:45%">
<span class='white'>Target coordinates</span>
</div>
<div style="float:left;width:20%">
{{if data.dest}}
{{:helper.link(data.d_x, null, { 'setx' : 1 }, null, null)}} {{:helper.link(data.d_y, null, { 'sety' : 1 }, null, null)}}
{{else}}
{{:helper.link('None', null, { 'sety' : 1, 'setx' : 1 }, null, null)}}
{{/if}}
</div>
</div> </div>
<h3>Navigation data</h3> <div class='block' style='clear: both;'>
<div class='item'> <h3>Navigation data</h3>
{{:helper.link('Save current position', 'disk', { 'add' : 'current' }, null)}} <div class='item'>
{{:helper.link('Add new entry', 'document', { 'add' : 'new' }, null)}} <div class="itemLabel">
</div> Location:
</div>
<div class='statusDisplay'> <div class="itemContent">
{{if data.locations}} {{:data.sector}}
</div>
</div>
<div class='item'>
<div class="itemLabel">
Coordinates:
</div>
<div class="itemContent">
{{:data.s_x}} : {{:data.s_y}}
</div>
</div>
<div class='item'>
<div class="itemLabel">
Scan data:
</div>
<div class="itemContent">
{{:data.sector_info}}
</div>
</div>
<div class='item'>
<div class="itemLabel">
Status:
</div>
<div class="itemContent">
{{:data.landed}}
</div>
</div>
<div class='item'>
{{:helper.link('Save current position', 'disk', { 'add' : 'current' }, null)}}
{{:helper.link('Add new entry', 'document', { 'add' : 'new' }, null)}}
</div>
<div class='statusDisplay'>
<table style="width:100%">
<tr><th style="width:40%">Name<th>Coordinates<th>Actions
{{for data.locations}} {{for data.locations}}
<div class='item'> <tr class="candystripe"><td>{{:value.name}}
<span class='average'>{{:value.name}}:</span> <td>{{:value.x}} : {{:value.y}}
<span class='white'>{{:value.x}} : {{:value.y}}</span> <td>{{:helper.link('Plot course', 'arrowreturnthick-1-e', { 'x' : value.x, 'y' : value.y }, null, null)}}
</div> {{:helper.link('Remove', 'close', { 'remove' : value.reference }, null, null)}}
<div class='item'>
{{:helper.link('Plot course', 'arrowreturnthick-1-e', { 'x' : value.x, 'y' : value.y }, null, null)}}
{{:helper.link('Remove entry', 'close', { 'remove' : value.reference }, null, null)}}
</div>
{{/for}} {{/for}}
{{/if}} </table>
</div> </div>
</div>

59
nano/templates/nav.tmpl Normal file
View File

@@ -0,0 +1,59 @@
<h3>Navigation</h3>
<div class='block'>
<div class='item'>
<div class="itemContent">
<div class='item'>
<span class='white'>Map view</span>
{{:helper.link(data.viewing ? 'Engaged' : 'Disengaged', 'shuffle', { 'viewing' : 1 }, null, data.viewing ? 'selected' : null)}}
</div>
</div>
</div>
</div>
<div style="float:left;width:50%">
<h3>Sector information</h3>
<div class='block'>
{{:data.sector}}
<br>
<span class='average'>Coordinates:</span> {{:data.s_x}} : {{:data.s_y}}
<br>
<span class='average'>Additional information:</span> {{:data.sector_info}}
</div>
</div>
<div style="float:right;width:50%">
<h3>Flight data</h3>
<div class='block'>
<div class='item'>
<div class="itemLabel">
<span class='average'>ETA to next grid:</span>
</div>
<div style="float:right">
{{:data.ETAnext}}
</div>
</div>
<div class='item'>
<div class="itemLabel">
<span class='average'>Speed:</span>
</div>
<div style="float:right">
{{:data.speed}} Gm/h
</div>
</div>
<div class='item'>
<div class="itemLabel">
<span class='average'>Acceleration:</span>
</div>
<div style="float:right">
{{:data.accel}} Gm/h
</div>
</div>
<div class='item'>
<div class="itemLabel">
<span class='average'>Heading:</span>
</div>
<div style="float:right">
{{:data.heading}}&deg;
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,90 @@
<h3>Sensors control console</h3>
<div class='block'>
{{:helper.link(data.on ? 'Switch off' : 'Switch on', 'gear', { 'toggle' : 1 }, data.status != 'MISSING' ? null : 'disabled', data.on ? 'selected' : null)}}
<div class='item'>
<div class="itemLabel">
<span class='white'>Status:</span>
</div>
<div class="itemContent">
{{:data.status}}
</div>
</div>
<div class='item'>
<div class="itemLabel">
<span class='white'>Range:</span>
</div>
<div class="itemContent">
{{:helper.link(data.range, null, { 'range' : 1 }, null, null)}}
</div>
</div>
</div>
<div class='block'>
<div class='item'>
<div class="itemLabel">
Integrity:
</div>
<div class="itemContent">
{{if data.health < (data.max_health * 0.25)}}
{{:helper.displayBar(data.health, 0, data.max_health, 'bad')}}
<br><span class="bad">{{:data.health}}/{{:data.max_health}}</span>
{{else data.health < data.max_health *.75}}
{{:helper.displayBar(data.health, 0, data.max_health, 'average')}}
<br><span class="average">{{:data.health}}/{{:data.max_health}}</span>
{{else}}
{{:helper.displayBar(data.health, 0, data.max_health, 'good')}}
<br><span class="good">{{:data.health}}/{{:data.max_health}}</span>
{{/if}}
</div>
</div>
<div class='item'>
<div class="itemLabel">
Temperature:
</div>
<div class="itemContent">
{{if data.heat < (data.critical_heat * 0.5)}}
{{:helper.displayBar(data.heat, 0, data.critical_heat, 'good')}}
{{else data.heat < (data.critical_heat * 0.75)}}
{{:helper.displayBar(data.heat, 0, data.critical_heat, 'average')}}
{{else}}
{{:helper.displayBar(data.heat, 0, data.critical_heat, 'bad')}}
{{/if}}
</div>
<div class="itemContent">
{{if data.heat < (data.critical_heat * 0.5)}}
<span class="good">Temperature low.</span>
{{else data.heat < (data.critical_heat * 0.75)}}
<span class="average">Sensor temperature high!</span>
{{else}}
<span class="bad">TEMPERATURE CRITICAL: Disable or reduce power immediately!</span>
{{/if}}
</div>
</div>
</div>
<div class='item'>
<div class="itemContent">
<div class='item'>
<span class='white'>Sector map view</span>
{{:helper.link(data.viewing ? 'Engaged' : 'Disengaged', 'shuffle', { 'viewing' : 1 }, null, data.viewing ? 'selected' : null)}}
</div>
</div>
</div>
<h4>Sensor contacts</h4>
<div class='block'>
{{if data.contacts}}
<table>
{{for data.contacts}}
<tr>
<div class='item'>
<td>{{:helper.link('Scan', 'search' ,{ 'scan' : value.ref }, null, null)}}</td>
<td><span class='white'>{{:value.name}}</span>, bearing {{:value.bearing}}</td>
</div>
</tr>
{{/for}}
</table>
{{/if}}
</div>
{{if data.status == 'MISSING'}}
<div class='item'>
{{:helper.link('Link up with the sensor suite', 'gear', { 'link' : 1 }, data.status == 'MISSING' ? null : 'disabled', null)}}
</div>
{{/if}}

View File

@@ -7,7 +7,7 @@
<div class="item" style="padding-top: 10px"> <div class="item" style="padding-top: 10px">
<div class="item"> <div class="item">
<div class="itemLabel"> <div class="itemLabel">
Drive: Engines:
</div> </div>
<div class="itemContent"> <div class="itemContent">
{{if data.shuttle_state == "idle"}} {{if data.shuttle_state == "idle"}}
@@ -61,6 +61,22 @@
{{:helper.link('Choose Destination', 'arrowreturn-1-s', {'pick' : '1'}, data.can_pick ? null : 'disabled' , null)}} {{:helper.link('Choose Destination', 'arrowreturn-1-s', {'pick' : '1'}, data.can_pick ? null : 'disabled' , null)}}
</div> </div>
</div> </div>
{{if data.fuel_usage}}
<div class="item" style="padding-top: 10px">
<div class="itemLabel">
Est. Delta-V Budget:
</div>
<div class="itemContent">
<span class='{{:data.fuel_span}}'>{{:data.remaining_fuel}} m/s</span>
</div>
<div class="itemLabel">
Avg. Delta-V Per Maneuver:
</div>
<div class="itemContent">
{{:data.fuel_usage}} m/s
</div>
</div>
{{/if}}
<h3>Shuttle Control</h3> <h3>Shuttle Control</h3>
<div class="item" style="padding-top: 10px"> <div class="item" style="padding-top: 10px">
<div class="item"> <div class="item">

Binary file not shown.

Binary file not shown.

BIN
sound/machines/thruster.ogg Normal file

Binary file not shown.

View File

@@ -67,6 +67,7 @@
#include "code\__defines\qdel.dm" #include "code\__defines\qdel.dm"
#include "code\__defines\research.dm" #include "code\__defines\research.dm"
#include "code\__defines\roguemining_vr.dm" #include "code\__defines\roguemining_vr.dm"
#include "code\__defines\shuttle.dm"
#include "code\__defines\sound.dm" #include "code\__defines\sound.dm"
#include "code\__defines\species_languages.dm" #include "code\__defines\species_languages.dm"
#include "code\__defines\species_languages_vr.dm" #include "code\__defines\species_languages_vr.dm"
@@ -2230,6 +2231,7 @@
#include "code\modules\mob\mob_transformation_simple.dm" #include "code\modules\mob\mob_transformation_simple.dm"
#include "code\modules\mob\say.dm" #include "code\modules\mob\say.dm"
#include "code\modules\mob\say_vr.dm" #include "code\modules\mob\say_vr.dm"
#include "code\modules\mob\skillset.dm"
#include "code\modules\mob\transform_procs.dm" #include "code\modules\mob\transform_procs.dm"
#include "code\modules\mob\typing_indicator.dm" #include "code\modules\mob\typing_indicator.dm"
#include "code\modules\mob\update_icons.dm" #include "code\modules\mob\update_icons.dm"
@@ -2849,8 +2851,20 @@
#include "code\modules\organs\subtypes\xenos.dm" #include "code\modules\organs\subtypes\xenos.dm"
#include "code\modules\overmap\_defines.dm" #include "code\modules\overmap\_defines.dm"
#include "code\modules\overmap\overmap_object.dm" #include "code\modules\overmap\overmap_object.dm"
#include "code\modules\overmap\overmap_shuttle.dm"
#include "code\modules\overmap\sectors.dm" #include "code\modules\overmap\sectors.dm"
#include "code\modules\overmap\spacetravel.dm" #include "code\modules\overmap\spacetravel.dm"
#include "code\modules\overmap\ships\landable.dm"
#include "code\modules\overmap\ships\ship.dm"
#include "code\modules\overmap\ships\computers\computer_shims.dm"
#include "code\modules\overmap\ships\computers\engine_control.dm"
#include "code\modules\overmap\ships\computers\helm.dm"
#include "code\modules\overmap\ships\computers\sensors.dm"
#include "code\modules\overmap\ships\computers\ship.dm"
#include "code\modules\overmap\ships\computers\shuttle.dm"
#include "code\modules\overmap\ships\engines\engine.dm"
#include "code\modules\overmap\ships\engines\gas_thruster.dm"
#include "code\modules\overmap\ships\engines\ion_thruster.dm"
#include "code\modules\paperwork\adminpaper.dm" #include "code\modules\paperwork\adminpaper.dm"
#include "code\modules\paperwork\carbonpaper.dm" #include "code\modules\paperwork\carbonpaper.dm"
#include "code\modules\paperwork\clipboard.dm" #include "code\modules\paperwork\clipboard.dm"
@@ -3184,7 +3198,6 @@
#include "code\modules\shieldgen\shield_diffuser.dm" #include "code\modules\shieldgen\shield_diffuser.dm"
#include "code\modules\shieldgen\shield_gen.dm" #include "code\modules\shieldgen\shield_gen.dm"
#include "code\modules\shieldgen\shield_gen_external.dm" #include "code\modules\shieldgen\shield_gen_external.dm"
#include "code\modules\shuttles\_defines.dm"
#include "code\modules\shuttles\antagonist.dm" #include "code\modules\shuttles\antagonist.dm"
#include "code\modules\shuttles\crashes.dm" #include "code\modules\shuttles\crashes.dm"
#include "code\modules\shuttles\departmental.dm" #include "code\modules\shuttles\departmental.dm"