mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-22 04:22:39 +01:00
**Overview:** The first huge fuckoff mapping PR for giving the Horizon enough extra space to be able to comfortably map on it for the duration before NBT2 and not be super cramped (extends aft by 6 turfs). Includes a SECOND vault to heist at the back of the ship and a lot of maint area people can repurpose. Notably, this also removes the Xenobio Hazardous Containment room and the Medical Emergency Storage room (contents of the latter have been moved). Otherwise, y'all got more ship. **Map Images (OUTDATED NOW):** <img width="2453" height="868" alt="Screenshot 2025-10-16 141649" src="https://github.com/user-attachments/assets/be9a540d-af92-46b4-b59f-e298204a678a" /> <img width="2450" height="940" alt="Screenshot 2025-10-16 141702" src="https://github.com/user-attachments/assets/b96f3f3e-dd4b-4457-9c5c-1f09f8bb7a00" /> <img width="2452" height="895" alt="Screenshot 2025-10-16 141714" src="https://github.com/user-attachments/assets/9a16e55d-8386-46d9-a3d3-d4e5a0ff6ec0" /> **Misc Features:** <img width="1069" height="685" alt="Screenshot 2025-10-16 141727" src="https://github.com/user-attachments/assets/89c14f85-f476-4f91-bd02-7c36f36a4418" /> <img width="983" height="825" alt="Screenshot 2025-10-16 141736" src="https://github.com/user-attachments/assets/6b20da20-982c-4ec1-b252-3507f1211e94" /> <img width="1382" height="951" alt="Screenshot 2025-10-16 141743" src="https://github.com/user-attachments/assets/fdfd683d-33a4-47e3-9df8-dec1f9286598" /> <img width="2405" height="863" alt="Screenshot 2025-10-16 141803" src="https://github.com/user-attachments/assets/c539c4bd-4a8f-4326-a30b-5a1d09eca26b" /> **changes:** - qol: "Hugely expands the Horizon's maints and adjusts/expands much of the aft of the ship." - rscadd: "Adds a new Vault to Horizon (Deck 3 aft, behind the Gym)." - rscdel: "Removes Xenobiology Hazardous Specimens compartment." - rscdel: "Removes Medical Emergency Storage compartment." - spellcheck: "Replaces a few mentions of 'room' with 'compartment.'" - spellcheck: "Renames the Bridge Break Room to Bridge Wardroom." - spellcheck: "Renames the Kitchen to the Galley." - spellcheck: "Renames the Dining Hall to the Mess Hall." - spellcheck: "Renames each Washroom to the Head."
773 lines
24 KiB
Plaintext
773 lines
24 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/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/machinery/atmospherics/portables_connector/atmos_interface
|
|
|
|
/// The interface used to give fuel (phoron) to the drive
|
|
var/obj/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
|
|
|
|
/// 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/machinery/bluespacedrive/Initialize()
|
|
..()
|
|
|
|
//Thanks to byond bug 2925542
|
|
bound_y = -64
|
|
bound_height = 128
|
|
bound_x = -32
|
|
bound_width = 96
|
|
|
|
atmos_interface = locate(/obj/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/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/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/machinery/bluespacedrive/Destroy()
|
|
QDEL_NULL(internal_gas)
|
|
QDEL_NULL(fuel_gas)
|
|
|
|
atmos_interface = null
|
|
fuel_interface = null
|
|
|
|
. = ..()
|
|
|
|
/obj/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/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/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/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/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/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/machinery/bluespacedrive/proc/handle_atmos_interface_qdeleting()
|
|
SIGNAL_HANDLER
|
|
|
|
atmos_interface = null
|
|
|
|
///Handles the qdel of the atmos_interface
|
|
/obj/machinery/bluespacedrive/proc/handle_fuel_interface_qdeleting()
|
|
SIGNAL_HANDLER
|
|
|
|
fuel_interface = null
|
|
|
|
///Handles the qdel of the atmos_interface
|
|
/obj/machinery/bluespacedrive/proc/handle_singularity_deletion()
|
|
SIGNAL_HANDLER
|
|
|
|
our_singularity = null
|
|
|
|
///Toggles the energized state of the drive
|
|
/obj/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()
|
|
|
|
/**
|
|
* Purges the drive charge
|
|
*
|
|
* forced - If TRUE, the purge isn't the natural effect of consuming the gasses
|
|
*/
|
|
/obj/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/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/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/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/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/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
|
|
purge_charge(forced = FALSE)
|
|
update_icon()
|
|
|
|
|
|
/**
|
|
* Aborts the jump sequence
|
|
*/
|
|
/obj/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/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/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/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/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 controls the bluespace drive
|
|
*/
|
|
/obj/machinery/computer/bluespacedrive
|
|
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/machinery/bluespacedrive`) that this console controls
|
|
var/obj/machinery/bluespacedrive/linked_bluespace_drive
|
|
|
|
/obj/machinery/computer/bluespacedrive/Initialize()
|
|
..()
|
|
|
|
return INITIALIZE_HINT_LATELOAD
|
|
|
|
/obj/machinery/computer/bluespacedrive/LateInitialize()
|
|
. = ..()
|
|
|
|
linked_bluespace_drive = locate() in get_area(src)
|
|
|
|
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/machinery/computer/bluespacedrive/Destroy()
|
|
linked_bluespace_drive = null
|
|
|
|
. = ..()
|
|
|
|
|
|
/obj/machinery/computer/bluespacedrive/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["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
|
|
|
|
return data
|
|
|
|
|
|
/obj/machinery/computer/bluespacedrive/ui_act(action, params)
|
|
. = ..()
|
|
if(.)
|
|
return
|
|
|
|
switch(action)
|
|
|
|
if("toggle_energized")
|
|
linked_bluespace_drive.toggle_energized()
|
|
|
|
if("purge_charge")
|
|
linked_bluespace_drive.purge_charge(forced = TRUE)
|
|
|
|
if("set_rotation")
|
|
linked_bluespace_drive.set_rotation(params["rotation"])
|
|
|
|
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/machinery/computer/bluespacedrive/ui_interact(mob/user, datum/tgui/ui)
|
|
ui = SStgui.try_update_ui(user, src, ui)
|
|
if(!ui)
|
|
ui = new(user, src, "BluespaceDrive", ui_x=500, ui_y=380)
|
|
ui.open()
|
|
|
|
|
|
/obj/machinery/computer/bluespacedrive/attack_hand(mob/user)
|
|
ui_interact(user)
|
|
|
|
/// Signal handler for when the linked bluespace drive is deleted
|
|
/obj/machinery/computer/bluespacedrive/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/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/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/machinery/bluespacedrive::name] Field Handbook"
|
|
desc = "A manual illustrating the basic operation of the [/obj/machinery/bluespacedrive::name], useful for those who missed the last 300 years of history."
|
|
|
|
info = {"
|
|
<h2>
|
|
<b>[/obj/machinery/bluespacedrive::name] Field Handbook - Quick Reference</b><BR>
|
|
</h2>
|
|
|
|
<font size = "1">
|
|
<i>"How to use the [/obj/machinery/bluespacedrive::name] for bluespace jumping."</i>
|
|
</font>
|
|
|
|
<BR>
|
|
<BR>
|
|
<BR>
|
|
|
|
<font size = "2">
|
|
<h3>The [/obj/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/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>Set the rotation of the jump on the knob, in absolute galactic degrees.</li>
|
|
<li><b><span style="color:red;">Announce the jump and ensure no personnel is outside the ship!</span></b></li>
|
|
<li>Activate the jump, the drive will take approximately 30 seconds to energize the field, then it will jump automatically.</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/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/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/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>
|
|
"}
|
|
|
|
. = ..()
|