diff --git a/code/__DEFINES/__game.dm b/code/__DEFINES/__game.dm index e667ccf6db3f..e0d9fa45a8f8 100644 --- a/code/__DEFINES/__game.dm +++ b/code/__DEFINES/__game.dm @@ -245,6 +245,7 @@ /// Frequency stuff only works with 45kbps oggs. #define GET_RANDOM_FREQ rand(32000, 55000) +#define GET_RANDOM_FREQ_MINOR rand(42000, 48000) // Ceilings diff --git a/code/__DEFINES/dcs/signals/atom/signals_movable.dm b/code/__DEFINES/dcs/signals/atom/signals_movable.dm index ba889d0b5212..910f3844d546 100644 --- a/code/__DEFINES/dcs/signals/atom/signals_movable.dm +++ b/code/__DEFINES/dcs/signals/atom/signals_movable.dm @@ -1,6 +1,9 @@ //from base of atom/movable/onTransitZ(): (old_z, new_z) #define COMSIG_MOVABLE_Z_CHANGED "movable_ztransit" +//from base of /area/Entered(): (/atom, old_area, new_area) +#define COMSIG_MOVABLE_ENTERED_AREA "movable_entered_area" + /// From /atom/movable/proc/launch_towards #define COMSIG_MOVABLE_PRE_THROW "movable_pre_throw" #define COMPONENT_CANCEL_THROW (1<<0) diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 9f6f104d6b90..bdab61efbc9b 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -171,6 +171,14 @@ //================================================= +/* SPECIAL LIGHTING DEFINES */ + +#define SPECIAL_LIGHTING_PREROUND "preround" +#define SPECIAL_LIGHTING_SUNSET "sunset" +#define SPECIAL_LIGHTING_SUNRISE "sunrise" + +//================================================= + //Languages! #define LANGUAGE_HUMAN 1 #define LANGUAGE_ALIEN 2 diff --git a/code/__DEFINES/mode.dm b/code/__DEFINES/mode.dm index 4c3a658ff421..093ddc5fa54a 100644 --- a/code/__DEFINES/mode.dm +++ b/code/__DEFINES/mode.dm @@ -58,6 +58,7 @@ #define MODE_RANDOM_HIVE (1<<12)// Makes Join-as-Xeno choose a hive to join as burrowed larva at random rather than at user's input.. #define MODE_THUNDERSTORM (1<<13)// Enables thunderstorm effects on maps that are compatible with it. (Lit exterior tiles, rain effects) #define MODE_FACTION_CLASH (1<<14)// Disables scopes, sniper sentries, OBs, shooting corpses, dragging enemy corpses, stripping enemy corpses +#define MODE_SUNSET (1<<15) // Has a sunset on the ground Z at the start of the round // Gamemode Toggleable Flags #define MODE_NO_SNIPER_SENTRY (1<<0) /// Upgrade kits will no longer allow you to select long-range upgrades @@ -316,3 +317,6 @@ DEFINE_BITFIELD(whitelist_status, list( GLOBAL_VAR(last_ares_callout) GLOBAL_VAR(last_qm_callout) + +/// Registered a single time, used to determine sunrise stuff +GLOBAL_VAR(sunrise_starting_time) diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index facc2b951ad3..49b4caa04056 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -417,6 +417,7 @@ DEFINE_BITFIELD(flags_round_type, list( "MODE_RANDOM_HIVE" = MODE_RANDOM_HIVE, "MODE_THUNDERSTORM" = MODE_THUNDERSTORM, "MODE_FACTION_CLASH" = MODE_FACTION_CLASH, + "MODE_SUNSET" = MODE_SUNSET, )) DEFINE_BITFIELD(toggleable_flags, list( diff --git a/code/_onclick/hud/fullscreen.dm b/code/_onclick/hud/fullscreen.dm index 505b1876e3af..6998f49b3b39 100644 --- a/code/_onclick/hud/fullscreen.dm +++ b/code/_onclick/hud/fullscreen.dm @@ -1,8 +1,15 @@ +#define Z_CHANGE_CALL "z_change" +#define AREA_CHANGE_CALL "area_change" /mob var/list/fullscreens = list() + ///The type of special lighting such as a sunset or lightning is currently active, dont have more than one of these without a special fullscreen framework + var/special_lighting = null + ///A var to check if there is currently an active special lighting timer already set in order to prevent dupes + var/special_lighting_active_timer = FALSE + /mob/proc/overlay_fullscreen(category, type, severity) var/atom/movable/screen/fullscreen/screen = fullscreens[category] if (!screen || screen.type != type) @@ -61,6 +68,35 @@ else client.remove_from_screen(screen) +/mob/proc/initialize_special_lighting() //initialized on hud.dm when a new mob is spawned so you can't dodge this unless you dont have a client somehow + if(!SSticker.mode) + if(special_lighting) + return + SSticker.OnRoundstart(CALLBACK(src, PROC_REF(initialize_special_lighting))) + special_lighting = SPECIAL_LIGHTING_PREROUND // do not let a special_lighting get called before roundstart + return + if(SSticker.mode.flags_round_type & MODE_SUNSET) + if(!fullscreens["lighting_backdrop"] || special_lighting == SPECIAL_LIGHTING_SUNSET || special_lighting_active_timer) + return + special_lighting = SPECIAL_LIGHTING_SUNSET + special_lighting_active_timer = TRUE + if(ROUND_TIME < 4 SECONDS) //if you're in before full setup, dont let special lightings get called prior, it gets messy + addtimer(CALLBACK(src, PROC_REF(special_lighting_animate), SPECIAL_LIGHTING_SUNSET, 30 SECONDS, 9, 10 SECONDS, 0, null, 1, FALSE, TRUE, TRUE), 3 SECONDS) + addtimer(CALLBACK(src, PROC_REF(special_lighting_register_signals)), 3 SECONDS) + else if(ROUND_TIME < 280 SECONDS) + special_lighting = SPECIAL_LIGHTING_SUNSET + special_lighting_active_timer = TRUE + special_lighting_animate(SPECIAL_LIGHTING_SUNSET, 30 SECONDS, 9, 10 SECONDS, 0, 0.1 SECONDS, 1, TRUE, TRUE, TRUE) + special_lighting_register_signals() + return + if(GLOB.sunrise_starting_time) + if(!fullscreens["lighting_backdrop"] || special_lighting == SPECIAL_LIGHTING_SUNRISE || special_lighting == SPECIAL_LIGHTING_SUNSET || special_lighting_active_timer) + return + special_lighting = SPECIAL_LIGHTING_SUNRISE + special_lighting_active_timer = TRUE + special_lighting_animate(SPECIAL_LIGHTING_SUNRISE, 30 SECONDS, 6, 1 SECONDS, 0.1 SECONDS, -1, TRUE, TRUE, FALSE) + special_lighting_register_signals() //sunrise is permanent, you wont need to unregister + /atom/movable/screen/fullscreen icon = 'icons/mob/hud/screen1_full.dmi' @@ -227,9 +263,249 @@ color = "#000" blend_mode = BLEND_ADD + +/mob/proc/special_lighting_animate(p_special_lighting_type = null, p_stage_time, p_max_stages, p_startup_delay = 1 SECONDS, p_special_start_time = 0, p_special_stage_time = null, p_special_tick_dir, p_special_call = FALSE, p_create_new_lighting_timer = FALSE, p_lighting_deactivates = TRUE) + + var/atom/movable/screen/fullscreen/screen = fullscreens["lighting_backdrop"] + var/area/lighting_mob_area = get_area(src) + + if(p_special_lighting_type != special_lighting) + return + + var/lighting_color = "#000" /// used in the animation, set by the special_lighting_type + + var/stage_time = p_stage_time /// how long each stage lasts, don't edit this if you want smooth movement, use special_stage_time instead + var/max_stages = p_max_stages /// how many stages of special lighting there are, starts at 0 + + var/startup_delay = p_startup_delay /// how long the initial stage lasts for, doesn't factor in round start stuff + var/special_start_time = p_special_start_time /// when the special_lighting starts (use 0 if roundstart) + + var/special_stage_time = p_special_stage_time /// changes animation time without changing stage time, used by special calls and init stages + var/special_call = p_special_call /// the type of special call + var/special_tick_dir = p_special_tick_dir /// If it gets a special call, if it ticks up or down in order to prevent advantages + + var/create_new_lighting_timer = p_create_new_lighting_timer /// used to prevent timer dupes, keep this as False unless its supposed to be the first call + var/lighting_deactivates = p_lighting_deactivates /// If the lighting deactivates + + var/lighting_stage = clamp((floor((ROUND_TIME + stage_time - special_start_time - startup_delay)/stage_time)), 0, max_stages) /// the current stage of the lighting, ticks up by 1 every stagetime after startup_delay + start_time + //uses formula (x + y - w - z)/(y) with x = round_time, y = stage_time, w = special_start_time, and z being startup_delay + + var/time_til_next_lighting_call = max(((lighting_stage * stage_time) + startup_delay + special_start_time - ROUND_TIME), 0.5 SECONDS) /// how long until the next sunstage occurs (minimum of 0.5 seconds) + + if(special_call && lighting_stage != 0) // controls stuff related to special calls, prevents people from getting unfair advantages by getting stages reset, unnecessary for short anims + if(lighting_deactivates && ROUND_TIME < (stage_time * max_stages) + special_start_time + startup_delay) //if its finished max stage anim and doesn't deactivate, make special calls animate to full + lighting_stage = clamp((lighting_stage + special_tick_dir), 0, max_stages) + if(time_til_next_lighting_call < special_stage_time) + time_til_next_lighting_call = time_til_next_lighting_call + special_stage_time //delays main anims until the special call anim is done + + if(special_lighting == SPECIAL_LIGHTING_SUNSET) + lighting_color = special_lighting_sunset(lighting_stage) + if(special_lighting == SPECIAL_LIGHTING_SUNRISE) + lighting_color = special_lighting_sunrise(lighting_stage) + + if(lighting_stage == 0) //there aren't any cases you won't want these coming up fast + special_stage_time = 0.5 SECONDS + time_til_next_lighting_call = startup_delay + special_start_time - ROUND_TIME + + if(create_new_lighting_timer) // if create_new_lighting_timer = TRUE, a new timer gets set + special_lighting_active_timer = FALSE + + if(!special_lighting_active_timer) + if(lighting_stage < max_stages) + addtimer(CALLBACK(src, PROC_REF(special_lighting_animate), special_lighting, stage_time, max_stages, startup_delay, special_start_time, null, special_tick_dir, FALSE, TRUE, lighting_deactivates), time_til_next_lighting_call, TIMER_UNIQUE|TIMER_OVERRIDE|TIMER_DELETE_ME) + special_lighting_active_timer = TRUE + if(lighting_stage == max_stages && lighting_deactivates) // deactives special lighting when the sun hits #000 + addtimer(CALLBACK(src, PROC_REF(special_lighting_unregister_signals)), time_til_next_lighting_call, TIMER_UNIQUE|TIMER_OVERRIDE|TIMER_DELETE_ME) + + if(CEILING_IS_PROTECTED(lighting_mob_area?.ceiling, CEILING_PROTECTION_TIER_2)) //if underground, don't animate, this is needed in combo with the special area check + return + if(!is_ground_level(z) && special_call != Z_CHANGE_CALL) // dont animate if not groundlevel + return + + if(special_stage_time) + stage_time = special_stage_time + + animate(screen, color = lighting_color, time = stage_time) + + +/mob/proc/special_lighting_sunset(lighting_stage) + + var/lighting_color = "#000" /// used in the animation, set by the special_lighting_type + + //if its cold or in space (or chances claim) + if(SSmapping.configs[GROUND_MAP].environment_traits[MAP_COLD] || SSmapping.configs[GROUND_MAP].map_name == MAP_LV522_CHANCES_CLAIM || MAP_PRISON_STATION_V3) + switch(lighting_stage) //for sun stages, the more you have the better it looks when special called, I recommend choosing cinematic 4 colors then using a gradient tool to pick out the rest + if(0) + lighting_color = "#a8c3cf" + if(1) + lighting_color = "#7a9abb" + if(2) + lighting_color = "#6679a8" + if(3) + lighting_color = "#516a8b" + if(4) + lighting_color = "#38486e" + if(5) + lighting_color = "#2c2f4d" + if(6) + lighting_color = "#211b36" + if(7) + lighting_color = "#1f1b33" + if(8) + lighting_color = "#0c0a1b" + if(9) + lighting_color = "#000" + else //the default, a very warm sunset + switch(lighting_stage) + if(0) + lighting_color = "#e3a979" + if(1) + lighting_color = "#e29658" + if(2) + lighting_color = "#da8b4a" + if(3) + lighting_color = "#a9633c" + if(4) + lighting_color = "#90422d" + if(5) + lighting_color = "#68333a" + if(6) + lighting_color = "#4d2b35" + if(7) + lighting_color = "#231935" + if(8) + lighting_color = "#050c27" + if(9) + lighting_color = "#000" + + return lighting_color + + +/mob/proc/special_lighting_sunrise(lighting_stage) + + var/lighting_color = "#000" /// used in the animation, set by the special_lighting_type + + switch(lighting_stage) //only one type of sunrise cause it just looks more cinematic to have a warm sunset on cold maps + if(0) + lighting_color = "#000" + if(1) + lighting_color = "#040712" + if(2) + lighting_color = "#111322" + if(3) + lighting_color = "#291642" + if(4) + lighting_color = "#3f2239" + if(5) + lighting_color = "#632c3d" + if(6) + lighting_color = "#b97034" //it ends on very orange for cinematics + + return lighting_color + + +/mob/proc/special_lighting_register_signals() + + RegisterSignal(src, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(special_lighting_z_change), TRUE) + RegisterSignal(src, COMSIG_MOVABLE_ENTERED_AREA, PROC_REF(special_lighting_area_change), TRUE) + + +/mob/proc/special_lighting_unregister_signals() + + special_lighting = null //clears special lighting + + UnregisterSignal(src, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(special_lighting_z_change)) + UnregisterSignal(src, COMSIG_MOVABLE_ENTERED_AREA, PROC_REF(special_lighting_area_change)) + + +/mob/proc/special_lighting_z_change(atom/source, old_z, new_z) + SIGNAL_HANDLER + + var/atom/movable/screen/fullscreen/screen = fullscreens["lighting_backdrop"] + + var/stage_time = 30 SECONDS + var/max_stages = null + var/startup_delay = 10 SECONDS + var/special_start_time = 0 + var/special_stage_time = 0.1 SECONDS + var/special_tick_dir = 0 + var/special_call = Z_CHANGE_CALL + var/create_new_lighting_timer = FALSE + var/lighting_deactivates = TRUE + + if(!special_lighting || special_lighting == SPECIAL_LIGHTING_PREROUND) + return + + switch(special_lighting) //figure out a way of handling this better if possible + if(SPECIAL_LIGHTING_SUNSET) + max_stages = 9 + special_tick_dir = 1 + if(SPECIAL_LIGHTING_SUNRISE) + max_stages = 6 + special_start_time = GLOB.sunrise_starting_time + special_tick_dir = -1 + lighting_deactivates = FALSE + + if(is_ground_level(new_z)) + special_lighting_animate(special_lighting, stage_time, max_stages, startup_delay, special_start_time, special_stage_time, special_tick_dir, special_call, create_new_lighting_timer, lighting_deactivates) + + if(!is_ground_level(new_z)) + animate(screen, color = "#000", time = 0.1 SECONDS) + + +/mob/proc/special_lighting_area_change(atom/source, old_area, new_area) + SIGNAL_HANDLER + + var/atom/movable/screen/fullscreen/screen = fullscreens["lighting_backdrop"] + + var/stage_time = 30 SECONDS + var/max_stages = null + var/startup_delay = 10 SECONDS + var/special_start_time = 0 + var/special_stage_time = 4 SECONDS + var/special_tick_dir = 0 + var/special_call = AREA_CHANGE_CALL + var/create_new_lighting_timer = FALSE + var/lighting_deactivates = TRUE + + + if(!special_lighting || special_lighting == SPECIAL_LIGHTING_PREROUND) + return + + switch(special_lighting) + if(SPECIAL_LIGHTING_SUNSET) + max_stages = 9 + special_tick_dir = 1 + if(SPECIAL_LIGHTING_SUNRISE) + max_stages = 6 + special_start_time = GLOB.sunrise_starting_time + special_tick_dir = -1 + lighting_deactivates = FALSE + + + var/area/mob_old_area = old_area + var/area/mob_new_area = new_area + + var/oldloc_incave = null + var/newloc_incave = null + + if(CEILING_IS_PROTECTED(mob_old_area?.ceiling, CEILING_PROTECTION_TIER_2)) + oldloc_incave = TRUE + if(CEILING_IS_PROTECTED(mob_new_area?.ceiling, CEILING_PROTECTION_TIER_2)) + newloc_incave = TRUE + + if(newloc_incave && !oldloc_incave) //handles both null old loc and false oldloc + animate(screen, color = "#000", time = 4 SECONDS, easing = QUAD_EASING | EASE_OUT) + else if(oldloc_incave && !newloc_incave) + special_lighting_animate(special_lighting, stage_time, max_stages, startup_delay, special_start_time, special_stage_time, special_tick_dir, special_call, create_new_lighting_timer, lighting_deactivates) + + /atom/movable/screen/fullscreen/see_through_darkness icon_state = "nightvision" plane = LIGHTING_PLANE layer = LIGHTING_PRIMARY_LAYER blend_mode = BLEND_ADD show_when_dead = TRUE + +#undef Z_CHANGE_CALL +#undef AREA_CHANGE_CALL diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm index 2d49abb52012..c4347ec99836 100644 --- a/code/_onclick/hud/hud.dm +++ b/code/_onclick/hud/hud.dm @@ -83,6 +83,8 @@ plane_masters["[instance.plane]"] = instance if(owner.client) instance.backdrop(mymob) + if(!isnewplayer(mymob) && !mymob.special_lighting) //if they have a client but arent on the title screen + mymob.initialize_special_lighting() for(var/mytype in subtypesof(/atom/movable/plane_master_controller)) var/atom/movable/plane_master_controller/controller_instance = new mytype(null,src) diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index be7037295497..b7a1d8eba5cd 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -351,15 +351,24 @@ if(POWER_CHANNEL_ONEOFF) used_oneoff += amount -/area/Entered(A,atom/OldLoc) - if(ismob(A)) +/area/Entered(A, atom/OldLoc) + if(ismob(A) && !isnewplayer(A)) if(!OldLoc) return - var/mob/M = A - var/area/old_area = get_area(OldLoc) - if(old_area == src) + var/mob/area_entered_mod = A + + var/area/new_area = get_area(area_entered_mod) + var/area/old_area = null + if(!isarea(OldLoc)) + old_area = get_area(OldLoc) + else + old_area = OldLoc + + if(old_area == src || !old_area) return - M?.client?.soundOutput?.update_ambience(src, null, TRUE) + + SEND_SIGNAL(area_entered_mod, COMSIG_MOVABLE_ENTERED_AREA, old_area, new_area) + area_entered_mod?.client?.soundOutput?.update_ambience(src, null, TRUE) else if(istype(A, /obj/structure/machinery)) add_machine(A) diff --git a/code/game/gamemodes/colonialmarines/colonialmarines.dm b/code/game/gamemodes/colonialmarines/colonialmarines.dm index 14f5397b1f91..6284748282ea 100644 --- a/code/game/gamemodes/colonialmarines/colonialmarines.dm +++ b/code/game/gamemodes/colonialmarines/colonialmarines.dm @@ -9,7 +9,7 @@ xeno_required_num = 1 //Need at least one xeno. monkey_amount = 5 corpses_to_spawn = 0 - flags_round_type = MODE_INFESTATION|MODE_FOG_ACTIVATED|MODE_NEW_SPAWN + flags_round_type = MODE_INFESTATION|MODE_FOG_ACTIVATED|MODE_NEW_SPAWN|MODE_SUNSET static_comms_amount = 1 var/round_status_flags @@ -428,6 +428,13 @@ else SSticker.roundend_check_paused = TRUE round_finished = MODE_INFESTATION_M_MAJOR //Humans destroyed the xenomorphs. + if(!GLOB.sunrise_starting_time) + GLOB.sunrise_starting_time = ROUND_TIME + for(var/mob/lighting_mob as anything in GLOB.player_list) + if(!lighting_mob.special_lighting && lighting_mob.fullscreens["lighting_backdrop"]) + lighting_mob.special_lighting = SPECIAL_LIGHTING_SUNRISE + lighting_mob.special_lighting_active_timer = TRUE + lighting_mob.special_lighting_animate(SPECIAL_LIGHTING_SUNRISE, 30 SECONDS, 6, 10 SECONDS, GLOB.sunrise_starting_time, null, -1, FALSE, TRUE, FALSE) ares_conclude() addtimer(VARSET_CALLBACK(SSticker, roundend_check_paused, FALSE), MARINE_MAJOR_ROUND_END_DELAY) else if(!num_humans && !num_xenos) @@ -452,6 +459,13 @@ round_finished = MODE_INFESTATION_M_MAJOR else round_finished = MODE_INFESTATION_M_MINOR + if(!GLOB.sunrise_starting_time) //putting a sunset call here too + GLOB.sunrise_starting_time = ROUND_TIME + for(var/mob/lighting_mob as anything in GLOB.player_list) + if(!lighting_mob.special_lighting && lighting_mob.fullscreens["lighting_backdrop"]) + lighting_mob.special_lighting = SPECIAL_LIGHTING_SUNRISE + lighting_mob.special_lighting_active_timer = TRUE + lighting_mob.special_lighting_animate(SPECIAL_LIGHTING_SUNRISE, 30 SECONDS, 6, 10 SECONDS, GLOB.sunrise_starting_time, null, -1, FALSE, TRUE, FALSE) /////////////////////////////// //Checks if the round is over// diff --git a/code/game/sound.dm b/code/game/sound.dm index 1ab8fc42f41a..549564cf8ee9 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -118,7 +118,10 @@ S.file = get_sfx(soundin) if(random_freq) - S.frequency = GET_RANDOM_FREQ + if(random_freq == "minor") + S.frequency = GET_RANDOM_FREQ_MINOR + else + S.frequency = GET_RANDOM_FREQ S.volume = vol S.volume_cat = vol_cat S.channel = channel diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index d4db6bccde83..fd5061df920e 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -578,10 +578,10 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp if(!new_turf) return - var/area/new_area = new_turf.loc + var/area/new_area = get_area(new_turf) if((new_area != last_area) && new_area) - new_area.Entered(src) + new_area.Entered(src, last_area) if(last_area) last_area.Exited(src) diff --git a/code/modules/mob/living/carbon/xenomorph/hive_status.dm b/code/modules/mob/living/carbon/xenomorph/hive_status.dm index d2545a85d527..db276b270705 100644 --- a/code/modules/mob/living/carbon/xenomorph/hive_status.dm +++ b/code/modules/mob/living/carbon/xenomorph/hive_status.dm @@ -71,6 +71,9 @@ var/see_humans_on_tacmap = FALSE + /// Used to track the initial screech for groundside mobs + var/initial_screech = TRUE + var/list/hive_inherant_traits // Cultist Info @@ -213,6 +216,26 @@ xeno_message(SPAN_XENOANNOUNCE("The Hive is now strong enough to support: [castes]")) xeno_maptext("The Hive can now support: [castes]", "Hive Strengthening") + if(SSticker.mode.flags_round_type & MODE_INFESTATION) //checks if gamemode is a xeno gamemode before calling, will roar with no queen cause of implied queen existence + zlevel_evo_echo() + if(initial_screech) //set to false after the first screech is called + initial_screech = FALSE + +/datum/hive_status/proc/zlevel_evo_echo() + for(var/mob/groundmob as anything in GLOB.player_list) + if(is_ground_level(groundmob.z) && !isxeno(groundmob)) + if(initial_screech) + playsound_client(groundmob.client, 'sound/voice/alien_echoroar_1.ogg', groundmob.loc, 65, FALSE) //boosted a lot cause quiet audio + if(ishuman(groundmob)) + to_chat(groundmob, SPAN_HIGHDANGER("You hear a distant screech and feel your insides freeze up... something new is with you in this colony.")) + if(issynth(groundmob)) + to_chat(groundmob, SPAN_HIGHDANGER("You hear the distant call of an unknown bioform, it sounds like they're informing others to change form. You begin to analyze and decrypt the strange vocalization.")) + return + var/area/queen_area = get_area(living_xeno_queen) + if(CEILING_IS_PROTECTED(queen_area?.ceiling, CEILING_PROTECTION_TIER_3) || !queen_area) + playsound_client(groundmob.client, 'sound/voice/alien_echoroar_2.ogg', groundmob.loc, 70, "minor") //if queen is underground or there is no queen + else + playsound_client(groundmob.client, 'sound/voice/alien_echoroar_3.ogg', groundmob.loc, 80, "minor") //if queen is outside // Adds a xeno to this hive /datum/hive_status/proc/add_xeno(mob/living/carbon/xenomorph/X) diff --git a/sound/voice/alien_echoroar_1.ogg b/sound/voice/alien_echoroar_1.ogg new file mode 100644 index 000000000000..e46ac612b6e9 Binary files /dev/null and b/sound/voice/alien_echoroar_1.ogg differ diff --git a/sound/voice/alien_echoroar_2.ogg b/sound/voice/alien_echoroar_2.ogg new file mode 100644 index 000000000000..dd4ec770d0a1 Binary files /dev/null and b/sound/voice/alien_echoroar_2.ogg differ diff --git a/sound/voice/alien_echoroar_3.ogg b/sound/voice/alien_echoroar_3.ogg new file mode 100644 index 000000000000..506ed83a9442 Binary files /dev/null and b/sound/voice/alien_echoroar_3.ogg differ