Skip to content

Commit

Permalink
Crashable lifeboats and early launch (#4314)
Browse files Browse the repository at this point in the history
# About the pull request

This PR:

Allows lifeboats to be early launched by people with senior access

Gives a chance for lifeboats to crash if early launched

Refactors escape shuttles and lifeboats to have the same "crashable"
parent

Removes alcohol from emergency wall cabinets

Should stop crashing shuttles from landing on each other

# Explain why it's good for the game

Early launch is neat and crashing to the planet to more xenos is an
interesting situation.

More hijack objectives soonTM.

# Testing Photographs and Procedure
<details>
<summary>Screenshots & Videos</summary>

Put screenshots and videos here with an empty line between the
screenshots and the `<details>` tags.

</details>


# Changelog

:cl: Morrow
add: Added the ability to early launch lifeboats
add: Added the ability for lifeboats to crash if early launched
del: Removed alcohol from emergency wall cabinets
fix: Should stop crashing shuttles from landing on each other
/:cl:
  • Loading branch information
morrowwolf authored Sep 8, 2023
1 parent 8625443 commit bac1345
Show file tree
Hide file tree
Showing 19 changed files with 273 additions and 170 deletions.
2 changes: 1 addition & 1 deletion code/__DEFINES/mode.dm
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#define SHUTTLE_LOCK_COOLDOWN 10 MINUTES
#define MONORAIL_LOCK_COOLDOWN 3 MINUTES
#define SHUTTLE_LOCK_TIME_LOCK 1 MINUTES
#define EVACUATION_AUTOMATIC_DEPARTURE 10 MINUTES //All pods automatically depart in 10 minutes, unless they are full or unable to launch for some reason.
#define EVACUATION_AUTOMATIC_DEPARTURE (10 MINUTES) //All pods automatically depart in 10 minutes, unless they are full or unable to launch for some reason.
#define EVACUATION_ESTIMATE_DEPARTURE ((evac_time + EVACUATION_AUTOMATIC_DEPARTURE - world.time) * 0.1)

#define EVACUATION_STATUS_STANDING_BY 0
Expand Down
18 changes: 9 additions & 9 deletions code/game/gamemodes/cm_self_destruct.dm
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ var/global/datum/authority/branch/evacuation/EvacuationAuthority //This is initi
for(var/obj/structure/machinery/status_display/SD in machines)
if(is_mainship_level(SD.z))
SD.set_picture("evac")
for(var/obj/docking_port/mobile/escape_shuttle/shuttle in SSshuttle.mobile)
for(var/obj/docking_port/mobile/crashable/escape_shuttle/shuttle in SSshuttle.mobile)
shuttle.prepare_evac()
activate_lifeboats()
process_evacuation()
Expand All @@ -121,7 +121,7 @@ var/global/datum/authority/branch/evacuation/EvacuationAuthority //This is initi
if(is_mainship_level(SD.z))
SD.set_picture("redalert")

for(var/obj/docking_port/mobile/escape_shuttle/shuttle in SSshuttle.mobile)
for(var/obj/docking_port/mobile/crashable/escape_shuttle/shuttle in SSshuttle.mobile)
shuttle.cancel_evac()
return TRUE

Expand All @@ -132,17 +132,17 @@ var/global/datum/authority/branch/evacuation/EvacuationAuthority //This is initi
ai_announcement("WARNING: Evacuation order confirmed. Launching escape pods.", 'sound/AI/evacuation_confirmed.ogg')
addtimer(CALLBACK(src, PROC_REF(launch_lifeboats)), 10 SECONDS) // giving some time to board lifeboats

for(var/obj/docking_port/mobile/escape_shuttle/shuttle in SSshuttle.mobile)
for(var/obj/docking_port/mobile/crashable/escape_shuttle/shuttle in SSshuttle.mobile)
shuttle.evac_launch()
sleep(50)

sleep(300) //Sleep 30 more seconds to make sure everyone had a chance to leave.
var/lifesigns = 0
// lifesigns += P.passengers
var/obj/docking_port/mobile/lifeboat/lifeboat1 = SSshuttle.getShuttle(MOBILE_SHUTTLE_LIFEBOAT_PORT)
var/obj/docking_port/mobile/crashable/lifeboat/lifeboat1 = SSshuttle.getShuttle(MOBILE_SHUTTLE_LIFEBOAT_PORT)
lifeboat1.check_for_survivors()
lifesigns += lifeboat1.survivors
var/obj/docking_port/mobile/lifeboat/lifeboat2 = SSshuttle.getShuttle(MOBILE_SHUTTLE_LIFEBOAT_STARBOARD)
var/obj/docking_port/mobile/crashable/lifeboat/lifeboat2 = SSshuttle.getShuttle(MOBILE_SHUTTLE_LIFEBOAT_STARBOARD)
lifeboat2.check_for_survivors()
lifesigns += lifeboat2.survivors
ai_announcement("ATTENTION: Evacuation complete. Outbound lifesigns detected: [lifesigns ? lifesigns : "none"].", 'sound/AI/evacuation_complete.ogg')
Expand All @@ -166,23 +166,23 @@ var/global/datum/authority/branch/evacuation/EvacuationAuthority //This is initi
// LIFEBOATS CORNER
/datum/authority/branch/evacuation/proc/activate_lifeboats()
for(var/obj/docking_port/stationary/lifeboat_dock/lifeboat_dock in GLOB.lifeboat_almayer_docks)
var/obj/docking_port/mobile/lifeboat/lifeboat = lifeboat_dock.get_docked()
var/obj/docking_port/mobile/crashable/lifeboat/lifeboat = lifeboat_dock.get_docked()
if(lifeboat && lifeboat.available)
lifeboat.status = LIFEBOAT_ACTIVE
lifeboat_dock.open_dock()


/datum/authority/branch/evacuation/proc/deactivate_lifeboats()
for(var/obj/docking_port/stationary/lifeboat_dock/lifeboat_dock in GLOB.lifeboat_almayer_docks)
var/obj/docking_port/mobile/lifeboat/lifeboat = lifeboat_dock.get_docked()
var/obj/docking_port/mobile/crashable/lifeboat/lifeboat = lifeboat_dock.get_docked()
if(lifeboat && lifeboat.available)
lifeboat.status = LIFEBOAT_INACTIVE

/datum/authority/branch/evacuation/proc/launch_lifeboats()
for(var/obj/docking_port/stationary/lifeboat_dock/lifeboat_dock in GLOB.lifeboat_almayer_docks)
var/obj/docking_port/mobile/lifeboat/lifeboat = lifeboat_dock.get_docked()
var/obj/docking_port/mobile/crashable/lifeboat/lifeboat = lifeboat_dock.get_docked()
if(lifeboat && lifeboat.available)
lifeboat.send_to_infinite_transit()
lifeboat.evac_launch()

//=========================================================================================
//=========================================================================================
Expand Down
4 changes: 2 additions & 2 deletions code/game/machinery/doors/multi_tile.dm
Original file line number Diff line number Diff line change
Expand Up @@ -353,8 +353,8 @@

/obj/structure/machinery/door/airlock/multi_tile/almayer/dropshiprear/lifeboat/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override)
. = ..()
if(istype(port, /obj/docking_port/mobile/lifeboat))
var/obj/docking_port/mobile/lifeboat/lifeboat = port
if(istype(port, /obj/docking_port/mobile/crashable/lifeboat))
var/obj/docking_port/mobile/crashable/lifeboat/lifeboat = port
lifeboat.doors += src

/// External airlock that is part of the lifeboat dock
Expand Down
2 changes: 0 additions & 2 deletions code/game/machinery/vending/vendor_types/supplies.dm
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@
list("FOOD AND BEVERAGE", -1, null, null),
list("MRE", 25, /obj/item/storage/box/MRE, VENDOR_ITEM_REGULAR),
list("Water Bottle", 25, /obj/item/reagent_container/food/drinks/cans/waterbottle, VENDOR_ITEM_REGULAR),
list("Aspen Beer", 10, /obj/item/storage/beer_pack, VENDOR_ITEM_REGULAR),//NOTE TO SELF, LOCK THIS ALCOHOL BEHIND SHIP ESCAPE
list("Wey-Yu Sake", 5, /obj/item/reagent_container/food/drinks/bottle/sake, VENDOR_ITEM_REGULAR),

list("UTILITY", -1, null, null),
list("M94 Marking Flare Pack", 5, /obj/item/storage/box/m94, VENDOR_ITEM_REGULAR),
Expand Down
27 changes: 20 additions & 7 deletions code/modules/shuttle/computer.dm
Original file line number Diff line number Diff line change
Expand Up @@ -284,23 +284,36 @@

/obj/structure/machinery/computer/shuttle/lifeboat/attack_hand(mob/user)
. = ..()
var/obj/docking_port/mobile/lifeboat/lifeboat = SSshuttle.getShuttle(shuttleId)
var/obj/docking_port/mobile/crashable/lifeboat/lifeboat = SSshuttle.getShuttle(shuttleId)
if(lifeboat.status == LIFEBOAT_LOCKED)
to_chat(user, SPAN_WARNING("\The [src] flickers with error messages."))
to_chat(user, SPAN_WARNING("[src] flickers with error messages."))
else if(lifeboat.status == LIFEBOAT_INACTIVE)
to_chat(user, SPAN_NOTICE("\The [src]'s screen says \"Awaiting evacuation order\"."))
to_chat(user, SPAN_NOTICE("[src]'s screen says \"Awaiting evacuation order\"."))
else if(lifeboat.status == LIFEBOAT_ACTIVE)
switch(lifeboat.mode)
if(SHUTTLE_IDLE)
to_chat(user, SPAN_NOTICE("\The [src]'s screen says \"Awaiting confirmation of the evacuation order\"."))
if(!istype(user, /mob/living/carbon/human))
to_chat(user, SPAN_NOTICE("[src]'s screen says \"Awaiting confirmation of the evacuation order\"."))
return

var/mob/living/carbon/human/human_user = user
if(!(ACCESS_MARINE_SENIOR in human_user.wear_id?.access))
to_chat(user, SPAN_NOTICE("[src]'s screen says \"Awaiting confirmation of the evacuation order\"."))
return

if(tgui_alert(user, "Early launch the lifeboat?", "Confirm", list("Yes", "No"), 10 SECONDS) == "Yes")
to_chat(user, SPAN_NOTICE("[src]'s screen blinks and says \"Early launch accepted\"."))
lifeboat.evac_launch()
return

if(SHUTTLE_IGNITING)
to_chat(user, SPAN_NOTICE("\The [src]'s screen says \"Engines firing\"."))
to_chat(user, SPAN_NOTICE("[src]'s screen says \"Engines firing\"."))
if(SHUTTLE_CALL)
to_chat(user, SPAN_NOTICE("\The [src] has flight information scrolling across the screen. The autopilot is working correctly."))
to_chat(user, SPAN_NOTICE("[src] has flight information scrolling across the screen. The autopilot is working correctly."))

/obj/structure/machinery/computer/shuttle/lifeboat/attack_alien(mob/living/carbon/xenomorph/xeno)
if(xeno.caste && xeno.caste.is_intelligent)
var/obj/docking_port/mobile/lifeboat/lifeboat = SSshuttle.getShuttle(shuttleId)
var/obj/docking_port/mobile/crashable/lifeboat/lifeboat = SSshuttle.getShuttle(shuttleId)
if(lifeboat.status == LIFEBOAT_LOCKED)
to_chat(xeno, SPAN_WARNING("We already wrested away control of this metal bird."))
return XENO_NO_DELAY_ACTION
Expand Down
12 changes: 6 additions & 6 deletions code/modules/shuttle/computers/escape_pod_computer.dm
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@

/obj/structure/machinery/computer/shuttle/escape_pod_panel/ui_data(mob/user)
. = list()
var/obj/docking_port/mobile/escape_shuttle/shuttle = SSshuttle.getShuttle(shuttleId)
var/obj/docking_port/mobile/crashable/escape_shuttle/shuttle = SSshuttle.getShuttle(shuttleId)

if(pod_state == STATE_IDLE && shuttle.evac_set)
pod_state = STATE_READY
Expand All @@ -63,7 +63,7 @@
if(.)
return

var/obj/docking_port/mobile/escape_shuttle/shuttle = SSshuttle.getShuttle(shuttleId)
var/obj/docking_port/mobile/crashable/escape_shuttle/shuttle = SSshuttle.getShuttle(shuttleId)
switch(action)
if("force_launch")
shuttle.evac_launch()
Expand Down Expand Up @@ -204,7 +204,7 @@
heat_proof = 1
unslashable = TRUE
unacidable = TRUE
var/obj/docking_port/mobile/escape_shuttle/linked_shuttle
var/obj/docking_port/mobile/crashable/escape_shuttle/linked_shuttle

/obj/structure/machinery/door/airlock/evacuation/Initialize()
. = ..()
Expand All @@ -229,16 +229,16 @@
/obj/structure/machinery/door/airlock/evacuation/attack_alien(mob/living/carbon/xenomorph/xeno)
if(!density || unslashable) //doors become slashable after evac is called
return FALSE

if(xeno.claw_type < CLAW_TYPE_SHARP)
to_chat(xeno, SPAN_WARNING("[src] is bolted down tight."))
return XENO_NO_DELAY_ACTION

xeno.animation_attack_on(src)
playsound(src, 'sound/effects/metalhit.ogg', 25, 1)
take_damage(HEALTH_DOOR / XENO_HITS_TO_DESTROY_BOLTED_DOOR)
return XENO_ATTACK_ACTION


/obj/structure/machinery/door/airlock/evacuation/attack_remote()
return FALSE
Expand Down
179 changes: 179 additions & 0 deletions code/modules/shuttle/shuttles/crashable/crashable.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
/obj/docking_port/mobile/crashable
name = "crashable shuttle"

/// Whether or not this shuttle is crash landing
var/crash_land = FALSE
/// Whether fires occur aboard the shuttle when crashing
var/fires_on_crash = FALSE

/obj/docking_port/mobile/crashable/enterTransit()
. = ..()

if(!crash_land)
return

notify_ghosts(header = "Crashing shuttle!", message = "<b>[name]</b> has catastrophically failed and is crashing at <b>[get_area(destination)]</b>.", source = src)

for(var/area/shuttle_area as anything in shuttle_areas)
shuttle_area.flags_alarm_state |= ALARM_WARNING_FIRE
shuttle_area.updateicon()
for(var/mob/evac_mob in shuttle_area)
if(evac_mob.client)
playsound_client(evac_mob.client, 'sound/effects/bomb_fall.ogg', vol = 50)

for(var/turf/found_turf as anything in destination.return_turfs())
if(istype(found_turf, /turf/closed))
found_turf.ChangeTurf(/turf/open/floor)

for(var/mob/current_mob as anything in get_mobs_in_z_level_range(destination.return_center_turf(), 18))
var/relative_dir = get_dir(current_mob, destination.return_center_turf())
var/final_dir = dir2text(relative_dir)
to_chat(current_mob, SPAN_HIGHDANGER("You hear something crashing down from above [final_dir ? "to the [final_dir]" : "nearby"]!"))

if(fires_on_crash)
handle_fires()

addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(cell_explosion), destination.return_center_turf(), length(destination.return_turfs()) * 2, 25, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, create_cause_data("crashing shuttle")), 1.5 SECONDS)

/obj/docking_port/mobile/crashable/on_prearrival()
. = ..()

if(!crash_land)
return

movement_force = list("KNOCKDOWN" = 0, "THROW" = 5)

for(var/area/shuttle_area in shuttle_areas)
for(var/mob/evac_mob in shuttle_area)
shake_camera(evac_mob, 20, 2)
if(evac_mob.client)
playsound_client(evac_mob.client, get_sfx("bigboom"), vol = 50)

/// Called when the shuttle is launched and checks for crash and creates a crash point
/obj/docking_port/mobile/crashable/proc/evac_launch()
if(!crash_check())
return

create_crash_point()

/// Returns whether or not the shuttle will crash after being sent
/obj/docking_port/mobile/crashable/proc/crash_check()
return FALSE

/// Sets up a valid crash point, fails after 10 tries
/obj/docking_port/mobile/crashable/proc/create_crash_point()
for(var/i = 1 to 10)
var/list/all_ground_levels = SSmapping.levels_by_trait(ZTRAIT_GROUND)
var/ground_z_level = all_ground_levels[1]

var/list/area/potential_areas = SSmapping.areas_in_z["[ground_z_level]"]

var/area/area_picked = pick(potential_areas)

var/list/potential_turfs = list()

for(var/turf/turf_in_area in area_picked)
potential_turfs += turf_in_area

if(!length(potential_turfs))
continue

var/turf/turf_picked = pick(potential_turfs)

var/obj/docking_port/stationary/crashable/temp_crashable_port = new(turf_picked)
temp_crashable_port.width = width
temp_crashable_port.height = height
temp_crashable_port.id = id

if(!check_crash_point(temp_crashable_port))
qdel(temp_crashable_port)
continue

destination = temp_crashable_port
break

if(destination)
crash_land = TRUE

/// Checks for anything that may get in the way of a crash, returns FALSE if there is something in the way or is out of bounds
/obj/docking_port/mobile/crashable/proc/check_crash_point(obj/docking_port/stationary/crashable/checked_crashable_port)
for(var/turf/found_turf as anything in checked_crashable_port.return_turfs())
var/area/found_area = get_area(found_turf)
if(found_area.flags_area & AREA_NOTUNNEL)
return FALSE

if(!found_area.can_build_special)
return FALSE

if(istype(found_turf, /turf/closed/wall))
var/turf/closed/wall/found_closed_turf = found_turf
if(found_closed_turf.hull)
return FALSE

if(istype(found_turf, /turf/closed/shuttle))
return FALSE

for(var/obj/docking_port/stationary/stationary_dock in get_turf(checked_crashable_port))
if(stationary_dock != checked_crashable_port)
return FALSE

for(var/obj/docking_port/mobile/cycled_mobile_port as anything in SSshuttle.mobile)
if(cycled_mobile_port == src)
continue

if(!cycled_mobile_port.destination)
continue

if(length(checked_crashable_port.return_turfs() & cycled_mobile_port.destination.return_turfs()))
return FALSE

return TRUE

/// Forces the shuttle to crash, admin called
/obj/docking_port/mobile/crashable/proc/force_crash()
create_crash_point()
set_mode(SHUTTLE_IGNITING)
on_ignition()
setTimer(ignitionTime)

/// Sets up and handles fires/explosions on crashing shuttles
/obj/docking_port/mobile/crashable/proc/handle_fires()
var/list/turf/total_turfs = list()
for(var/area/shuttle_area as anything in shuttle_areas)
for(var/turf/cycled_turf in shuttle_area)
total_turfs += cycled_turf

for(var/i = 1 to (length(total_turfs) / 40))
var/turf/position = pick(total_turfs)
new /obj/effect/warning/explosive(position, 3 SECONDS)
playsound(position, 'sound/effects/pipe_hissing.ogg', vol = 40)
addtimer(CALLBACK(src, PROC_REF(kablooie), position), 3 SECONDS)

/// Actually blows up the fire/explosion on crashing shuttles, used for effect delay
/obj/docking_port/mobile/crashable/proc/kablooie(turf/position)
var/new_cause_data = create_cause_data("crashing shuttle fire")
var/list/exploding_types = list(/obj/item/explosive/grenade/high_explosive/bursting_pipe, /obj/item/explosive/grenade/incendiary/bursting_pipe)
for(var/path in exploding_types)
var/obj/item/explosive/grenade/exploder = new path(position)
exploder.cause_data = new_cause_data
exploder.prime()

/// Handles opening the doors for the specific shuttle type upon arriving at the crash point
/obj/docking_port/mobile/crashable/proc/open_doors()
return

/obj/docking_port/stationary/crashable
name = "Crashable Dock"

/obj/docking_port/stationary/crashable/on_arrival(obj/docking_port/mobile/arriving_shuttle)
. = ..()

if(istype(arriving_shuttle, /obj/docking_port/mobile/crashable))
var/obj/docking_port/mobile/crashable/crashing_shuttle = arriving_shuttle
crashing_shuttle.open_doors()

for(var/area/shuttle_area in arriving_shuttle.shuttle_areas)
shuttle_area.remove_base_lighting()

shuttle_area.flags_alarm_state &= ~ALARM_WARNING_FIRE
shuttle_area.updateicon()
Loading

0 comments on commit bac1345

Please sign in to comment.