diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm
index 301ca0409655..6af4a3585e29 100644
--- a/code/__DEFINES/subsystems.dm
+++ b/code/__DEFINES/subsystems.dm
@@ -109,6 +109,7 @@
// Subsystems shutdown in the reverse of the order they initialize in
// The numbers just define the ordering, they are meaningless otherwise.
+#define SS_INIT_PROFILER 86
#define SS_INIT_INPUT 85
#define SS_INIT_TOPIC 83
#define SS_INIT_LOBBYART 82
diff --git a/code/__HELPERS/job.dm b/code/__HELPERS/job.dm
index 89fe6877647e..220236c6f7e3 100644
--- a/code/__HELPERS/job.dm
+++ b/code/__HELPERS/job.dm
@@ -14,32 +14,10 @@
all_jobs += new jobtype
return all_jobs
-
/proc/get_all_centcom_jobs() return list()
-//gets the actual job rank (ignoring alt titles)
-//this is used solely for sechuds
-/obj/proc/GetJobRealName()
- if (!istype(src,/obj/item/card/id)) return
- var/obj/item/card/id/I = src
- if(I.rank in GLOB.joblist) return I.rank
- if(I.assignment in GLOB.joblist) return I.assignment
- return "Unknown"
-
/proc/get_all_job_icons() return GLOB.joblist + list("Prisoner")//For all existing HUD icons
-/obj/proc/GetJobName() //Used in secHUD icon generation
- var/obj/item/card/id/I = src
- if(istype(I))
- var/job_icons = get_all_job_icons()
- var/centcom = get_all_centcom_jobs()
-
- if(I.assignment in job_icons) return I.assignment//Check if the job has a hud icon
- if(I.rank in job_icons) return I.rank
- if(I.assignment in centcom) return "Centcom"//Return with the NT logo if it is a Centcom job
- if(I.rank in centcom) return "Centcom"
- return "Unknown" //Return unknown if none of the above apply
-
/proc/get_actual_job_name(mob/M)
if(!M)
return null
diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm
index 9c9784286d09..0bfa0a759287 100644
--- a/code/_onclick/other_mobs.dm
+++ b/code/_onclick/other_mobs.dm
@@ -13,7 +13,7 @@
var/obj/structure/S = A
S.do_climb(src, mods)
return TRUE
- else if(!(isitem(A) && get_dist(src, A) <= 1) && client.prefs.toggle_prefs & TOGGLE_MIDDLE_MOUSE_SWAP_HANDS)
+ else if(!(isitem(A) && get_dist(src, A) <= 1) && (client && (client.prefs.toggle_prefs & TOGGLE_MIDDLE_MOUSE_SWAP_HANDS)))
swap_hand()
return TRUE
diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm
index cc3d00fd951b..385cbcb8d446 100644
--- a/code/controllers/configuration/entries/general.dm
+++ b/code/controllers/configuration/entries/general.dm
@@ -627,3 +627,5 @@ This maintains a list of ip addresses that are able to bypass topic filtering.
protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED
/datum/config_entry/flag/guest_ban
+
+/datum/config_entry/flag/auto_profile
diff --git a/code/controllers/subsystem/profiler.dm b/code/controllers/subsystem/profiler.dm
new file mode 100644
index 000000000000..f9ba79046c2c
--- /dev/null
+++ b/code/controllers/subsystem/profiler.dm
@@ -0,0 +1,74 @@
+#define PROFILER_FILENAME "profiler.json"
+#define SENDMAPS_FILENAME "sendmaps.json"
+
+SUBSYSTEM_DEF(profiler)
+ name = "Profiler"
+ init_order = SS_INIT_PROFILER
+ runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY
+ wait = 300 SECONDS
+ var/fetch_cost = 0
+ var/write_cost = 0
+
+/datum/controller/subsystem/profiler/stat_entry(msg)
+ msg += "F:[round(fetch_cost,1)]ms"
+ msg += "|W:[round(write_cost,1)]ms"
+ return msg
+
+/datum/controller/subsystem/profiler/Initialize()
+ if(CONFIG_GET(flag/auto_profile))
+ StartProfiling()
+ else
+ StopProfiling() //Stop the early start profiler
+ return SS_INIT_SUCCESS
+
+/datum/controller/subsystem/profiler/OnConfigLoad()
+ if(CONFIG_GET(flag/auto_profile))
+ StartProfiling()
+ can_fire = TRUE
+ else
+ StopProfiling()
+ can_fire = FALSE
+
+/datum/controller/subsystem/profiler/fire()
+ DumpFile()
+
+/datum/controller/subsystem/profiler/Shutdown()
+ if(CONFIG_GET(flag/auto_profile))
+ DumpFile(allow_yield = FALSE)
+ world.Profile(PROFILE_CLEAR, type = "sendmaps")
+ return ..()
+
+/datum/controller/subsystem/profiler/proc/StartProfiling()
+ world.Profile(PROFILE_START)
+ world.Profile(PROFILE_START, type = "sendmaps")
+
+/datum/controller/subsystem/profiler/proc/StopProfiling()
+ world.Profile(PROFILE_STOP)
+ world.Profile(PROFILE_STOP, type = "sendmaps")
+
+/datum/controller/subsystem/profiler/proc/DumpFile(allow_yield = TRUE)
+ var/timer = TICK_USAGE_REAL
+ var/current_profile_data = world.Profile(PROFILE_REFRESH, format = "json")
+ var/current_sendmaps_data = world.Profile(PROFILE_REFRESH, type = "sendmaps", format="json")
+ fetch_cost = MC_AVERAGE(fetch_cost, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
+ if(allow_yield)
+ CHECK_TICK
+
+ if(!length(current_profile_data)) //Would be nice to have explicit proc to check this
+ stack_trace("Warning, profiling stopped manually before dump.")
+ var/prof_file = file("[GLOB.log_directory]/[PROFILER_FILENAME]")
+ if(fexists(prof_file))
+ fdel(prof_file)
+ if(!length(current_sendmaps_data)) //Would be nice to have explicit proc to check this
+ stack_trace("Warning, sendmaps profiling stopped manually before dump.")
+ var/sendmaps_file = file("[GLOB.log_directory]/[SENDMAPS_FILENAME]")
+ if(fexists(sendmaps_file))
+ fdel(sendmaps_file)
+
+ timer = TICK_USAGE_REAL
+ WRITE_FILE(prof_file, current_profile_data)
+ WRITE_FILE(sendmaps_file, current_sendmaps_data)
+ write_cost = MC_AVERAGE(write_cost, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
+
+#undef PROFILER_FILENAME
+#undef SENDMAPS_FILENAME
diff --git a/code/datums/looping_sounds/misc_sounds.dm b/code/datums/looping_sounds/misc_sounds.dm
new file mode 100644
index 000000000000..6411b3f51f4a
--- /dev/null
+++ b/code/datums/looping_sounds/misc_sounds.dm
@@ -0,0 +1,3 @@
+/datum/looping_sound/looping_launch_announcement_alarm
+ mid_sounds = list('sound/vehicles/Dropships/single_alarm_brr_dropship_1.ogg' = 1)
+ start_sound = list('sound/vehicles/Dropships/single_alarm_brr_dropship_1.ogg' = 1)
diff --git a/code/game/jobs/job/civilians/other/mess_seargent.dm b/code/game/jobs/job/civilians/other/mess_seargent.dm
index 97578eb1159d..fb4f5ee14d7c 100644
--- a/code/game/jobs/job/civilians/other/mess_seargent.dm
+++ b/code/game/jobs/job/civilians/other/mess_seargent.dm
@@ -1,13 +1,31 @@
/datum/job/civilian/chef
title = JOB_MESS_SERGEANT
- total_positions = 1
+ total_positions = 2
spawn_positions = 1
+ allow_additional = TRUE
+ scaled = TRUE
selection_class = "job_ot"
flags_startup_parameters = ROLE_ADD_TO_DEFAULT
supervisors = "the auxiliary support officer"
gear_preset = /datum/equipment_preset/uscm_ship/chef
entry_message_body = "Your job is to service the marines with excellent food, drinks and entertaining the shipside crew when needed. You have a lot of freedom and it is up to you, to decide what to do with it. Good luck!"
+/datum/job/civilian/chef/set_spawn_positions(count)
+ spawn_positions = mess_sergeant_slot_formula(count)
+
+/datum/job/civilian/chef/get_total_positions(latejoin = FALSE)
+ var/positions = spawn_positions
+ if(latejoin)
+ positions = mess_sergeant_slot_formula(get_total_marines())
+ if(positions <= total_positions_so_far)
+ positions = total_positions_so_far
+ else
+ total_positions_so_far = positions
+ else
+ total_positions_so_far = positions
+
+ return positions
+
/obj/effect/landmark/start/chef
name = JOB_MESS_SERGEANT
icon_state = "chef_spawn"
diff --git a/code/game/jobs/slot_scaling.dm b/code/game/jobs/slot_scaling.dm
index 7230f57eb745..2d444d06e5ab 100644
--- a/code/game/jobs/slot_scaling.dm
+++ b/code/game/jobs/slot_scaling.dm
@@ -50,3 +50,6 @@
/proc/working_joe_slot_formula(playercount)
return job_slot_formula(playercount,30,1,3,6)
+
+/proc/mess_sergeant_slot_formula(playercount)
+ return job_slot_formula(playercount, 70, 1, 1, 2)
diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm
index a5e0eafe2f91..f6af3c0ca237 100644
--- a/code/game/objects/items/cards_ids.dm
+++ b/code/game/objects/items/cards_ids.dm
@@ -97,6 +97,21 @@
. = ..()
screen_loc = null
+/obj/item/card/id/proc/GetJobName() //Used in secHUD icon generation
+
+ var/job_icons = get_all_job_icons()
+ var/centcom = get_all_centcom_jobs()
+
+ if(assignment in job_icons)
+ return assignment//Check if the job has a hud icon
+ if(rank in job_icons)
+ return rank
+ if(assignment in centcom)
+ return "Centcom"//Return with the NT logo if it is a Centcom job
+ if(rank in centcom)
+ return "Centcom"
+ return "Unknown" //Return unknown if none of the above apply
+
/obj/item/card/id/attack_self(mob/user as mob)
..()
user.visible_message("[user] shows you: [icon2html(src, viewers(user))] [name]: assignment: [assignment]")
diff --git a/code/game/objects/items/props/helmetgarb.dm b/code/game/objects/items/props/helmetgarb.dm
index b20c5671503e..35558bf01925 100644
--- a/code/game/objects/items/props/helmetgarb.dm
+++ b/code/game/objects/items/props/helmetgarb.dm
@@ -529,7 +529,7 @@
/obj/item/prop/helmetgarb/family_photo/pickup(mob/user, silent)
. = ..()
if(!owner)
- RegisterSignal(user, COMSIG_POST_SPAWN_UPDATE, PROC_REF(set_owner))
+ RegisterSignal(user, COMSIG_POST_SPAWN_UPDATE, PROC_REF(set_owner), override = TRUE)
///Sets the owner of the family photo to the human it spawns with, needs var/source for signals
diff --git a/code/game/objects/items/reagent_containers/food/fortunecookie.dm b/code/game/objects/items/reagent_containers/food/fortunecookie.dm
index a878ff589dc8..270bd4d7c44a 100644
--- a/code/game/objects/items/reagent_containers/food/fortunecookie.dm
+++ b/code/game/objects/items/reagent_containers/food/fortunecookie.dm
@@ -93,7 +93,7 @@
user.put_in_hands(cookiefortune)
cookiefortune = null
else
- to_chat(SPAN_WARNING("You break open the fortune cookie, but there's no fortune inside! Oh no!"))
+ to_chat(user, SPAN_WARNING("You break open the fortune cookie, but there's no fortune inside! Oh no!"))
else
. = ..()
@@ -109,7 +109,7 @@
user.put_in_hands(cookiefortune)
cookiefortune = null
else
- to_chat(SPAN_WARNING("You break open the fortune cookie, but there's no fortune inside! Oh no!"))
+ to_chat(user, SPAN_WARNING("You break open the fortune cookie, but there's no fortune inside! Oh no!"))
else
. = ..()
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index 3912e2d64165..82e091be9008 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -313,6 +313,8 @@ Also change the icon to reflect the amount of sheets, if possible.*/
if(mods["alt"])
if(!CAN_PICKUP(user, src))
return
+ if(amount <= 1)
+ return
var/desired = tgui_input_number(user, "How much would you like to split off from this stack?", "How much?", 1, amount-1, 1)
if(!desired)
return
diff --git a/code/game/objects/items/tools/misc_tools.dm b/code/game/objects/items/tools/misc_tools.dm
index 0b4a7cc98775..f70f93497021 100644
--- a/code/game/objects/items/tools/misc_tools.dm
+++ b/code/game/objects/items/tools/misc_tools.dm
@@ -289,7 +289,7 @@
/obj/item/tool/pen/fountain/pickup(mob/user, silent)
. = ..()
if(!owner_name)
- RegisterSignal(user, COMSIG_POST_SPAWN_UPDATE, PROC_REF(set_owner))
+ RegisterSignal(user, COMSIG_POST_SPAWN_UPDATE, PROC_REF(set_owner), override = TRUE)
///Sets the owner of the pen to who it spawns with, requires var/source for signals
/obj/item/tool/pen/fountain/proc/set_owner(datum/source)
diff --git a/code/game/objects/items/toys/toys.dm b/code/game/objects/items/toys/toys.dm
index 851f203c52c1..88946f5fa446 100644
--- a/code/game/objects/items/toys/toys.dm
+++ b/code/game/objects/items/toys/toys.dm
@@ -591,7 +591,7 @@
/obj/item/toy/plush/random_plushie/pickup(mob/user, silent)
. = ..()
- RegisterSignal(user, COMSIG_POST_SPAWN_UPDATE, PROC_REF(create_plushie))
+ RegisterSignal(user, COMSIG_POST_SPAWN_UPDATE, PROC_REF(create_plushie), override = TRUE)
///The randomizer picking and spawning a plushie on either the ground or in the humans backpack. Needs var/source due to signals
/obj/item/toy/plush/random_plushie/proc/create_plushie(datum/source)
diff --git a/code/game/objects/structures/crates_lockers/largecrate.dm b/code/game/objects/structures/crates_lockers/largecrate.dm
index 2f2877ba7539..f1b58e6f657b 100644
--- a/code/game/objects/structures/crates_lockers/largecrate.dm
+++ b/code/game/objects/structures/crates_lockers/largecrate.dm
@@ -28,9 +28,8 @@
material_sheet = new parts_type(current_turf, 2)
// Move the objects back to the turf, above the crate material
- for(var/atom/movable/moving_atom in contents)
- var/atom/movable/current_atom = contents[1]
- current_atom.forceMove(current_turf)
+ for(var/atom/movable/moving_atom as anything in contents)
+ moving_atom.forceMove(current_turf)
deconstruct(TRUE)
diff --git a/code/game/objects/structures/props.dm b/code/game/objects/structures/props.dm
index bd5610487ea0..f465e1535d68 100644
--- a/code/game/objects/structures/props.dm
+++ b/code/game/objects/structures/props.dm
@@ -805,14 +805,14 @@
/obj/structure/prop/brazier/campfire/attackby(obj/item/attacking_item, mob/user)
if(!istype(attacking_item, /obj/item/stack/sheet/wood))
- to_chat(SPAN_NOTICE("You cannot fuel [src] with [attacking_item]."))
+ to_chat(user, SPAN_NOTICE("You cannot fuel [src] with [attacking_item]."))
return
var/obj/item/stack/sheet/wood/fuel = attacking_item
if(remaining_fuel >= initial(remaining_fuel))
to_chat(user, SPAN_NOTICE("You cannot fuel [src] further."))
return
if(!fuel.use(1))
- to_chat(SPAN_NOTICE("You do not have enough [attacking_item] to fuel [src]."))
+ to_chat(user, SPAN_NOTICE("You do not have enough [attacking_item] to fuel [src]."))
return
visible_message(SPAN_NOTICE("[user] fuels [src] with [fuel]."))
remaining_fuel++
diff --git a/code/modules/clothing/under/marine_uniform.dm b/code/modules/clothing/under/marine_uniform.dm
index dbbfdb059fc2..a950b4de3d94 100644
--- a/code/modules/clothing/under/marine_uniform.dm
+++ b/code/modules/clothing/under/marine_uniform.dm
@@ -1004,7 +1004,7 @@
return
if(!linked_hood)
- to_chat(SPAN_BOLDWARNING("You are missing a linked_hood! This should not be possible."))
+ to_chat(user, SPAN_BOLDWARNING("You are missing a linked_hood! This should not be possible."))
CRASH("[user] attempted to toggle hood on [src] that was missing a linked_hood.")
playsound(user.loc, "armorequip", 25, 1)
diff --git a/code/modules/cm_aliens/structures/special/pylon_core.dm b/code/modules/cm_aliens/structures/special/pylon_core.dm
index 62a7417c57f8..a7cb15a31ce7 100644
--- a/code/modules/cm_aliens/structures/special/pylon_core.dm
+++ b/code/modules/cm_aliens/structures/special/pylon_core.dm
@@ -272,12 +272,14 @@
if(spawning_larva || (last_larva_queue_time + spawn_cooldown * 4) < world.time)
last_larva_queue_time = world.time
var/list/players_with_xeno_pref = get_alien_candidates(linked_hive)
- if(length(players_with_xeno_pref))
- if(spawning_larva && spawn_burrowed_larva(players_with_xeno_pref[1]))
- // We were in spawning_larva mode and successfully spawned someone
- count_spawned = 1
- // Update everyone's queue status
- message_alien_candidates(players_with_xeno_pref, dequeued = count_spawned)
+ if(spawning_larva)
+ var/i = 0
+ while(i < length(players_with_xeno_pref) && can_spawn_larva())
+ if(spawn_burrowed_larva(players_with_xeno_pref[++i]))
+ // We were in spawning_larva mode and successfully spawned someone
+ count_spawned++
+ // Update everyone's queue status
+ message_alien_candidates(players_with_xeno_pref, dequeued = count_spawned)
if(linked_hive.hijack_burrowed_surge && (last_surge_time + surge_cooldown) < world.time)
last_surge_time = world.time
diff --git a/code/modules/droppod/droppod_ui.dm b/code/modules/droppod/droppod_ui.dm
index 33202e38a0a7..b0c6683a4f7c 100644
--- a/code/modules/droppod/droppod_ui.dm
+++ b/code/modules/droppod/droppod_ui.dm
@@ -76,7 +76,8 @@ GLOBAL_LIST_INIT(droppod_target_mode, list(
/datum/admin_podlauncher/proc/refresh_bay()
bay = locate(/area/admin/droppod/loading) in GLOB.sorted_areas
if(!bay)
- to_chat(SPAN_WARNING("There's no /area/admin/droppod/loading. You can make one yourself, but yell at the mappers to fix this."))
+ if(holder)
+ to_chat(holder, SPAN_WARNING("There's no /area/admin/droppod/loading. You can make one yourself, but yell at the mappers to fix this."))
CRASH("No /area/admin/droppod/loading has been mapped into the admin z-level!")
ordered_area = list()
for(var/turf/T in bay)
@@ -221,7 +222,8 @@ GLOBAL_LIST_INIT(droppod_target_mode, list(
custom_dropoff = TRUE
temp_pod.dropoff_point = get_turf(target)
- to_chat(SPAN_NOTICE("You have selected [temp_pod.dropoff_point] as your dropoff location."))
+ if(holder)
+ to_chat(holder, SPAN_NOTICE("You have selected [temp_pod.dropoff_point] as your dropoff location."))
SStgui.update_uis(src)
return COMPONENT_INTERRUPT_CLICK
diff --git a/code/modules/keybindings/setup.dm b/code/modules/keybindings/setup.dm
index 703649808f70..9ba1b783a11d 100644
--- a/code/modules/keybindings/setup.dm
+++ b/code/modules/keybindings/setup.dm
@@ -15,7 +15,7 @@
for(var/k in 1 to length(macro_set))
var/list/split_name = splittext(macro_set[k], ".")
- if(findtext(split_name[2], "srvkeybinds-") == 1)
+ if((length(split_name) >= 2) && (findtext(split_name[2], "srvkeybinds-") == 1))
var/macro_name = "[split_name[1]].[split_name[2]]" // [3] is "command"
erase_output = "[erase_output];[macro_name].parent=null"
winset(src, null, erase_output)
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 3bc8e97623da..95fd393d12b5 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -1741,3 +1741,9 @@
return FALSE
. = ..()
+
+/mob/living/carbon/human/make_dizzy(amount)
+ dizziness = min(500, dizziness + amount) // store what will be new value
+ // clamped to max 500
+ if(dizziness > 100 && !is_dizzy)
+ INVOKE_ASYNC(src, PROC_REF(dizzy_process))
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index c28de81ecfc1..26139af07eb6 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -593,20 +593,13 @@
adds a dizziness amount to a mob
use this rather than directly changing var/dizziness
since this ensures that the dizzy_process proc is started
-currently only humans get dizzy
+currently only mob/living/carbon/human get dizzy
value of dizziness ranges from 0 to 1000
below 100 is not dizzy
*/
/mob/proc/make_dizzy(amount)
- if(!istype(src, /mob/living/carbon/human)) // for the moment, only humans get dizzy
- return
-
- dizziness = min(500, dizziness + amount) // store what will be new value
- // clamped to max 500
- if(dizziness > 100 && !is_dizzy)
- INVOKE_ASYNC(src, PROC_REF(dizzy_process))
-
+ return
/*
dizzy process - wiggles the client's pixel offset over time
diff --git a/code/modules/projectiles/guns/flamer/flamer.dm b/code/modules/projectiles/guns/flamer/flamer.dm
index 44fe816c0e6a..0089df506d2d 100644
--- a/code/modules/projectiles/guns/flamer/flamer.dm
+++ b/code/modules/projectiles/guns/flamer/flamer.dm
@@ -461,7 +461,8 @@ GLOBAL_LIST_EMPTY(flamer_particles)
tied_reagent = new R.type() // Can't get deleted this way
tied_reagent.make_alike(R)
- tied_reagents = obj_reagents
+ if(obj_reagents)
+ tied_reagents = obj_reagents
target_clicked = target
diff --git a/code/modules/shuttle/computers/dropship_computer.dm b/code/modules/shuttle/computers/dropship_computer.dm
index 4fe102270537..d72e0871af72 100644
--- a/code/modules/shuttle/computers/dropship_computer.dm
+++ b/code/modules/shuttle/computers/dropship_computer.dm
@@ -319,6 +319,9 @@
.["door_status"] = is_remote ? list() : shuttle.get_door_data()
.["has_flyby_skill"] = skillcheck(user, SKILL_PILOT, SKILL_PILOT_EXPERT)
+ // Launch Alarm Variables
+ .["playing_launch_announcement_alarm"] = shuttle.playing_launch_announcement_alarm
+
.["destinations"] = list()
// add flight
.["destinations"] += list(
@@ -381,6 +384,7 @@
msg_admin_niche(log)
log_interact(user, msg = "[log]")
shuttle.send_for_flyby()
+ stop_playing_launch_announcement_alarm()
return TRUE
update_equipment(is_optimised, FALSE)
@@ -410,6 +414,7 @@
var/log = "[key_name(user)] launched the dropship [src.shuttleId] on transport."
msg_admin_niche(log)
log_interact(user, msg = "[log]")
+ stop_playing_launch_announcement_alarm()
return TRUE
if("button-push")
playsound(loc, get_sfx("terminal_button"), KEYBOARD_SOUND_VOLUME, 1)
@@ -469,6 +474,23 @@
if("cancel-flyby")
if(shuttle.in_flyby && shuttle.timer && shuttle.timeLeft(1) >= DROPSHIP_WARMUP_TIME)
shuttle.setTimer(DROPSHIP_WARMUP_TIME)
+ if("play_launch_announcement_alarm")
+ if (shuttle.mode != SHUTTLE_IDLE && shuttle.mode != SHUTTLE_RECHARGING)
+ to_chat(usr, SPAN_WARNING("The Launch Announcement Alarm is designed to tell people that you're going to take off soon."))
+ return
+ shuttle.alarm_sound_loop.start()
+ shuttle.playing_launch_announcement_alarm = TRUE
+ return
+ if ("stop_playing_launch_announcement_alarm")
+ stop_playing_launch_announcement_alarm()
+ return
+
+/obj/structure/machinery/computer/shuttle/dropship/flight/proc/stop_playing_launch_announcement_alarm()
+ var/obj/docking_port/mobile/marine_dropship/shuttle = SSshuttle.getShuttle(shuttleId)
+
+ shuttle.alarm_sound_loop.stop()
+ shuttle.playing_launch_announcement_alarm = FALSE
+ return
/obj/structure/machinery/computer/shuttle/dropship/flight/lz1
icon = 'icons/obj/structures/machinery/computer.dmi'
diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm
index 7bbdb214d34b..85fc38bf5f1b 100644
--- a/code/modules/shuttle/shuttle.dm
+++ b/code/modules/shuttle/shuttle.dm
@@ -343,6 +343,9 @@
var/rechargeTime = 0 //time spent after arrival before being able to launch again
var/prearrivalTime = 0 //delay after call time finishes for sound effects, explosions, etc.
+ var/playing_launch_announcement_alarm = FALSE // FALSE = off ; TRUE = on
+ var/datum/looping_sound/looping_launch_announcement_alarm/alarm_sound_loop
+
var/landing_sound = 'sound/effects/engine_landing.ogg'
var/ignition_sound = 'sound/effects/engine_startup.ogg'
/// Default shuttle audio ambience while flying
@@ -383,6 +386,7 @@
/obj/docking_port/mobile/Destroy(force)
if(force)
+ QDEL_NULL(alarm_sound_loop)
SSshuttle.mobile -= src
destination = null
previous = null
@@ -410,6 +414,14 @@
initial_engines = count_engines()
current_engines = initial_engines
+ //Launch Announcement Alarm variables setup
+ alarm_sound_loop = new(src)
+ alarm_sound_loop.mid_length = 20
+ alarm_sound_loop.extra_range = 30
+ alarm_sound_loop.volume = 100
+ alarm_sound_loop.is_sound_projecting = TRUE
+ alarm_sound_loop.falloff_distance = 7
+
#ifdef DOCKING_PORT_HIGHLIGHT
highlight("#0f0")
#endif
diff --git a/code/modules/tooltip/tooltip.dm b/code/modules/tooltip/tooltip.dm
index b3dc005c0887..e668196d383a 100644
--- a/code/modules/tooltip/tooltip.dm
+++ b/code/modules/tooltip/tooltip.dm
@@ -98,10 +98,12 @@ Notes:
last_target = null
/datum/tooltip/proc/do_hide()
- winshow(owner, control, FALSE)
+ if(owner)
+ winshow(owner, control, FALSE)
/datum/tooltip/Destroy(force, ...)
last_target = null
+ owner = null
return ..()
//Open a tooltip for user, at a location based on params
diff --git a/colonialmarines.dme b/colonialmarines.dme
index 293b69c60d1c..101a80f0e262 100644
--- a/colonialmarines.dme
+++ b/colonialmarines.dme
@@ -268,6 +268,7 @@
#include "code\controllers\subsystem\police_clues.dm"
#include "code\controllers\subsystem\power.dm"
#include "code\controllers\subsystem\predships.dm"
+#include "code\controllers\subsystem\profiler.dm"
#include "code\controllers\subsystem\projectiles.dm"
#include "code\controllers\subsystem\quadtrees.dm"
#include "code\controllers\subsystem\reagents.dm"
@@ -553,6 +554,7 @@
#include "code\datums\langchat\langchat.dm"
#include "code\datums\looping_sounds\_looping_sound.dm"
#include "code\datums\looping_sounds\item_sounds.dm"
+#include "code\datums\looping_sounds\misc_sounds.dm"
#include "code\datums\origin\civilian.dm"
#include "code\datums\origin\origin.dm"
#include "code\datums\origin\upp.dm"
diff --git a/html/changelogs/AutoChangeLog-pr-4857.yml b/html/changelogs/AutoChangeLog-pr-4857.yml
deleted file mode 100644
index 775c87aff5e5..000000000000
--- a/html/changelogs/AutoChangeLog-pr-4857.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "hislittlecuzingames"
-delete-after: True
-changes:
- - code_imp: "Added ability to have looping sounds from further away"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-4953.yml b/html/changelogs/AutoChangeLog-pr-4953.yml
new file mode 100644
index 000000000000..4dd8c48e8206
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-4953.yml
@@ -0,0 +1,4 @@
+author: "Drathek"
+delete-after: True
+changes:
+ - bugfix: "Tweaked larva queue spawning: Now spawns as many larva as possible each cycle rather than one."
\ No newline at end of file
diff --git a/html/changelogs/archive/2023-11.yml b/html/changelogs/archive/2023-11.yml
index 6ffb285f9689..66eaccb86d87 100644
--- a/html/changelogs/archive/2023-11.yml
+++ b/html/changelogs/archive/2023-11.yml
@@ -266,3 +266,16 @@
Zonespace27:
- bugfix: Jump-to-area verb will now warn you if there aren't any turfs in the given
area.
+2023-11-21:
+ hislittlecuzingames:
+ - code_imp: Added ability to have looping sounds from further away
+2023-11-22:
+ AnturK:
+ - server: the server now supports auto-profiling
+ Birdtalon:
+ - code_imp: Removes some istype(src)
+ Morrow:
+ - rscadd: Mess tech positions now scale from 1 to 2 after 70 marines are in the
+ game
+ hislittlecuzingames:
+ - rscadd: Launch Announcement Alarm for dropships to notify ground forces of departure.
diff --git a/sound/vehicles/Dropships/single_alarm_brr_dropship_1.ogg b/sound/vehicles/Dropships/single_alarm_brr_dropship_1.ogg
new file mode 100644
index 000000000000..9fe0b4c11da1
Binary files /dev/null and b/sound/vehicles/Dropships/single_alarm_brr_dropship_1.ogg differ
diff --git a/tgui/packages/tgui/interfaces/DropshipFlightControl.tsx b/tgui/packages/tgui/interfaces/DropshipFlightControl.tsx
index 65a67524f5b4..bbb7fea96d2c 100644
--- a/tgui/packages/tgui/interfaces/DropshipFlightControl.tsx
+++ b/tgui/packages/tgui/interfaces/DropshipFlightControl.tsx
@@ -23,6 +23,8 @@ interface DropshipNavigationProps extends NavigationProps {
primary_lz?: string;
automated_control: AutomatedControl;
has_flyby_skill: 0 | 1;
+
+ playing_launch_announcement_alarm: boolean;
}
const DropshipDoorControl = (_, context) => {
@@ -42,7 +44,10 @@ const DropshipDoorControl = (_, context) => {