Splits Pilot: SpaCecRaft intO three levelS and Adds Piloting Education BacKgrounds (#22673)

These were some of the first given feedback for skills, so I may as well
implement it.

Piloting is now split into three levels like other skills which note
what pilot class of vessel you may comfortably pilot.
(Familiar) **Shuttle Pilot** is for all landables: Spark, Canary,
Intrepid, the Quark, and the like are all equal under it.
(Trained) **Class II Pilot** covers most ships, which are "overmap-only"
and unable to land or dock.
(Professional) **Class IV Pilot** covers only the Horizon normally, but
design-wise extends to whatever is the main player ship, or for anything
massive

**Antags get Professional Pilot, so they can always do ship hijack
gimmicks without worry.**

As a convenience to make Bridge personnel stand out, Professional/Class
IV Pilots can deduce their current overmap coordinate from examining
space on help intent for 3s. There's no way to directly link to the
overmap, so on the backend, this ability briefly references an existing
ship console.

### Design

Class II and IV are pre-existing terms in-lore, used on the Interstellar
Travel page to refer to civilian size classes.
With how important each level of piloting is, they cost _+4 points_ each
instead of going 2 -> 4 -> 8. This lets there exist the occasional pilot
character from any background, but it's _always_ an investment and
piloting the Horizon stays hard without training.
As Familiar currently costs 6 points, this is effectively a 2-point buff
for most cases as you'll rarely have to pilot non-shuttles.
(**EDIT**: Piloting levels are now 4 -> 8 -> 10 so there's a bit of
flexibility to have an extra skill for Professional Pilots from
Expeditionary Trade)

#### The _**real meat**_ of this PR...
is that you can now attempt to pilot vessels a level higher than you
with penalties, so there's now a failure spectrum should you manage to
access an adjacent-class ship rather than always being hard-locked. The
penalties affect acceleration, slowing, turning, and rolling. They're
most extreme for Shuttle and Class IV to represent how clueless an
unlicensed pilot would be and how complex the Horizon realistically is
to operate.

With smart usage of autopilot, you can actually find a way to travel
normal-ish. I think this is a fun interaction to have for underskilled
characters, and makes autopilot actually have a use as it otherwise
kills you. Maybe Bridge personnel can give lessons to Class II pilots
with it.

### Piloting Education Backgrounds

Coming are THREE piloting education backgrounds: Flight Academy, Fleet
Training, and Expeditionary Trade.

#### ALL GET _Familiar Electrical Engineering,_ _Familiar Atmospheric_

(EDIT: Flight Academy is now the only background that gets Familiar
Mechanical Engineering, this makes them stand out as being notably
handy/utility-ready for emergencies, but other backgrounds can still
easily match them with points.
Fleet Training has Tenacity down to Trained for character variety,
though tenacity is very slight buffs and hard to notice.
Expeditionary Trade now uses Familiar Firearms over Familiar Armed
Combat as it's more immediately important.)

Electrical Engineering now lets you use a power cell on an unpowered
ship console to give it emergency battery life based on the charge. This
helps with cases of being stranded from an APC broken by a meteor, a
high-capacity cell can give 10m or more based on Electrical level. I may
expand this bypass mechanic to all consoles in the future.
Atmospherics skill has no implementation currently, but dealing with
breaches or cycling on shuttles is too important.

Flight Academy - BC, XO, Captain
*Professional Piloting, Trained Leadership, Familiar Mechanical
Engineering*
> "You are at least 25 years of age, with the best navigation training
the Spur can offer, vessel handiness in a pinch, and the know-how for
reining in or assuring passengers for the voyage."

Flight Academy has Leadership honestly just because I didn't want Fleet
Training to look too good, and because I think they can rock the "this
is your pilot speaking" in a cool way. Bridge personnel are usually the
ones that have to wraggle people on away sites, especially during
events.
Mechanical Engineering allows them to make machine frames of ship
consoles in emergencies.


Fleet Training - BC, XO, Captain 
*Professional Piloting, Trained Firearms, Trained Tenacity*
> "You are at least 25 years of age, with the most extensive navigation
training possible and military discipline to back it up. You're a steady
shot in emergencies and, damn it-- You. Go. Down. With. The. Ship."

This was made because a player informed me many BC and XOs choose
military backgrounds, and the +4 points design would prevent that. Fleet
Training isn't the same as Military Training, but having all of Piloting
gives you 6 points free to match MT if wanted. The high Tenacity is
primarily for surviving in ship combat, where you'll probably
bleed/suffocate to death.

Expeditionary Trade - Miners, Xenology roles, OM, RD
*Familiar Piloting, Familiar Firearms, Familiar Medicine*
> "You've developed trade skills for a career of expeditions. You are at
home in a shuttle piloting to and from for an average day's work. You
can even hit a shot or tend to wounds when things eventually get
unsafe."

This is for Miner and Xenoarch primarily. An expedition is just any
journey with an objective, all roles revolving around piloting shuttles
to an objective needs to be able to hold their own if they ever find
carp or have an accident, especially since they'll likely be alone.

#### MISC stuff

corrected shaper gear comments I left wrong

Hotwiring piloting consoles now checks for Familiar in Electrical
Engineering. Its visible emote also now looks identical to attempting an
emergency bypass at first glance, so you can sneakily attempt one with
an unpowered console.

The Doctor of Psychology education background now gives Trained in
Leadership. This was intended to be uncommented, but the person forgot
to do it.

Research Directors now need to have Familiar/Shuttle Pilot. According to
the Guide to Piloting wikipage, they're supposed to be able to fly the
Intrepid and Quark for expeditions, and likely mirroring how the OM can
fly the Spark, but an RD can spawn completely incapable of piloting
currently.

---------

Signed-off-by: runecap <43975590+runecap@users.noreply.github.com>
Co-authored-by: VMSolidus <evilexecutive@gmail.com>
This commit is contained in:
runecap
2026-07-08 17:13:18 +00:00
committed by GitHub
parent e63355d56c
commit 441ef5805d
17 changed files with 366 additions and 23 deletions
@@ -71,9 +71,7 @@
SPECIES_SKRELL_AXIORI = 60
)
skills = list(
/* Uncomment this block after finishing the Leadership skill. Psychologists should be able to give people morale bonuses as a mechanic.
/singleton/skill/leadership = SKILL_LEVEL_TRAINED,
*/
/singleton/skill/pharmacology = SKILL_LEVEL_FAMILIAR,
/singleton/skill/medicine = SKILL_LEVEL_FAMILIAR,
/singleton/skill/anatomy = SKILL_LEVEL_FAMILIAR,
+53
View File
@@ -25,3 +25,56 @@
SPECIES_SKRELL = 55,
SPECIES_SKRELL_AXIORI = 55
)
/singleton/education/flight_academy
name = "Flight Academy"
description = "You are at least 25 years of age, with the best navigation training the Spur can offer, vessel handiness in a pinch, and the know-how for reining in or assuring passengers for the voyage."
jobs = list("Bridge Crew", "Executive Officer", "Captain")
minimum_character_age = list(
SPECIES_HUMAN = 25,
SPECIES_SKRELL = 60,
SPECIES_SKRELL_AXIORI = 60
)
skills = list(
/singleton/skill/pilot_spacecraft = SKILL_LEVEL_PROFESSIONAL,
/singleton/skill/electrical_engineering = SKILL_LEVEL_FAMILIAR,
/singleton/skill/atmospherics_systems = SKILL_LEVEL_FAMILIAR,
/singleton/skill/mechanical_engineering = SKILL_LEVEL_FAMILIAR, //To make a machine frame for ship consoles in emergencies
/singleton/skill/leadership = SKILL_LEVEL_TRAINED
)
/singleton/education/fleet_training
name = "Fleet Training"
description = "You are at least 25 years of age, with the most extensive navigation training possible and military discipline to back it up. You're a steady shot in emergencies \
and, damn it-- You. Go. Down. With. The. Ship."
jobs = list("Bridge Crew", "Executive Officer", "Captain")
minimum_character_age = list(
SPECIES_HUMAN = 25,
SPECIES_SKRELL = 60,
SPECIES_SKRELL_AXIORI = 60
)
skills = list(
/singleton/skill/pilot_spacecraft = SKILL_LEVEL_PROFESSIONAL,
/singleton/skill/electrical_engineering = SKILL_LEVEL_FAMILIAR,
/singleton/skill/atmospherics_systems = SKILL_LEVEL_FAMILIAR,
/singleton/skill/firearms = SKILL_LEVEL_TRAINED,
/singleton/skill/tenacity = SKILL_LEVEL_TRAINED
)
/singleton/education/expeditionary_trade
name = "Expeditionary Trade"
description = "You've developed trade skills for a career of expeditions. You are at home in a shuttle piloting to and from for an average day's work. You can even hit a shot or tend to \
wounds when things eventually get unsafe."
jobs = list("Shaft Miner", "Xenoarchaeologist", "Xenobiologist", "Xenobotanist", "Operations Manager", "Research Director")
minimum_character_age = list(
SPECIES_HUMAN = 18,
SPECIES_SKRELL = 60,
SPECIES_SKRELL_AXIORI = 60
)
skills = list(
/singleton/skill/pilot_spacecraft = SKILL_LEVEL_FAMILIAR,
/singleton/skill/electrical_engineering = SKILL_LEVEL_FAMILIAR,
/singleton/skill/atmospherics_systems = SKILL_LEVEL_FAMILIAR,
/singleton/skill/firearms = SKILL_LEVEL_FAMILIAR,
/singleton/skill/medicine = SKILL_LEVEL_FAMILIAR
)
+2 -1
View File
@@ -234,11 +234,12 @@
/datum/language/bug/broadcast(var/mob/living/speaker,var/message,var/speaker_mask)
log_say("[key_name(speaker)] : ([name]) [message]")
if(is_lemurian_sea_sector())
to_chat(speaker, SPAN_WARNING("You attempt to reach the Hivenet, but find nothing!"))
return
var/mob/living/carbon/human/H = speaker //Check for Preimminent Shaper robes, which obscure Hive affiliation
var/mob/living/carbon/human/H = speaker //Check for Preimminent Shaper helmet, which obscure Hive affiliation
var/obj/item/clothing/head/shaper/helmet = H.get_equipped_item(slot_head)
if(!speaker_mask)
speaker_mask = speaker.real_name
@@ -483,7 +483,7 @@
return get_id_name("Unknown")
if( head && (head.flags_inv&HIDEFACE) )
return get_id_name("Unknown") //Likewise for hats
if(istype(wear_suit, /obj/item/clothing/suit/vaurca/shaper)) //Check for Preimminent Shaper helmet which obscures Hive affiliation
if(istype(wear_suit, /obj/item/clothing/suit/vaurca/shaper)) //Check for Preimminent robes which obscures Hive affiliation
var/list/hiveless_name = splittext(real_name, " ") //then remove Hive surname, ignore ID for obvious reason.
return hiveless_name[1]
var/face_name = get_face_name()
+82 -4
View File
@@ -254,6 +254,8 @@
var/ndir = text2num(params["roll"])
if(ishuman(usr))
var/mob/living/carbon/human/H = usr
var/piloting_difference = H.GetComponent(PILOT_SPACECRAFT_SKILL_COMPONENT)?.skill_level - connected.pilot_class
var/dir_to_move = turn(connected.dir, ndir == WEST ? 90 : -90)
var/turf/new_turf = get_step(connected, dir_to_move)
if(new_turf.x > SSatlas.current_map.overmap_size || new_turf.y > SSatlas.current_map.overmap_size)
@@ -262,6 +264,13 @@
if(do_after(H, 1 SECOND) && connected.can_combat_roll())
visible_message(SPAN_DANGER("[H] tilts the yoke all the way to the [ndir == WEST ? "left" : "right"]!"))
connected.combat_roll(ndir)
if(piloting_difference <= 0 && prob(60)) //A lack of difference means skill level (1-4) is less than pilot_class (1-3)
ndir = pick(NORTH, SOUTH)
connected.forceMove(get_step(connected, ndir))
if(connected.pilot_class != PILOTING_CLASS_TWO && prob(70))
connected.forceMove(get_step(connected, ndir))
to_chat(H, SPAN_WARNING("You don't need to be an expert to realize you fumbled that."))
H.visible_message(SPAN_DANGER("[H]'s grip slips!"), SPAN_DANGER("Your handling slips and the vessel teeters off trajectory!"))
if(issilicon(usr))
var/mob/living/silicon/H = usr
var/dir_to_move = turn(connected.dir, ndir == WEST ? 90 : -90)
@@ -288,7 +297,24 @@
if(isliving(usr))// AI and robots are allowed to pilot now!
if (action == "move")
if(prob(usr.confused * 5))
var/mob/living/H = usr
var/piloting_difference = H.GetComponent(PILOT_SPACECRAFT_SKILL_COMPONENT)?.skill_level - connected.pilot_class
if(piloting_difference <= 0)
to_chat(H, SPAN_NOTICE("You begin burning up the vessel's speed..."))
if((connected.pilot_class != PILOTING_CLASS_TWO && do_after(H, 2 SECONDS)) || (connected.pilot_class == PILOTING_CLASS_TWO && do_after(H, 1 SECOND)))
connected.relaymove(H, connected.dir, accellimit)
if(prob(65)) //Can't ignore the 1s burn_delay, so manually do the proc to adjust speed instead
var/acceleration = min(connected.get_burn_acceleration(), accellimit)
var/theta = dir2degree(connected.dir)
if(connected.pilot_class == PILOTING_CLASS_MAX && prob(70))
acceleration *= 2
to_chat(H, SPAN_DANGER("Too fast!"))
connected.adjust_speed(acceleration * cos(theta), acceleration * sin(theta))
H.visible_message(SPAN_WARNING("[H] motions strongly at \the [src]"), SPAN_WARNING("The speed picks up faster than anticipated."))
else
return
if(prob(H.confused * 5))
params["turn"] = pick("45", "-45")
else
connected.relaymove(usr, connected.dir, accellimit)
@@ -296,7 +322,35 @@
if (action == "turn")
var/ndir = text2num(params["turn"])
if(connected.can_turn())
if(ishuman(usr))
var/mob/living/carbon/human/H = usr
var/piloting_difference = H.GetComponent(PILOT_SPACECRAFT_SKILL_COMPONENT)?.skill_level - connected.pilot_class
if(connected.can_turn() && piloting_difference <= 0)
to_chat(H, SPAN_NOTICE("You feel you can work a turn [ndir == WEST ? "left" : "right"] here..."))
if((connected.pilot_class != PILOTING_CLASS_TWO && do_after(H, 3 SECONDS)) || (connected.pilot_class == PILOTING_CLASS_TWO && do_after(H, 1 SECOND)))
connected.turn_ship(ndir)
if(prob(60))
connected.turn_ship(ndir)
if(connected.pilot_class == PILOTING_CLASS_MAX && prob(70))
connected.turn_ship(ndir)
to_chat(H, SPAN_DANGER("Too far!"))
H.visible_message(SPAN_WARNING("[H] swerves inaccurately on \the [src]"), SPAN_WARNING("You're imprecise and make a wider turn."))
addtimer(CALLBACK(src, PROC_REF(refresh_ui)), min(connected.vessel_mass / 10, 1) SECONDS + 1)
else // When moving/interrupted mid-action, always get worse result
connected.turn_ship(ndir)
connected.turn_ship(ndir)
if(prob(70))
connected.turn_ship(ndir)
to_chat(H, SPAN_DANGER("Damn it!"))
H.visible_message(SPAN_WARNING("[H] swerves loosely on \the [src]."), SPAN_WARNING("Your negligence overshoots the turning."))
addtimer(CALLBACK(src, PROC_REF(refresh_ui)), min(connected.vessel_mass / 10, 1) SECONDS + 1)
else if(connected.can_turn()) // Normal, w/o penalty
connected.turn_ship(ndir)
addtimer(CALLBACK(src, PROC_REF(refresh_ui)), min(connected.vessel_mass / 10, 1) SECONDS + 1)
else if(connected.can_turn()) // For AI and robots
connected.turn_ship(ndir)
addtimer(CALLBACK(src, PROC_REF(refresh_ui)), min(connected.vessel_mass / 10, 1) SECONDS + 1)
@@ -314,8 +368,32 @@
connected.combat_turn(ndir)
if (action == "brake")
connected.decelerate()
addtimer(CALLBACK(src, PROC_REF(refresh_ui)), connected.burn_delay + 1)
if(ishuman(usr))
var/mob/living/carbon/human/H = usr
var/piloting_difference = H.GetComponent(PILOT_SPACECRAFT_SKILL_COMPONENT)?.skill_level - connected.pilot_class
to_chat(H, SPAN_NOTICE("You begin clamping down the vessel's speed..."))
if(piloting_difference <= 0)
if((connected.pilot_class != PILOTING_CLASS_TWO && do_after(H, 2 SECONDS)) || (connected.pilot_class == PILOTING_CLASS_TWO && do_after(H, 1 SECOND)))
connected.decelerate()
if(prob(60)) // Can't ignore the 1s burn_delay, so manually do decelerate()'s effects instead
var/magnitude_velocity = ((connected.speed[1] ** 2) + (connected.speed[2] **2)) ** (1/2)
var/alpha = min(connected.get_burn_acceleration(), magnitude_velocity)
var/delta_x = -(connected.speed[1] / magnitude_velocity) * alpha
var/delta_y = -(connected.speed[2] / magnitude_velocity) * alpha
if(connected.pilot_class != PILOTING_CLASS_TWO && prob(70))
delta_x *= 2
delta_y *= 2
connected.adjust_speed(delta_x, delta_y)
to_chat(H, SPAN_WARNING("That clamp was stronger than intended."))
else
return
else // Normal, w/o penalty
connected.decelerate()
addtimer(CALLBACK(src, PROC_REF(refresh_ui)), connected.burn_delay + 1)
else
connected.decelerate()
addtimer(CALLBACK(src, PROC_REF(refresh_ui)), connected.burn_delay + 1)
if (action == "apilot")
autopilot = !autopilot
+72 -5
View File
@@ -16,14 +16,47 @@ somewhere on that shuttle. Subtypes of these can be then used to perform ship ov
/// For hotwiring, how many cycles are needed. This decreases by 1 each cycle and triggers at 0
var/hotwire_progress = 8
// Time window for emergency power from Pilot: Spacecraft + Electrical Engineering skills.
var/emergency_power_window
/obj/structure/machinery/computer/antagonist_hints(mob/user, distance, is_adjacent)
. += ..()
. += "Consoles like these are typically access-locked."
. += "You can remove this lock with <b>wirecutters</b>, but it would take awhile! Alternatively, you can also use a cryptographic sequencer (emag) for instant removal."
. += "Hotwiring with wirecutters looks identical to attempting an emergency power bypass at first glance. You can avoid early suspicion doing it with equipment power out."
/obj/structure/machinery/computer/mechanics_hints(mob/user, distance, is_adjacent)
. += ..()
if(user.GetComponent(ELECTRICAL_ENGINEERING_SKILL_COMPONENT)?.skill_level >= SKILL_LEVEL_FAMILIAR)
. += "Ship consoles like these can be directly given batterylife in emergencies. Simply use a power cell on it when unpowered to attempt a bypass with some of the charge." \
+ " Batterylife efficiency scales with Electrical Engineering and bypass completion is faster when Familiar with Piloting Spacecraft."
/obj/structure/machinery/computer/ship/attackby(obj/item/attacking_item, mob/user)
if(attacking_item.tool_behaviour == TOOL_CABLECOIL) // Repair from hotwire
var/electrical_level = user.GetComponent(ELECTRICAL_ENGINEERING_SKILL_COMPONENT)?.skill_level
if(electrical_level > SKILL_LEVEL_UNFAMILIAR && (emergency_power_window || stat & NOPOWER) && istype(attacking_item, /obj/item/cell))
var/obj/item/cell/battery = attacking_item
var/pilot_level = user.GetComponent(PILOT_SPACECRAFT_SKILL_COMPONENT)?.skill_level
user.visible_message("<b>[user]<b> opens a panel underneath \the [src]...", SPAN_NOTICE("You start searching for the power port to attempt an emergency power bypass..."))
emergency_power_window = world.time
if(pilot_level <= SKILL_LEVEL_UNFAMILIAR && Adjacent(user) && user.get_active_hand() == battery)
if(do_after(user, 3 SECONDS))
to_chat(user, SPAN_NOTICE("Although unfamiliar with spacecraft to find it fast, your electrical intuition knows there's a port somewhere..."))
else
user.visible_message("<b>[user]</b> closes the panel underneath \the [src].", SPAN_WARNING("You need to stay and look longer if you want to perform a bypass."))
return
while(battery.percent() > 0 && Adjacent(user) && user.get_active_hand() == battery)
if(do_after(user, 3 SECONDS))
if((pilot_level <= SKILL_LEVEL_UNFAMILIAR && do_after(user, 2 SECONDS)) || pilot_level >= SKILL_LEVEL_FAMILIAR)
var/bypass_value = battery.maxcharge/10
emergency_power_window += bypass_value/((100 - pilot_level * 3)/electrical_level) SECONDS // should be 10m for high-caps
playsound(src.loc, 'sound/machines/click.ogg', 30)
battery.charge -= bypass_value
user.visible_message("<b>[user]</b> presses into some port with a click.<BR><i>\The [src]'s power bypass timer notifies there are <b>[round((emergency_power_window - world.time)/10)]</b> seconds of emergency power remaining.</i>", SPAN_NOTICE("You press into the port with \the [battery] transferring 10% into \the [src] and leaving \the [battery] with [battery.percent()]%<BR>\The [src]'s power bypass timer notifies there are <b>[round((emergency_power_window - world.time)/10)]</b> seconds of emergency power remaining."))
stat &= ~NOPOWER
update_icon()
return
if(attacking_item.tool_behaviour == TOOL_CABLECOIL && electrical_level > SKILL_LEVEL_UNFAMILIAR) // Repair from hotwire
var/obj/item/stack/cable_coil/C = attacking_item
if(hotwire_progress >= initial(hotwire_progress))
to_chat(usr, SPAN_BOLD("\The [src] does not require repairs."))
@@ -41,12 +74,12 @@ somewhere on that shuttle. Subtypes of these can be then used to perform ship ov
playsound(src.loc, 'sound/items/Deconstruct.ogg', 30, TRUE)
return
if(attacking_item.tool_behaviour == TOOL_WIRECUTTER) // Hotwiring
if(attacking_item.tool_behaviour == TOOL_WIRECUTTER && electrical_level > SKILL_LEVEL_UNFAMILIAR) // Hotwiring
if(!req_access && !req_one_access && !emagged) // Already hacked/no need to hack
to_chat(user, SPAN_BOLD("[src] is not access-locked."))
return
// Begin hotwire
user.visible_message("<b>[user]</b> opens a panel underneath \the [src] and starts snipping wires...", SPAN_BOLD("You open the maintenance panel and attempt to hotwire \the [src]..."))
user.visible_message("<b>[user]</b> opens a panel underneath \the [src]...", SPAN_BOLD("You open the maintenance panel and attempt to hotwire \the [src]..."))
while(hotwire_progress > 0)
if(do_after(user, 15 SECONDS, src, DO_UNIQUE))
hotwire_progress--
@@ -60,15 +93,46 @@ somewhere on that shuttle. Subtypes of these can be then used to perform ship ov
return ..()
/obj/structure/machinery/computer/ship/attack_hand(mob/user)
var/piloting_difference = user.GetComponent(PILOT_SPACECRAFT_SKILL_COMPONENT)?.skill_level - connected.pilot_class
var/pilot_level = user.GetComponent(PILOT_SPACECRAFT_SKILL_COMPONENT)?.skill_level
if(stat & (NOPOWER|BROKEN))
return FALSE
if(emergency_power_window && world.time >= emergency_power_window)
emergency_power_window = null
if(!powered())
stat |= NOPOWER
visible_message(SPAN_DANGER("\The [src] flickers, its power bypass depleted."))
else
visible_message(SPAN_NOTICE("\The [src] hums as it transitions from emergency power to main."))
update_icon()
// Snowflake case for checking player characters for a Pilot Spacecraft Skill.
// Only player characters will have the component. Which will both always be present on them, and will only enable its own return logic if it exists.
// NPCs, Ghostroles, and Offship Antags that don't generate skills are unaffected by this check by intentional design so that we don't have to account for them.
if (user.GetComponent(PILOT_SPACECRAFT_SKILL_COMPONENT)?.skill_level == SKILL_LEVEL_UNFAMILIAR)
if (!connected.pilot_class && pilot_level <= SKILL_LEVEL_UNFAMILIAR)
// No pilot_class means it's probably a station, so only Unfamiliar is checked for
to_chat(user, SPAN_WARNING("There's just so many buttons... You have no idea where to even begin."))
return FALSE
// A lack of a difference means skill level (1-4) is less than pilot_class (1-3)
if(piloting_difference <= 0)
if(connected.pilot_class == PILOTING_CLASS_SHUTTLE)
user.visible_message("<b>[user]</b> starts indecisively messing with \the [src].", SPAN_WARNING("There's just so many buttons... You have no idea where to even begin, but..."))
if(do_after(user, 10 SECONDS) && Adjacent(user))
user.visible_message("<b>[user]</b> peers at \the [src].", SPAN_NOTICE("...maybe, if you take it slow? It <i>is</i> only a shuttle."))
if(do_after(user, 3 SECONDS) && Adjacent(user))
if(prob(30))
to_chat(user, SPAN_WARNING("You lose track and can't figure out the controls."))
return
else
return
else
to_chat(user, SPAN_WARNING("You can't keep track of controls while moving."))
return
else
to_chat(user, SPAN_WARNING("This ship's class is notably more complex than you're used to, but you can still grasp the core controls."))
// Conversely, Non-Unfamiliar skill level (2-4) will always be higher than pilot class (1-3)
if(pilot_level < connected.pilot_class)
to_chat(user, SPAN_WARNING("There's just so many buttons... You have no idea where to even begin, this is far too complex for you."))
return
if(use_check_and_message(user))
return
if(!emagged && !allowed(user))
@@ -86,6 +150,9 @@ somewhere on that shuttle. Subtypes of these can be then used to perform ship ov
/obj/structure/machinery/computer/ship/get_examine_text(mob/user, distance, is_adjacent, infix, suffix)
. = ..()
if(emergency_power_window)
var/power_window_rounded = round((emergency_power_window - world.time)/10)
. += SPAN_ITALIC("The emergency power bypass is enabled, the timer shows <b>[power_window_rounded > 0 ? power_window_rounded : "no"]</b> seconds remain.")
if(initial(hotwire_progress) != hotwire_progress)
if(hotwire_progress != 0)
. += SPAN_ITALIC("The bottom panel appears open with wires hanging out. It can be repaired with additional cabling. <i>Current progress: [(hotwire_progress / initial(hotwire_progress)) * 100]%</i>")
@@ -3,6 +3,33 @@
name = "general shuttle control console"
ui_template = "ShuttleControlConsoleMultiExplore"
var/obj/effect/overmap/visitable/ship/connected //Ship we're connected to
var/emergency_power_window //Time window for emergency power from Pilot: Spacecraft + Electrical Engineering skills
/obj/structure/machinery/computer/shuttle_control/explore/attackby(obj/item/attacking_item, mob/user)
var/electrical_level = user.GetComponent(ELECTRICAL_ENGINEERING_SKILL_COMPONENT)?.skill_level
if(electrical_level > SKILL_LEVEL_UNFAMILIAR && (emergency_power_window || stat & NOPOWER) && istype(attacking_item, /obj/item/cell))
var/obj/item/cell/battery = attacking_item
var/pilot_level = user.GetComponent(PILOT_SPACECRAFT_SKILL_COMPONENT)?.skill_level
user.visible_message("<b>[user]<b> opens a panel underneath \the [src]...", SPAN_NOTICE("You start searching for the power port to attempt an emergency power bypass..."))
emergency_power_window = world.time
if(pilot_level == SKILL_LEVEL_UNFAMILIAR && Adjacent(user) && user.get_active_hand() == battery)
if(do_after(user, 3 SECONDS))
to_chat(user, SPAN_NOTICE("Although unfamiliar with spacecraft to find it fast, your electrical intuition knows there's a port somewhere..."))
else
user.visible_message("<b>[user]</b> closes the panel underneath \the [src].", SPAN_WARNING("You need to stay and look longer if you want to perform a bypass."))
return
while(battery.percent() > 0 && Adjacent(user) && user.get_active_hand() == battery)
if(do_after(user, 3 SECONDS))
if((pilot_level == SKILL_LEVEL_UNFAMILIAR && do_after(user, 2 SECONDS)) || pilot_level >= SKILL_LEVEL_FAMILIAR)
var/bypass_value = battery.maxcharge/10
emergency_power_window += bypass_value/((100 - pilot_level * 3)/electrical_level) SECONDS // should be 10m for high-caps
playsound(src.loc, 'sound/machines/click.ogg', 30)
battery.charge -= bypass_value
user.visible_message("<b>[user]</b> presses into some port with a click.<BR><i>\The [src]'s power bypass timer notifies there are <b>[round((emergency_power_window - world.time)/10)]</b> seconds of emergency power remaining.</i>", SPAN_NOTICE("You press into the port with \the [battery] transferring 10% into \the [src] and leaving \the [battery] with [battery.percent()]%<BR>\The [src]'s power bypass timer notifies there are <b>[round((emergency_power_window - world.time)/10)]</b> seconds of emergency power remaining."))
stat &= ~NOPOWER
update_icon()
return
/obj/structure/machinery/computer/shuttle_control/explore/Initialize()
. = ..()
+1
View File
@@ -11,6 +11,7 @@
var/use_mapped_z_levels = FALSE //If you use this, use /obj/effect/shuttle_landmark/ship as the landmark (set the landmark_tag to match on the shuttle, no other setup needed)
icon_state = "shuttle"
moving_state = "shuttle_moving"
pilot_class = PILOTING_CLASS_SHUTTLE
layer = OVERMAP_SHUTTLE_LAYER
/obj/effect/overmap/visitable/ship/landable/Destroy()
+4
View File
@@ -22,6 +22,9 @@
generic_object = FALSE
var/moving_state = "ship_moving"
/*For Pilot: Spacecraft skill. Denotes SHUTTLE for landables, CLASS_TWO for standard "overmap-only" ships, or CLASS_MAX for massive
ones which is just the Horizon/main player ship. When null, the skill only cares for being Unfamiliar; stations are null.*/
var/pilot_class = PILOTING_CLASS_TWO
layer = OVERMAP_SHIP_LAYER
//RP fluff details to appear on scan readouts for mobile objects.
@@ -81,6 +84,7 @@
obfuscated_name = "unidentified stationary object"
unknown_id = "Unknown artificial structure"
static_vessel = TRUE
pilot_class = null
propulsion = "None equipped, flight incapable"
halted = TRUE // Cannot fly under any circumstances