Files
BatrachophrenoandGitHub 4ecb0bc21c Repath obj/machinery to obj/structure/machinery [MDB Ignore] (#22500)
Repaths obj/machinery to obj/structure/machinery. **Note for
reviewers:** the only meaningful changed code exists within
**code/game/objects/structures.dm** and
**code/game/objects/structures/_machinery.dm**, largely concerning
damage procs. With the exception of moving airlock defines to their own
file, ALL OTHER CHANGES ARE STRICTLY PATH CHANGES.

Objects, _categorically_, are largely divided between those you can hold
in your hand/inventory and those you can't. Machinery objects are
already subtypes of Structures behaviorally, this PR just makes their
pathing reflect that, and allows for future work (tool actions, more
health/destruction functionality) to be developed without unnecessary
code duplication.

I have tested this PR by loading up the Horizon and dismantling various
machines and structures with tools, shooting guns of various types
throughout the ship, and detonating a bunch of explosions throughout the
ship.
2026-05-26 19:35:48 +00:00

883 lines
28 KiB
Plaintext

/datum/looping_sound/bluespace_drive
mid_sounds = list('sound/ambience/highsec/highsec2.ogg' = 1)
mid_length = 13 SECONDS
volume = 70
vary = TRUE
/obj/structure/machinery/bluespacedrive
name = "C-Goliath Drive"
desc = "Developed by NanoTrasen, the C-Goliath Drive is a complex piece of machinery designed to fold space using the physics of the Bluespace Dimension and powered by Phoron. \
As one of the greatest pieces of technology invented in the Orion Spur, the bluespace drive changed history twice. \
Once after its discovery, and again during the phoron shortage."
icon = 'icons/obj/machinery/bluespace-drive.dmi'
icon_state = "drive_base"
init_flags = EMPTY_BITFIELD
dir = NORTH
pixel_x = -81
pixel_y = -96
anchored = TRUE
density = TRUE
// opacity = TRUE
/// The atmospherics interface used to give gasses to the drive
var/obj/structure/machinery/atmospherics/portables_connector/atmos_interface
/// The interface used to give fuel (phoron) to the drive
var/obj/structure/machinery/atmospherics/portables_connector/fuel_interface
/// The internal gas that the drive uses, fed by the `atmos_interface`
var/datum/gas_mixture/internal_gas = new()
/// The fuel gas that the drive uses, fed by the `fuel_interface`
var/datum/gas_mixture/fuel_gas = new()
/**
* How much each mole of a given gas contributes to the power
*
* This is then multiplied by the logarithm of the gas temperature, so atmos techs have a reason to burn gasses
*
* Keys are gas IDs, see `GAS_*` in `code\__DEFINES\atmos.dm`
*
* Values are power, numbers
*/
var/static/list/gas_mole_to_power_factor = list(
GAS_PHORON = 1,
GAS_CO2 = 0.24,
GAS_NITROGEN = 0.3,
GAS_N2O = 0.32,
GAS_HELIUM = 0.4,
GAS_HYDROGEN = 0.8,
GAS_OXYGEN = 0.85,
GAS_SULFUR = 1.2,
GAS_CHLORINE = 2.75,
GAS_DEUTERIUM = 3,
GAS_TRITIUM = 4,
GAS_HELIUMFUEL = 6
)
/**
* How many phoron moles we need to jump, anything more is useless
*
* Encourages atmos techs to be precise with their calculations
*/
var/static/minimum_phoron_moles_per_jump = 1000 //About half of a full canister
/// The power given to the drive, due to gases
var/power_from_gas
/// The rotation we'll be using to jump
var/rotation = 0
/// The angle we'll be using to jump
var/angle = 60
/// If the drive is energized
var/energized = FALSE
/// If the drive is set for a jump, which unlocks the jump computer and allows a jump to be initiated
var/primed = FALSE
/// The looping sound that plays when the drive is energized
var/datum/looping_sound/bluespace_drive/energized_looping_sound
/// The timer id for the initiate jump sequence
var/initiate_jump_timer_id
/// The singularity that this drive made
var/obj/singularity/bluespace_drive/our_singularity
/// Our bluespace jump event
var/datum/event/bluespace_jump/bluespace_jump_event
/obj/structure/machinery/bluespacedrive/Initialize()
..()
//Thanks to byond bug 2925542
bound_y = -64
bound_height = 128
bound_x = -32
bound_width = 96
atmos_interface = locate(/obj/structure/machinery/atmospherics/portables_connector) in get_turf(src)
if(atmos_interface)
RegisterSignal(atmos_interface, COMSIG_QDELETING, PROC_REF(handle_atmos_interface_qdeleting))
fuel_interface = locate(/obj/structure/machinery/atmospherics/portables_connector) in get_step(src, WEST)
if(fuel_interface)
RegisterSignal(fuel_interface, COMSIG_QDELETING, PROC_REF(handle_fuel_interface_qdeleting))
return INITIALIZE_HINT_LATELOAD
/obj/structure/machinery/bluespacedrive/LateInitialize()
. = ..()
if(SSatlas.current_map.use_overmap && !linked)
var/my_sector = GLOB.map_sectors["[z]"]
if(istype(my_sector, /obj/effect/overmap/visitable/ship))
attempt_hook_up(my_sector)
if(!linked)
//Stacktrace only outside unit tests
#if !defined(UNIT_TEST)
stack_trace("Bluespace drives must be linked to a ship!")
qdel(src)
#endif
return
/obj/structure/machinery/bluespacedrive/Destroy()
QDEL_NULL(internal_gas)
QDEL_NULL(fuel_gas)
atmos_interface = null
fuel_interface = null
. = ..()
/obj/structure/machinery/bluespacedrive/update_icon()
ClearOverlays()
. = ..()
//We're energized (on)
if(energized)
AddOverlays("drive_glow")
//We're jumping
if(initiate_jump_timer_id)
AddOverlays("drive_orb")
/obj/structure/machinery/bluespacedrive/process(seconds_per_tick)
//If we have an atmos interface, and it's connected to a pipe, pump gas from it to our internal gas tank
if(atmos_interface?.node)
var/power_used = pump_gas(atmos_interface, atmos_interface.node.return_air(), internal_gas)
use_power_oneoff(power_used)
//If we have a fuel interface, and it's connected to a pipe, pump gas from it to our internal gas tank
//passive flow only, to encourage the use of higher pressures
if(fuel_interface?.node)
var/datum/gas_mixture/node_gas_mixture = fuel_interface.node.return_air()
scrub_gas(src, list(GAS_PHORON), node_gas_mixture, fuel_gas)
consume_internal_gasses()
if(power_from_gas && fuel_gas.total_moles)
if(!our_singularity)
our_singularity = new(get_turf(src), 100, FALSE, FALSE, src)
RegisterSignal(our_singularity, COMSIG_QDELETING, PROC_REF(handle_singularity_deletion))
else
if(our_singularity)
QDEL_NULL(our_singularity)
/obj/structure/machinery/bluespacedrive/CanPass(atom/movable/mover, turf/target, height, air_group)
if(istype(mover, /obj/singularity/bluespace_drive))
return TRUE
. = ..()
/**
* Compute the power from the gasses that we received, and discard them
* any non recognised gasses goes to (blue)space, aka is thrown away
*/
/obj/structure/machinery/bluespacedrive/proc/consume_internal_gasses()
SHOULD_NOT_SLEEP(TRUE)
for(var/gas_type in internal_gas.gas)
power_from_gas += internal_gas.get_gas(gas_type) * (gas_mole_to_power_factor[gas_type] * log(max(internal_gas.temperature, 1.1)))
//Reset the internal gasses, we have "consumed" them
internal_gas = new()
/**
* Moves the ship to the target location, depending on the drive charge and configuration
*/
/obj/structure/machinery/bluespacedrive/proc/move_ship()
SHOULD_NOT_SLEEP(TRUE)
var/turf/target_turf = get_jump_destination()
if(!target_turf)
return
linked.forceMove(target_turf)
/**
* Returns the destination of the jump, based on the current drive configuration
*
* Returns FALSE if the jump cannot be performed or would end up in the same turf, the new `/turf` otherwise
*/
/obj/structure/machinery/bluespacedrive/proc/get_jump_destination()
SHOULD_BE_PURE(TRUE)
SHOULD_NOT_SLEEP(TRUE)
//No fuel, no jump
if(!fuel_gas.total_moles || !power_from_gas)
return FALSE
var/turf/ship_turf = get_turf(linked)
var/datum/projectile_data/proj_data = projectile_trajectory(linked.x, linked.y, rotation, angle, (power_from_gas / (10 KILO)))
var/turf/target_turf = locate(proj_data.dest_x, proj_data.dest_y, linked.z)
//If the destination isn't where the ship can go, remain in place
if(!istype(target_turf, /turf/unsimulated/map) || istype(ship_turf, /turf/unsimulated/map/edge) || (target_turf == ship_turf))
return FALSE
else
return target_turf
///Handles the qdel of the atmos_interface
/obj/structure/machinery/bluespacedrive/proc/handle_atmos_interface_qdeleting()
SIGNAL_HANDLER
atmos_interface = null
///Handles the qdel of the atmos_interface
/obj/structure/machinery/bluespacedrive/proc/handle_fuel_interface_qdeleting()
SIGNAL_HANDLER
fuel_interface = null
///Handles the qdel of the atmos_interface
/obj/structure/machinery/bluespacedrive/proc/handle_singularity_deletion()
SIGNAL_HANDLER
our_singularity = null
///Toggles the energized state of the drive
/obj/structure/machinery/bluespacedrive/proc/toggle_energized()
SHOULD_NOT_SLEEP(TRUE)
energized = !energized
if(energized)
START_PROCESSING_MACHINE(src, MACHINERY_PROCESS_SELF)
energized_looping_sound = new(src, TRUE)
light_range = 5
light_color = "#0e3b69"
else
STOP_PROCESSING_MACHINE(src, MACHINERY_PROCESS_SELF)
QDEL_NULL(energized_looping_sound)
light_range = 0
light_color = null
//Turning the drive off while still holding a charge
if(internal_gas.total_moles || fuel_gas.total_moles)
purge_charge()
//If we're jumping, abort the jump
if(initiate_jump_timer_id)
abort_bluespace_jump()
update_icon()
update_light()
// Toggles whether the drive is primed or not (so whether the jump computer can initiate a jump or not)
/obj/structure/machinery/bluespacedrive/proc/toggle_primed()
primed = !primed
// not much going on here right now but mb a cool effect can go with it
/**
* Purges the drive charge
*
* forced - If TRUE, the purge isn't the natural effect of consuming the gasses
*/
/obj/structure/machinery/bluespacedrive/proc/purge_charge(forced)
SHOULD_NOT_SLEEP(TRUE)
if(forced)
playsound(src, 'sound/effects/supermatter.ogg', 100, TRUE)
for(var/mob/living/carbon/human/H in get_hearers_in_LOS(world.view, src))
H.flash_act(FLASH_PROTECTION_MAJOR)
H.noise_act(EAR_PROTECTION_MAJOR, 0, 1)
//Dump the power
power_from_gas = 0
//No point computing the removal of all the content since we're purging, just make a new gas mixture
fuel_gas = new()
internal_gas = new() //Technically this is reset on every processing and shouldn't be necessary, neverthless...
if(our_singularity)
QDEL_NULL(our_singularity)
update_icon()
///Sets the rotation of the drive jump
/obj/structure/machinery/bluespacedrive/proc/set_rotation(rotation)
SHOULD_NOT_SLEEP(TRUE)
if(!isnum(rotation) || rotation < 0 || rotation > 359)
stack_trace("Invalid rotation!")
return
src.rotation = rotation
/*############################
JUMP SEQUENCE PROCS
############################*/
/**
* Initiates the jump sequence
*
* Returns FALSE if the jump cannot be performed, TRUE otherwise
*/
/obj/structure/machinery/bluespacedrive/proc/initiate_jump()
SHOULD_NOT_SLEEP(TRUE)
//Already jumping
if(initiate_jump_timer_id)
return FALSE
//We don't have enough power to jump
if(fuel_gas.total_moles < minimum_phoron_moles_per_jump)
return FALSE
if(!get_jump_destination())
return FALSE
activate_bluespace_jump_event()
command_announcement.Announce("Attention all hands, Tigard-Alasdair field generation warp arrays are being energized, assume bluespace jump action stations; \
bluespace transition procedures are now in effect. Severe risk of death or serious injury to all personnel outside of the vessel. \
30 seconds to space warping.",
"C-Goliath Bluespace Drive Jump Sequence Initiated")//, 'sound/effects/ship_weapons/leviathan_safetyoff.ogg')
for(var/mob/living/affected_mob in GLOB.player_list)
//Skip all mobs that are not in a connected z level to the drive
if(!AreConnectedZLevels(affected_mob.z, z))
continue
apply_bluespace_effect(affected_mob)
affected_mob.playsound_local(affected_mob, 'sound/magic/Ethereal_Enter.ogg', 60)
initiate_jump_timer_id = addtimer(CALLBACK(src, PROC_REF(enter_bluespace)), 30 SECONDS, TIMER_UNIQUE|TIMER_STOPPABLE)
update_icon()
return TRUE
/obj/structure/machinery/bluespacedrive/proc/enter_bluespace()
SHOULD_NOT_SLEEP(TRUE)
for(var/mob/living/affected_mob in GLOB.player_list)
//Skip all mobs that are not in a connected z level to the drive
if(!AreConnectedZLevels(affected_mob.z, z))
continue
//Sorry spessbro, your story ends here if you're still outside when the ship jumps
if(istype(get_area(affected_mob), /area/space))
to_chat(affected_mob, SPAN_DANGER("Space completely warps around you, turning your body into something that a mind can barely comprehend..."))
qdel(affected_mob)
//Discharge to all the coils (flavored as warper receivers)
var/coils_discharged_to = 0
for(var/obj/structure/machinery/power/tesla_coil/coil in orange(4, src))
if(!coil.anchored)
continue
src.Beam(coil, icon_state="lightning[rand(1,12)]", icon = 'icons/effects/effects.dmi', time= 2 SECONDS)
coils_discharged_to++
//If it's less than the expected amount of coils, it failed, purge the charge and do not move the ship,
//otherwise it succeeded, move the ship
if(coils_discharged_to < 4)
//Play the sound if at least one coil got the discharge
if(coils_discharged_to)
playsound(src, 'sound/magic/lightningbolt.ogg', 40, TRUE)
visible_message(SPAN_DANGER("\The [src] fails to warp completely, not finding all the warper receivers!"))
purge_charge(forced = TRUE)
else
move_ship()
exit_bluespace()
/**
* Exits the bluespace, also called if the jump is aborted
*/
/obj/structure/machinery/bluespacedrive/proc/exit_bluespace()
SHOULD_NOT_SLEEP(TRUE)
for(var/mob/living/affected_mob in GLOB.player_list)
//Skip all mobs that are not in a connected z level to the drive
if(!AreConnectedZLevels(affected_mob.z, z))
continue
remove_bluespace_effect(affected_mob)
affected_mob.playsound_local(affected_mob, 'sound/magic/Ethereal_Exit.ogg', 60)
deactivate_bluespace_jump_event()
initiate_jump_timer_id = null
primed = FALSE
purge_charge(forced = FALSE)
update_icon()
/**
* Aborts the jump sequence
*/
/obj/structure/machinery/bluespacedrive/proc/abort_bluespace_jump()
SHOULD_NOT_SLEEP(TRUE)
//The timer means we're jumping, if not set, we're not jumping so we can't abort
if(!initiate_jump_timer_id)
return
//Purge the charge if there's any, in case of an aborted jump
if(internal_gas.total_moles || fuel_gas.total_moles)
purge_charge()
deltimer(initiate_jump_timer_id)
exit_bluespace()
visible_message(SPAN_DANGER("\The [src] bluespace warp bubble constriction field falthers, discharging!"))
/obj/structure/machinery/bluespacedrive/proc/apply_bluespace_effect(mob/living/M)
if(M.client)
to_chat(M,SPAN_NOTICE("You feel oddly light, and somewhat disoriented as everything around you shimmers and warps ever so slightly."))
M.overlay_fullscreen("bluespace", /atom/movable/screen/fullscreen/bluespace_overlay)
M.confused = 20
/obj/structure/machinery/bluespacedrive/proc/remove_bluespace_effect(mob/living/M)
if(M.client)
to_chat(M,SPAN_NOTICE("You feel rooted in the material world again."))
M.clear_fullscreen("bluespace")
///Activates the bluespace jump event, mainly to give the skybox image
/obj/structure/machinery/bluespacedrive/proc/activate_bluespace_jump_event()
SHOULD_NOT_SLEEP(TRUE)
if(istype(bluespace_jump_event))
stack_trace("Bluespace jump event already active, but somehow is being triggered again!")
bluespace_jump_event = new()
///Deactivates the bluespace jump event, mainly to return the skybox image to normal
/obj/structure/machinery/bluespacedrive/proc/deactivate_bluespace_jump_event()
SHOULD_NOT_SLEEP(TRUE)
if(QDELETED(bluespace_jump_event))
return
bluespace_jump_event.end()
bluespace_jump_event.kill()
QDEL_NULL(bluespace_jump_event)
/*######################
CONTROL CONSOLE
######################*/
/**
* # Bluespace Drive Control Console
* The console that energises/deenergises the drive and can purge gas contents.
* For use by Engineering.
*/
/obj/structure/machinery/computer/bluespacedrivecontrol
name = "\improper bluespace drive control console"
desc = "Used to control the bluespace drive."
icon_keyboard = "lightblue_key"
icon_keyboard_emis = "lightblue_key_mask"
light_color = LIGHT_COLOR_BLUE
/// The bluespace drive (`/obj/structure/machinery/bluespacedrive`) that this console controls
var/obj/structure/machinery/bluespacedrive/linked_bluespace_drive
/obj/structure/machinery/computer/bluespacedrivecontrol/Initialize()
..()
return INITIALIZE_HINT_LATELOAD
/obj/structure/machinery/computer/bluespacedrivecontrol/LateInitialize()
. = ..()
if(SSatlas.current_map.use_overmap && !linked)
var/my_sector = GLOB.map_sectors["[z]"]
if(istype(my_sector, /obj/effect/overmap/visitable/ship))
attempt_hook_up(my_sector)
for(var/obj/structure/machinery/bluespacedrive/BSD in SSmachinery.machinery)
if(linked.check_ownership(BSD))
linked_bluespace_drive = BSD
break
if(!linked_bluespace_drive)
//Stacktrace only outside unit tests
#if !defined(UNIT_TEST)
stack_trace("Bluespace drive not found!")
qdel(src)
#endif
return
RegisterSignal(linked_bluespace_drive, COMSIG_QDELETING, PROC_REF(handle_drive_deletion))
/obj/structure/machinery/computer/bluespacedrivecontrol/Destroy()
linked = null
linked_bluespace_drive = null
. = ..()
/obj/structure/machinery/computer/bluespacedrivecontrol/ui_data(mob/user)
var/list/data = list()
data["energized"] = linked_bluespace_drive.energized
data["charge"] = (linked_bluespace_drive.internal_gas.total_moles || linked_bluespace_drive.fuel_gas.total_moles) ? TRUE : FALSE
data["jumping"] = linked_bluespace_drive.initiate_jump_timer_id ? TRUE : FALSE
data["jump_power"] = linked_bluespace_drive.power_from_gas / (10 KILO)
data["fuel_gas"] = linked_bluespace_drive.fuel_gas.total_moles
data["primed"] = linked_bluespace_drive.primed
return data
/obj/structure/machinery/computer/bluespacedrivecontrol/ui_act(action, params)
. = ..()
if(.)
return
switch(action)
if("toggle_energized")
linked_bluespace_drive.toggle_energized()
if("toggle_primed")
linked_bluespace_drive.toggle_primed()
if("purge_charge")
linked_bluespace_drive.purge_charge(forced = TRUE)
/obj/structure/machinery/computer/bluespacedrivecontrol/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "BluespaceDriveControl", ui_x=500, ui_y=380)
ui.open()
/obj/structure/machinery/computer/bluespacedrivecontrol/attack_hand(mob/user)
ui_interact(user)
/// Signal handler for when the linked bluespace drive is deleted
/obj/structure/machinery/computer/bluespacedrivecontrol/proc/handle_drive_deletion()
SIGNAL_HANDLER
linked_bluespace_drive = null
/*######################
JUMP CONSOLE
######################*/
/**
* # Bluespace Drive Jump Console
* The console that actually performs the bluespace jump.
* For use by the Bridge
*/
/obj/structure/machinery/computer/bluespacedrivejump
name = "\improper bluespace drive jump console"
desc = "Used to align and engage the bluespace drive for a jump."
icon_keyboard = "lightblue_key"
icon_keyboard_emis = "lightblue_key_mask"
light_color = LIGHT_COLOR_BLUE
/// The bluespace drive (`/obj/structure/machinery/bluespacedrive`) that this console controls
var/obj/structure/machinery/bluespacedrive/linked_bluespace_drive
/obj/structure/machinery/computer/bluespacedrivejump/Initialize()
..()
return INITIALIZE_HINT_LATELOAD
/obj/structure/machinery/computer/bluespacedrivejump/LateInitialize()
. = ..()
if(SSatlas.current_map.use_overmap && !linked)
var/my_sector = GLOB.map_sectors["[z]"]
if(istype(my_sector, /obj/effect/overmap/visitable/ship))
attempt_hook_up(my_sector)
for(var/obj/structure/machinery/bluespacedrive/BSD in SSmachinery.machinery)
if(linked.check_ownership(BSD))
linked_bluespace_drive = BSD
break
if(!linked_bluespace_drive)
//Stacktrace only outside unit tests
#if !defined(UNIT_TEST)
stack_trace("Bluespace drive not found!")
qdel(src)
#endif
return
RegisterSignal(linked_bluespace_drive, COMSIG_QDELETING, PROC_REF(handle_drive_deletion))
/obj/structure/machinery/computer/bluespacedrivejump/Destroy()
linked = null
linked_bluespace_drive = null
. = ..()
/obj/structure/machinery/computer/bluespacedrivejump/ui_data(mob/user)
var/list/data = list()
data["charge"] = (linked_bluespace_drive.internal_gas.total_moles || linked_bluespace_drive.fuel_gas.total_moles) ? TRUE : FALSE
data["rotation"] = linked_bluespace_drive.rotation
data["jumping"] = linked_bluespace_drive.initiate_jump_timer_id ? TRUE : FALSE
data["jump_power"] = linked_bluespace_drive.power_from_gas / (10 KILO)
data["fuel_gas"] = linked_bluespace_drive.fuel_gas.total_moles
data["primed"] = linked_bluespace_drive.primed
return data
/obj/structure/machinery/computer/bluespacedrivejump/ui_act(action, params)
. = ..()
if(.)
return
switch(action)
if("purge_charge")
linked_bluespace_drive.purge_charge(forced = TRUE)
if("set_rotation")
linked_bluespace_drive.set_rotation(params["rotation"])
if("toggle_primed")
linked_bluespace_drive.toggle_primed()
if("jump")
var/success = linked_bluespace_drive.initiate_jump()
if(!success)
visible_message(SPAN_NOTICE("\The [src] buzzes, flashing \"Unable to acquire bluespace path: Destination unreachable, same as current position \
or jump already in progress\"!"))
/obj/structure/machinery/computer/bluespacedrivejump/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "BluespaceDriveJump", ui_x=500, ui_y=380)
ui.open()
/obj/structure/machinery/computer/bluespacedrivejump/attack_hand(mob/user)
ui_interact(user)
/// Signal handler for when the linked bluespace drive is deleted
/obj/structure/machinery/computer/bluespacedrivejump/proc/handle_drive_deletion()
SIGNAL_HANDLER
linked_bluespace_drive = null
/*######################
BSD SINGULARITY
######################*/
/obj/singularity/bluespace_drive
name = "bluespace drive singularity"
energy = 100
///The bluespace drive that made us
var/obj/structure/machinery/bluespacedrive/drive_that_made_us
///How far can the singularity move from the drive, before it starts destroying things
var/max_safe_distance_from_drive = 4
///The beam that tethers the singularity to the drive
var/datum/beam/beam_to_drive
/obj/singularity/bluespace_drive/Initialize(mapload, energy, qdel_in, alert_admins, obj/structure/machinery/bluespacedrive/drive_that_made_us)
. = ..()
src.drive_that_made_us = drive_that_made_us
RegisterSignal(drive_that_made_us, COMSIG_QDELETING, PROC_REF(handle_drive_deletion))
beam_to_drive = src.Beam(loc, icon_state="n_beam", icon = 'icons/effects/beam.dmi', time=-1, maxdistance=max_safe_distance_from_drive)
RegisterSignal(beam_to_drive, COMSIG_QDELETING, PROC_REF(handle_beam_deletion))
/obj/singularity/bluespace_drive/Destroy()
drive_that_made_us = null
QDEL_NULL(beam_to_drive)
. = ..()
/obj/singularity/bluespace_drive/check_energy()
if(is_safe())
if(drive_that_made_us.initiate_jump_timer_id)
energy = 400
else
energy = 100
. = ..()
/obj/singularity/bluespace_drive/process()
//Since it doesn't move while it's small otherwise
if(is_safe())
move()
. = ..()
/obj/singularity/bluespace_drive/eat()
if(!is_safe())
. = ..()
/obj/singularity/bluespace_drive/consume(atom/A)
if(!is_safe())
. = ..()
/obj/singularity/bluespace_drive/event()
if(!is_safe())
. = ..()
/**
* Returns whether or not the singularity is safe
*/
/obj/singularity/bluespace_drive/proc/is_safe()
if(!drive_that_made_us || !beam_to_drive)
return FALSE
// if(get_dist(src, drive_that_made_us) > max_safe_distance_from_drive)
// return FALSE
return TRUE
/obj/singularity/bluespace_drive/proc/handle_drive_deletion()
SIGNAL_HANDLER
drive_that_made_us = null
QDEL_IN(src, 10 SECONDS)
/obj/singularity/bluespace_drive/proc/handle_beam_deletion()
SIGNAL_HANDLER
beam_to_drive = null
/*####################
BSD JUMP EVENT
####################*/
/**
* Bluespace Jump event, never triggers autonomously, only the BSD Drive can trigger it
*
* Mainly exist for the skybox shenanigans
*/
/datum/event/bluespace_jump
event_meta = new /datum/event_meta/bluespace_jump()
has_skybox_image = TRUE
no_fake = TRUE
endWhen = INFINITY //Event stopped manually
/datum/event/bluespace_jump/get_skybox_image()
var/image/res = overlay_image('icons/skybox/ionbox.dmi', "ions", color_matrix_rotate_hue(rand(-3,3)*5), RESET_COLOR|KEEP_TOGETHER)
res.blend_mode = BLEND_INSET_OVERLAY
res.add_filter("displace", 1, list("icon" = icon('icons/skybox/ionbox.dmi', "ions")))
res.alpha = 0
animate(res, alpha = 255, time = (5 SECONDS), easing = (CIRCULAR_EASING|EASE_OUT))
return res
/**
* Bluespace Jump event metadata
*/
/datum/event_meta/bluespace_jump
enabled = FALSE
weight = 0
/*##########################
FLUFF INGAME MANUAL
##########################*/
/obj/item/paper/fluff/bluespacedrive_manual
set_unsafe_on_init = TRUE
/obj/item/paper/fluff/bluespacedrive_manual/New(loc, ...)
name = "[/obj/structure/machinery/bluespacedrive::name] Field Handbook"
desc = "A manual illustrating the basic operation of the [/obj/structure/machinery/bluespacedrive::name], useful for those who missed the last 300 years of history."
info = {"
<h2>
<b>[/obj/structure/machinery/bluespacedrive::name] Field Handbook - Quick Reference</b><BR>
</h2>
<font size = "1">
<i>"How to use the [/obj/structure/machinery/bluespacedrive::name] for bluespace jumping."</i>
</font>
<BR>
<BR>
<BR>
<font size = "2">
<h3>The [/obj/structure/machinery/bluespacedrive::name] comes equipped with:</h3><BR>
<ul style="list-style:circle">
<li>Two separate gas feeding circuits: A Phoron line on the west and a moderator gas mix line on the north.</li>
<li>Two independent power circuits: The primary circuit, which feeds the outer shield ring, the compartment APC and the drive itself, and the secondary circuit, which feeds the inner shield ring.</li>
<li>A same-room control console.</li>
</ul>
<BR>
<BR>
<BR>
<h3>Operational Instructions:</h3><BR>
<ol>
<li>Energize and charge the two SMES circuits to an acceptable level.</li>
<li>Wrench down the coils and the outer shield ring generators, wrench down and weld down the inner shield ring generators and the emitters.</li>
<li>Prepare [/obj/structure/machinery/bluespacedrive::minimum_phoron_moles_per_jump] moles of Phoron to be pulled into the drive, on the Phoron line.</li>
<li>Prepare the moderator gas mixture to be fed into the drive, on the moderator gas mix line.</li>
<li>Once sure the calculations for the gasses are correct and the drive can feed, activate the emitters.</li>
<li>Wait for the charge bar indicators on the inner shield generators to reach 100%.</li>
<li>Operate the inner shield generators to turn them on. <span style="color:red;">Move away from them as soon as activated, the shield can and will repel you too!</span></li>
<li>Unlock with your ID card and activate the outer shield generators, if non-specialized personnel is present, lock them back after activation.</li>
<li>Operate the control console, energize the drive and observe the gasses being fed into it.</li>
<li>Once gas injections are complete, the drive can be primed which will unlock the jump computer.</li>
<li>The Bridge can now set the rotation and engage the jump. Tthe drive will take approximately 30 seconds to energize the field, then it will jump automatically.</li>
<li><b><span style="color:red;">Announce the jump and ensure no personnel is outside the ship!</span></b></li>
<li>De-energize the drive in the control console.</li>
<li>Disable the secondary circuit SMES output to disable the emitters, and wait for the inner shield generators to discharge and the shield to extinguish.</li>
<li>Disable the outer shield generators.</li>
</ol>
<BR>
<BR>
<BR>
<h3>Emergency Procedure:</h3><BR>
Should the drive need to be shut down for an emergency, or to abort the jump, it's possible to de-energize it from the control console.<BR>
Likewise, it's possible to dump unwanted gas mixtures contained in it via the appropriate dump button located in the control console.<BR>
Dumping gasses will cause the gasses to be lost, it's recommended to only do that in extreme circumstances, and pump out the Phoron from the Phoron line before.<BR>
Please note, the dissipation of the stored energy would cause a bluespace flash across the ship, which can cause temporary hearing and vision disturbances, when the drive is de-energized
while operational or the gasses are dumped. If time allows, the crew should be informed about it.<BR>
<BR>
<BR>
<h4><i>Dr. Marivek's notes:</i></h3><BR>
The [/obj/structure/machinery/bluespacedrive::name] will create the bluespace-field-driver singularity only when energized and fed with any valid gas in the moderator circuit and the Phoron line.<BR>
Any quantity above [/obj/structure/machinery/bluespacedrive::minimum_phoron_moles_per_jump] moles of Phoron is wasted, precise calculation is therefore encourage for efficiency.<BR>
Various gasses can be used for the moderation mix, any gas that is not valid will simply be absorbed without contributing to the bluespace effect.<BR>
Temperature of the moderation gas mixture is also influential, in my observations, ontop of the specific gas and the amount. Higher temperatures seems to increase the effect per mole.<BR>
The field-driver singularity is not self-sustaining, and can be destroyed by depowering the [/obj/structure/machinery/bluespacedrive::name].<BR>
Should the field-driver singularity become loose from the quantum entanglement tunnel, unless fed, it won't destroy more than its size and won't move.<BR>
It has been noted that, at times, it has been observed to escape the first shield ring. It is extremely important to ensure both shield rings are engaged for maximum safety.
</font>
"}
. = ..()