From 56fb81d02c98aaf67e9bed73fd9ac592112d4f91 Mon Sep 17 00:00:00 2001 From: Letter N <24603524+LetterN@users.noreply.github.com> Date: Thu, 24 Dec 2020 11:06:49 +0800 Subject: [PATCH] Immursive Audio 2 --- code/_onclick/hud/fullscreen.dm | 9 ++ code/_onclick/hud/parallax.dm | 14 +-- code/_onclick/hud/plane_master.dm | 30 +++---- code/_onclick/hud/screen_objects.dm | 63 ++++++++++---- code/controllers/subsystem/fire_burning.dm | 11 ++- code/controllers/subsystem/machines.dm | 6 +- code/controllers/subsystem/minor_mapping.dm | 48 ++++++++--- code/controllers/subsystem/parallax.dm | 2 +- code/datums/cinematic.dm | 26 ++++-- code/datums/components/combat_mode.dm | 4 +- code/datums/components/footstep.dm | 16 ++-- code/datums/components/squeak.dm | 45 ++++++---- code/datums/datum.dm | 32 ++++--- code/datums/diseases/heart_failure.dm | 4 +- code/datums/looping_sounds/_looping_sound.dm | 26 +++--- .../datums/looping_sounds/machinery_sounds.dm | 81 ++++++++++++++++-- code/game/machinery/recycler.dm | 79 +++++++++-------- code/game/objects/items.dm | 50 +++++++---- code/modules/admin/sound_emitter.dm | 16 ++-- code/modules/admin/verbs/playsound.dm | 10 +-- .../antagonists/changeling/changeling.dm | 2 +- .../antagonists/clockcult/clockcult.dm | 2 +- code/modules/antagonists/cult/cult.dm | 2 +- code/modules/antagonists/nukeop/nukeop.dm | 4 +- .../antagonists/traitor/datum_traitor.dm | 2 +- code/modules/mob/living/silicon/ai/ai.dm | 6 +- code/modules/power/supermatter/supermatter.dm | 6 +- code/modules/projectiles/gun.dm | 2 +- sound/machines/grill/grillsizzle.ogg | Bin 0 -> 30763 bytes 29 files changed, 388 insertions(+), 210 deletions(-) create mode 100644 sound/machines/grill/grillsizzle.ogg diff --git a/code/_onclick/hud/fullscreen.dm b/code/_onclick/hud/fullscreen.dm index d82f3e7cf5..076c949f8e 100644 --- a/code/_onclick/hud/fullscreen.dm +++ b/code/_onclick/hud/fullscreen.dm @@ -149,6 +149,15 @@ /obj/screen/fullscreen/color_vision/blue color = "#0000ff" +/obj/screen/fullscreen/cinematic_backdrop + icon = 'icons/mob/screen_gen.dmi' + screen_loc = "WEST,SOUTH to EAST,NORTH" + icon_state = "flash" + plane = SPLASHSCREEN_PLANE + layer = SPLASHSCREEN_LAYER - 1 + color = "#000000" + show_when_dead = TRUE + /obj/screen/fullscreen/lighting_backdrop icon = 'icons/mob/screen_gen.dmi' icon_state = "flash" diff --git a/code/_onclick/hud/parallax.dm b/code/_onclick/hud/parallax.dm index eaa8214b7d..5d48f430d7 100755 --- a/code/_onclick/hud/parallax.dm +++ b/code/_onclick/hud/parallax.dm @@ -10,6 +10,8 @@ C.parallax_layers_cached += new /obj/screen/parallax_layer/layer_1(null, C.view) C.parallax_layers_cached += new /obj/screen/parallax_layer/layer_2(null, C.view) C.parallax_layers_cached += new /obj/screen/parallax_layer/planet(null, C.view) + if(SSparallax.random_layer) + C.parallax_layers_cached += new SSparallax.random_layer C.parallax_layers_cached += new /obj/screen/parallax_layer/layer_3(null, C.view) C.parallax_layers = C.parallax_layers_cached.Copy() @@ -52,12 +54,12 @@ switch(C.prefs.parallax) if (PARALLAX_INSANE) C.parallax_throttle = FALSE - C.parallax_layers_max = 4 + C.parallax_layers_max = 5 return TRUE if (PARALLAX_MED) C.parallax_throttle = PARALLAX_DELAY_MED - C.parallax_layers_max = 2 + C.parallax_layers_max = 3 return TRUE if (PARALLAX_LOW) @@ -68,8 +70,9 @@ if (PARALLAX_DISABLE) return FALSE + //This is high parallax. C.parallax_throttle = PARALLAX_DELAY_DEFAULT - C.parallax_layers_max = 3 + C.parallax_layers_max = 4 return TRUE /datum/hud/proc/update_parallax_pref(mob/viewmob) @@ -219,15 +222,14 @@ L.screen_loc = "CENTER-7:[round(L.offset_x,1)],CENTER-7:[round(L.offset_y,1)]" /atom/movable/proc/update_parallax_contents() - set waitfor = FALSE if(length(client_mobs_in_contents)) for(var/thing in client_mobs_in_contents) var/mob/M = thing - if(M && M.client && M.hud_used && length(M.client.parallax_layers)) + if(M?.client && M.hud_used && length(M.client.parallax_layers)) M.hud_used.update_parallax() /mob/proc/update_parallax_teleport() //used for arrivals shuttle - if(client && client.eye && hud_used && length(client.parallax_layers)) + if(client?.eye && hud_used && length(client.parallax_layers)) var/area/areaobj = get_area(client.eye) hud_used.set_parallax_movedir(areaobj.parallax_movedir, TRUE) diff --git a/code/_onclick/hud/plane_master.dm b/code/_onclick/hud/plane_master.dm index 7a8b0a1121..f5b8991e20 100644 --- a/code/_onclick/hud/plane_master.dm +++ b/code/_onclick/hud/plane_master.dm @@ -28,8 +28,6 @@ . = ..() filters += filter(type="alpha", render_source=FIELD_OF_VISION_RENDER_TARGET, flags=MASK_INVERSE) -/obj/screen/plane_master/openspace/backdrop(mob/mymob) - filters = list() filters += filter(type = "drop_shadow", color = "#04080FAA", size = -10) filters += filter(type = "drop_shadow", color = "#04080FAA", size = -15) filters += filter(type = "drop_shadow", color = "#04080FAA", size = -20) @@ -93,13 +91,6 @@ else remove_filter("ambient_occlusion") -//Reserved to chat messages, so they are still displayed above the field of vision masking. -/obj/screen/plane_master/chat_messages - name = "chat messages plane master" - plane = CHAT_PLANE - appearance_flags = PLANE_MASTER - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - ///Contains all shadow cone masks, whose image overrides are displayed only to their respective owners. /obj/screen/plane_master/field_of_vision name = "field of vision mask plane master" @@ -135,10 +126,14 @@ blend_mode = BLEND_MULTIPLY mouse_opacity = MOUSE_OPACITY_TRANSPARENT +/obj/screen/plane_master/lighting/backdrop(mob/mymob) + mymob.overlay_fullscreen("lighting_backdrop_lit", /obj/screen/fullscreen/lighting_backdrop/lit) + mymob.overlay_fullscreen("lighting_backdrop_unlit", /obj/screen/fullscreen/lighting_backdrop/unlit) + /obj/screen/plane_master/lighting/Initialize() . = ..() - filters += filter(type="alpha", render_source=EMISSIVE_RENDER_TARGET, flags=MASK_INVERSE) - filters += filter(type="alpha", render_source=EMISSIVE_UNBLOCKABLE_RENDER_TARGET, flags=MASK_INVERSE) + filters += filter(type="alpha", render_source = EMISSIVE_RENDER_TARGET, flags = MASK_INVERSE) + filters += filter(type="alpha", render_source = EMISSIVE_UNBLOCKABLE_RENDER_TARGET, flags = MASK_INVERSE) /** * Things placed on this mask the lighting plane. Doesn't render directly. @@ -186,7 +181,6 @@ render_target = EMISSIVE_BLOCKER_RENDER_TARGET ///Contains space parallax - /obj/screen/plane_master/parallax name = "parallax plane master" plane = PLANE_SPACE_PARALLAX @@ -197,12 +191,16 @@ name = "parallax whitifier plane master" plane = PLANE_SPACE -/obj/screen/plane_master/lighting/backdrop(mob/mymob) - mymob.overlay_fullscreen("lighting_backdrop_lit", /obj/screen/fullscreen/lighting_backdrop/lit) - mymob.overlay_fullscreen("lighting_backdrop_unlit", /obj/screen/fullscreen/lighting_backdrop/unlit) - /obj/screen/plane_master/camera_static name = "camera static plane master" plane = CAMERA_STATIC_PLANE appearance_flags = PLANE_MASTER blend_mode = BLEND_OVERLAY + + +//Reserved to chat messages, so they are still displayed above the field of vision masking. +/obj/screen/plane_master/chat_messages + name = "runechat plane master" + plane = CHAT_PLANE + appearance_flags = PLANE_MASTER + blend_mode = BLEND_OVERLAY diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 2ed8c81ba2..53915ff42b 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -12,9 +12,14 @@ layer = HUD_LAYER plane = HUD_PLANE resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF + animate_movement = SLIDE_STEPS + speech_span = SPAN_ROBOT + vis_flags = VIS_INHERIT_PLANE appearance_flags = APPEARANCE_UI - var/obj/master = null //A reference to the object in the slot. Grabs or items, generally. - var/datum/hud/hud = null // A reference to the owner HUD, if any. + /// A reference to the object in the slot. Grabs or items, generally. + var/obj/master = null + /// A reference to the owner HUD, if any. + var/datum/hud/hud = null /** * Map name assigned to this object. * Automatically set by /client/proc/add_obj_to_map. @@ -60,7 +65,17 @@ name = "swap hand" /obj/screen/swap_hand/Click() - usr.swap_hand() + // At this point in client Click() code we have passed the 1/10 sec check and little else + // We don't even know if it's a middle click + // if(world.time <= usr.next_move) + // return 1 + + if(usr.incapacitated()) + return 1 + + if(ismob(usr)) + var/mob/M = usr + M.swap_hand() return 1 /obj/screen/craft @@ -96,17 +111,27 @@ H.open_language_menu(usr) /obj/screen/inventory - var/slot_id // The indentifier for the slot. It has nothing to do with ID cards. - var/icon_empty // Icon when empty. For now used only by humans. - var/icon_full // Icon when contains an item. For now used only by humans. + /// The identifier for the slot. It has nothing to do with ID cards. + var/slot_id + /// Icon when empty. For now used only by humans. + var/icon_empty + /// Icon when contains an item. For now used only by humans. + var/icon_full + /// The overlay when hovering over with an item in your hand var/list/object_overlays = list() layer = HUD_LAYER plane = HUD_PLANE /obj/screen/inventory/Click(location, control, params) - if(hud?.mymob && (hud.mymob != usr)) - return - // just redirect clicks + // At this point in client Click() code we have passed the 1/10 sec check and little else + // We don't even know if it's a middle click + // if(world.time <= usr.next_move) + // return TRUE + + if(usr.incapacitated()) // ignore_stasis = TRUE + return TRUE + if(ismecha(usr.loc)) // stops inventory actions in a mech + return TRUE if(hud?.mymob && slot_id) var/obj/item/inv_item = hud.mymob.get_item_by_slot(slot_id) @@ -150,12 +175,13 @@ var/image/item_overlay = image(holding) item_overlay.alpha = 92 - if(!user.can_equip(holding, slot_id, TRUE, TRUE, TRUE)) + if(!user.can_equip(holding, slot_id, TRUE)) item_overlay.color = "#FF0000" else item_overlay.color = "#00ff00" - object_overlays += item_overlay + cut_overlay(object_overlays) + // object_overlay = item_overlay add_overlay(object_overlays) /obj/screen/inventory/hand @@ -187,10 +213,17 @@ /obj/screen/inventory/hand/Click(location, control, params) - if(hud?.mymob && (hud.mymob != usr)) - return - var/mob/user = hud.mymob - // just redirect clicks + // At this point in client Click() code we have passed the 1/10 sec check and little else + // We don't even know if it's a middle click + var/mob/user = hud?.mymob + if(usr != user) + return TRUE + // if(world.time <= user.next_move) + // return TRUE + if(user.incapacitated()) + return TRUE + if (ismecha(user.loc)) // stops inventory actions in a mech + return TRUE if(user.active_hand_index == held_index) var/obj/item/I = user.get_active_held_item() diff --git a/code/controllers/subsystem/fire_burning.dm b/code/controllers/subsystem/fire_burning.dm index 3251285ade..f81c23d186 100644 --- a/code/controllers/subsystem/fire_burning.dm +++ b/code/controllers/subsystem/fire_burning.dm @@ -18,6 +18,7 @@ SUBSYSTEM_DEF(fire_burning) //cache for sanic speed (lists are references anyways) var/list/currentrun = src.currentrun + var/delta_time = wait * 0.1 while(currentrun.len) var/obj/O = currentrun[currentrun.len] @@ -28,10 +29,12 @@ SUBSYSTEM_DEF(fire_burning) return continue - if(O.resistance_flags & ON_FIRE) - O.take_damage(20, BURN, "fire", 0) - else - processing -= O + + if(O.resistance_flags & ON_FIRE) //in case an object is extinguished while still in currentrun + if(!(O.resistance_flags & FIRE_PROOF)) + O.take_damage(10 * delta_time, BURN, "fire", 0) + else + O.extinguish() if (MC_TICK_CHECK) return diff --git a/code/controllers/subsystem/machines.dm b/code/controllers/subsystem/machines.dm index f356009569..23190574d8 100644 --- a/code/controllers/subsystem/machines.dm +++ b/code/controllers/subsystem/machines.dm @@ -2,6 +2,7 @@ SUBSYSTEM_DEF(machines) name = "Machines" init_order = INIT_ORDER_MACHINES flags = SS_KEEP_TIMING + wait = 2 SECONDS var/list/processing = list() var/list/currentrun = list() var/list/powernets = list() @@ -27,7 +28,7 @@ SUBSYSTEM_DEF(machines) return ..() -/datum/controller/subsystem/machines/fire(resumed = 0) +/datum/controller/subsystem/machines/fire(resumed = FALSE) if (!resumed) for(var/datum/powernet/Powernet in powernets) Powernet.reset() //reset the power state. @@ -36,11 +37,10 @@ SUBSYSTEM_DEF(machines) //cache for sanic speed (lists are references anyways) var/list/currentrun = src.currentrun - var/seconds = wait * 0.1 while(currentrun.len) var/obj/machinery/thing = currentrun[currentrun.len] currentrun.len-- - if(!QDELETED(thing) && thing.process(seconds) != PROCESS_KILL) + if(!QDELETED(thing) && thing.process(wait * 0.1) != PROCESS_KILL) if(thing.use_power) thing.auto_use_power() //add back the power state else diff --git a/code/controllers/subsystem/minor_mapping.dm b/code/controllers/subsystem/minor_mapping.dm index bd950e453e..d6cbf99f97 100644 --- a/code/controllers/subsystem/minor_mapping.dm +++ b/code/controllers/subsystem/minor_mapping.dm @@ -1,3 +1,5 @@ +#define PROB_MOUSE_SPAWN 98 + SUBSYSTEM_DEF(minor_mapping) name = "Minor Mapping" init_order = INIT_ORDER_MINOR_MAPPING @@ -5,29 +7,43 @@ SUBSYSTEM_DEF(minor_mapping) /datum/controller/subsystem/minor_mapping/Initialize(timeofday) trigger_migration(CONFIG_GET(number/mice_roundstart)) + // place_satchels() return ..() /datum/controller/subsystem/minor_mapping/proc/trigger_migration(num_mice=10) var/list/exposed_wires = find_exposed_wires() - var/mob/living/simple_animal/mouse/M + var/mob/living/simple_animal/mouse/mouse var/turf/proposed_turf while((num_mice > 0) && exposed_wires.len) proposed_turf = pick_n_take(exposed_wires) - if(!M) - M = new(proposed_turf) - else - M.forceMove(proposed_turf) - if(M.environment_is_safe()) - num_mice -= 1 - M = null + if(prob(PROB_MOUSE_SPAWN)) + if(!mouse) + mouse = new(proposed_turf) + else + mouse.forceMove(proposed_turf) + // else + // mouse = new /mob/living/simple_animal/hostile/regalrat/controlled(proposed_turf) + if(mouse.environment_is_safe()) + num_mice -= 1 + mouse = null + +// /datum/controller/subsystem/minor_mapping/proc/place_satchels(amount=10) +// var/list/turfs = find_satchel_suitable_turfs() + +// while(turfs.len && amount > 0) +// var/turf/T = pick_n_take(turfs) +// var/obj/item/storage/backpack/satchel/flat/F = new(T) + +// SEND_SIGNAL(F, COMSIG_OBJ_HIDE, T.intact) +// amount-- /proc/find_exposed_wires() var/list/exposed_wires = list() - exposed_wires.Cut() + var/list/all_turfs - for (var/z in SSmapping.levels_by_trait(ZTRAIT_STATION)) + for(var/z in SSmapping.levels_by_trait(ZTRAIT_STATION)) all_turfs += block(locate(1,1,z), locate(world.maxx,world.maxy,z)) for(var/turf/open/floor/plating/T in all_turfs) if(is_blocked_turf(T)) @@ -36,3 +52,15 @@ SUBSYSTEM_DEF(minor_mapping) exposed_wires += T return shuffle(exposed_wires) + +// /proc/find_satchel_suitable_turfs() +// var/list/suitable = list() + +// for(var/z in SSmapping.levels_by_trait(ZTRAIT_STATION)) +// for(var/t in block(locate(1,1,z), locate(world.maxx,world.maxy,z))) +// if(isfloorturf(t) && !isplatingturf(t)) +// suitable += t + +// return shuffle(suitable) + +#undef PROB_MOUSE_SPAWN diff --git a/code/controllers/subsystem/parallax.dm b/code/controllers/subsystem/parallax.dm index 7acb779dcc..7096c667e1 100644 --- a/code/controllers/subsystem/parallax.dm +++ b/code/controllers/subsystem/parallax.dm @@ -16,7 +16,7 @@ SUBSYSTEM_DEF(parallax) . = ..() if(prob(70)) //70% chance to pick a special extra layer random_layer = pick(/obj/screen/parallax_layer/random/space_gas, /obj/screen/parallax_layer/random/asteroids) - random_parallax_color = pick(COLOR_TEAL, COLOR_GREEN, COLOR_SILVER, COLOR_YELLOW, COLOR_CYAN, COLOR_ORANGE, COLOR_PURPLE)//Special color for random_layer1. Has to be done here so everyone sees the same color. + random_parallax_color = pick(COLOR_TEAL, COLOR_GREEN, COLOR_YELLOW, COLOR_CYAN, COLOR_ORANGE, COLOR_PURPLE)//Special color for random_layer1. Has to be done here so everyone sees the same color. [COLOR_SILVER] planet_y_offset = rand(100, 160) planet_x_offset = rand(100, 160) diff --git a/code/datums/cinematic.dm b/code/datums/cinematic.dm index 7b3081cb33..2648ae1eab 100644 --- a/code/datums/cinematic.dm +++ b/code/datums/cinematic.dm @@ -30,7 +30,7 @@ /datum/cinematic var/id = CINEMATIC_DEFAULT var/list/watching = list() //List of clients watching this - var/list/locked = list() //Who had mob_transforming set during the cinematic + var/list/locked = list() //Who had mob_transforming set during the cinematic var/is_global = FALSE //Global cinematics will override mob-specific ones var/obj/screen/cinematic/screen var/datum/callback/special_callback //For special effects synced with animation (explosions after the countdown etc) @@ -45,7 +45,7 @@ if(!CC) continue var/client/C = CC - //C.mob.clear_fullscreen("cinematic") + C.mob.clear_fullscreen("cinematic") C.screen -= screen watching = null QDEL_NULL(screen) @@ -54,7 +54,7 @@ if(!MM) continue var/mob/M = MM - M.mob_transforming = FALSE + M.mob_transforming = FALSE locked = null return ..() @@ -93,7 +93,7 @@ toggle_ooc(TRUE) /datum/cinematic/proc/show_to(mob/M, client/C) - //SIGNAL_HANDLER //must not wait. + SIGNAL_HANDLER if(!M.mob_transforming) locked += M @@ -101,7 +101,7 @@ if(!C) return watching += C - //M.overlay_fullscreen("cinematic",/obj/screen/fullscreen/cinematic_backdrop) + M.overlay_fullscreen("cinematic",/obj/screen/fullscreen/cinematic_backdrop) C.screen += screen //Sound helper @@ -122,7 +122,7 @@ sleep(50) /datum/cinematic/proc/replacement_cinematic(datum/source, datum/cinematic/other) - //SIGNAL_HANDLER + SIGNAL_HANDLER if(!is_global && other.is_global) //Allow it to play if we're local and it's global return NONE @@ -210,6 +210,20 @@ special() screen.icon_state = "summary_cult" +// /datum/cinematic/cult_fail +// id = CINEMATIC_CULT_FAIL + +// /datum/cinematic/cult_fail/content() +// screen.icon_state = "station_intact" +// sleep(20) +// cinematic_sound(sound('sound/creatures/narsie_rises.ogg')) +// sleep(60) +// cinematic_sound(sound('sound/effects/explosion_distant.ogg')) +// sleep(10) +// cinematic_sound(sound('sound/magic/demon_dies.ogg')) +// sleep(30) +// special() + /datum/cinematic/nuke_annihilation id = CINEMATIC_ANNIHILATION diff --git a/code/datums/components/combat_mode.dm b/code/datums/components/combat_mode.dm index b9952e9133..0ffc32542b 100644 --- a/code/datums/components/combat_mode.dm +++ b/code/datums/components/combat_mode.dm @@ -87,7 +87,7 @@ else to_chat(source, self_message) if(playsound) - source.playsound_local(source, 'sound/misc/ui_toggle.ogg', 50, FALSE, pressure_affected = FALSE) //Sound from interbay! + source.playsound_local(source, 'sound/misc/ui_toggle.ogg', 50, FALSE, pressure_affected = FALSE, use_reverb= FALSE) //Sound from interbay! RegisterSignal(source, COMSIG_MOB_CLIENT_MOUSEMOVE, .proc/onMouseMove) RegisterSignal(source, COMSIG_MOVABLE_MOVED, .proc/on_move) RegisterSignal(source, COMSIG_MOB_CLIENT_MOVE, .proc/on_client_move) @@ -114,7 +114,7 @@ else to_chat(source, self_message) if(playsound) - source.playsound_local(source, 'sound/misc/ui_toggleoff.ogg', 50, FALSE, pressure_affected = FALSE) //Slightly modified version of the toggleon sound! + source.playsound_local(source, 'sound/misc/ui_toggleoff.ogg', 50, FALSE, pressure_affected = FALSE, use_reverb= FALSE) //Slightly modified version of the toggleon sound! UnregisterSignal(source, list(COMSIG_MOB_CLIENT_MOUSEMOVE, COMSIG_MOVABLE_MOVED, COMSIG_MOB_CLIENT_MOVE)) if(hud_icon) hud_icon.combat_on = FALSE diff --git a/code/datums/components/footstep.dm b/code/datums/components/footstep.dm index f767c607a5..8b326ac424 100644 --- a/code/datums/components/footstep.dm +++ b/code/datums/components/footstep.dm @@ -46,7 +46,7 @@ var/mob/living/LM = parent if(!T.footstep || LM.buckled || !CHECK_MOBILITY(LM, MOBILITY_STAND) || LM.buckled || LM.throwing || (LM.movement_type & (VENTCRAWLING | FLYING))) if (LM.lying && !LM.buckled && !(!T.footstep || LM.movement_type & (VENTCRAWLING | FLYING))) //play crawling sound if we're lying - playsound(T, 'sound/effects/footstep/crawl1.ogg', 15 * volume) + playsound(T, 'sound/effects/footstep/crawl1.ogg', 15 * volume, falloff_distance = 1) return if(HAS_TRAIT(LM, TRAIT_SILENT_STEP)) @@ -75,7 +75,7 @@ if(!T) return if(isfile(footstep_sounds) || istext(footstep_sounds)) - playsound(T, footstep_sounds, volume) + playsound(T, footstep_sounds, volume, falloff_distance = 1) return var/turf_footstep switch(footstep_type) @@ -89,7 +89,7 @@ turf_footstep = T.footstep if(!turf_footstep) return - playsound(T, pick(footstep_sounds[turf_footstep][1]), footstep_sounds[turf_footstep][2] * volume, TRUE, footstep_sounds[turf_footstep][3] + e_range) + playsound(T, pick(footstep_sounds[turf_footstep][1]), footstep_sounds[turf_footstep][2] * volume, TRUE, footstep_sounds[turf_footstep][3] + e_range, falloff_distance = 1) /datum/component/footstep/proc/play_humanstep() var/turf/open/T = prepare_step() @@ -114,10 +114,10 @@ turf_footstep = T.footstep L = GLOB.footstep if(FOOTSTEP_MOB_SLIME) - playsound(T, 'sound/effects/footstep/slime1.ogg', 50 * volume) + playsound(T, 'sound/effects/footstep/slime1.ogg', 50 * volume, falloff_distance = 1) return if(FOOTSTEP_MOB_CRAWL) - playsound(T, 'sound/effects/footstep/crawl1.ogg', 50 * volume) + playsound(T, 'sound/effects/footstep/crawl1.ogg', 50 * volume, falloff_distance = 1) return special = TRUE else @@ -126,13 +126,13 @@ playsound(T, pick(GLOB.footstep[T.footstep][1]), GLOB.footstep[T.footstep][2] * volume, TRUE, - GLOB.footstep[T.footstep][3] + e_range) + GLOB.footstep[T.footstep][3] + e_range, falloff_distance = 1) return if(!special && H.dna.species.special_step_sounds) - playsound(T, pick(H.dna.species.special_step_sounds), 50, TRUE) + playsound(T, pick(H.dna.species.special_step_sounds), 50, TRUE, falloff_distance = 1) else playsound(T, pick(L[turf_footstep][1]), L[turf_footstep][2] * volume, TRUE, - L[turf_footstep][3] + e_range) + L[turf_footstep][3] + e_range, falloff_distance = 1) diff --git a/code/datums/components/squeak.dm b/code/datums/components/squeak.dm index 0552a791ea..c82a4819c1 100644 --- a/code/datums/components/squeak.dm +++ b/code/datums/components/squeak.dm @@ -19,7 +19,14 @@ /// chance we'll be stopped from squeaking by cooldown when something crossing us squeaks var/cross_squeak_delay_chance = 33 // about 3 things can squeak at a time -/datum/component/squeak/Initialize(custom_sounds, volume_override, chance_override, step_delay_override, use_delay_override) + ///extra-range for this component's sound + var/sound_extra_range = -1 + ///when sounds start falling off for the squeak + var/sound_falloff_distance = SOUND_DEFAULT_FALLOFF_DISTANCE + ///sound exponent for squeak. Defaults to 10 as squeaking is loud and annoying enough. + var/sound_falloff_exponent = 10 + +/datum/component/squeak/Initialize(custom_sounds, volume_override, chance_override, step_delay_override, use_delay_override, extrarange, falloff_exponent, fallof_distance) if(!isatom(parent)) return COMPONENT_INCOMPATIBLE RegisterSignal(parent, list(COMSIG_ATOM_ENTERED, COMSIG_ATOM_BLOB_ACT, COMSIG_ATOM_HULK_ATTACK, COMSIG_PARENT_ATTACKBY), .proc/play_squeak) @@ -45,6 +52,12 @@ step_delay = step_delay_override if(isnum(use_delay_override)) use_delay = use_delay_override + if(isnum(extrarange)) + sound_extra_range = extrarange + if(isnum(falloff_exponent)) + sound_falloff_exponent = falloff_exponent + if(isnum(fallof_distance)) + sound_falloff_distance = fallof_distance /datum/component/squeak/UnregisterFromParent() if(!isatom(parent)) @@ -62,42 +75,42 @@ return ..() /datum/component/squeak/proc/play_squeak() - do_play_squeak() + SIGNAL_HANDLER + -/datum/component/squeak/proc/do_play_squeak(bypass_cooldown = FALSE) - if(!bypass_cooldown && ((last_squeak + squeak_delay) >= world.time)) - return FALSE if(prob(squeak_chance)) if(!override_squeak_sounds) - playsound(parent, pickweight(default_squeak_sounds), volume, 1, -1) + playsound(parent, pickweight(default_squeak_sounds), volume, TRUE, sound_extra_range, sound_falloff_exponent, falloff_distance = sound_falloff_distance) else - playsound(parent, pickweight(override_squeak_sounds), volume, 1, -1) - last_squeak = world.time + playsound(parent, pickweight(override_squeak_sounds), volume, TRUE, sound_extra_range, sound_falloff_exponent, falloff_distance = sound_falloff_distance) return TRUE - return FALSE /datum/component/squeak/proc/step_squeak() + SIGNAL_HANDLER + if(steps > step_delay) - do_play_squeak(TRUE) + play_squeak() steps = 0 else steps++ /datum/component/squeak/proc/play_squeak_crossed(datum/source, atom/movable/AM) + SIGNAL_HANDLER + if(isitem(AM)) var/obj/item/I = AM if(I.item_flags & ABSTRACT) return - else if(istype(AM, /obj/item/projectile)) - var/obj/item/projectile/P = AM - if(P.original != parent) - return + if(AM.movement_type & (FLYING|FLOATING) || !AM.has_gravity()) + return var/atom/current_parent = parent if(isturf(current_parent.loc)) - if(do_play_squeak()) + if(play_squeak()) SEND_SIGNAL(AM, COMSIG_CROSS_SQUEAKED) /datum/component/squeak/proc/use_squeak() + SIGNAL_HANDLER + if(last_use + use_delay < world.time) last_use = world.time play_squeak() @@ -118,6 +131,8 @@ RegisterSignal(holder, COMSIG_ATOM_DIR_CHANGE, .proc/holder_dir_change) /datum/component/squeak/proc/holder_dir_change(datum/source, old_dir, new_dir) + SIGNAL_HANDLER + //If the dir changes it means we're going through a bend in the pipes, let's pretend we bumped the wall if(old_dir != new_dir) play_squeak() diff --git a/code/datums/datum.dm b/code/datums/datum.dm index d11532a883..42580425ce 100644 --- a/code/datums/datum.dm +++ b/code/datums/datum.dm @@ -77,21 +77,21 @@ /** - * Default implementation of clean-up code. - * - * This should be overridden to remove all references pointing to the object being destroyed, if - * you do override it, make sure to call the parent and return it's return value by default - * - * Return an appropriate [QDEL_HINT][QDEL_HINT_QUEUE] to modify handling of your deletion; - * in most cases this is [QDEL_HINT_QUEUE]. - * - * The base case is responsible for doing the following - * * Erasing timers pointing to this datum - * * Erasing compenents on this datum - * * Notifying datums listening to signals from this datum that we are going away - * - * Returns [QDEL_HINT_QUEUE] - */ + * Default implementation of clean-up code. + * + * This should be overridden to remove all references pointing to the object being destroyed, if + * you do override it, make sure to call the parent and return it's return value by default + * + * Return an appropriate [QDEL_HINT][QDEL_HINT_QUEUE] to modify handling of your deletion; + * in most cases this is [QDEL_HINT_QUEUE]. + * + * The base case is responsible for doing the following + * * Erasing timers pointing to this datum + * * Erasing compenents on this datum + * * Notifying datums listening to signals from this datum that we are going away + * + * Returns [QDEL_HINT_QUEUE] + */ /datum/proc/Destroy(force=FALSE, ...) SHOULD_CALL_PARENT(TRUE) tag = null @@ -138,8 +138,6 @@ UnregisterSignal(target, signal_procs[target]) //END: ECS SHIT - SSsounds.free_datum_channels(src) //?? (not on tg) - return QDEL_HINT_QUEUE #ifdef DATUMVAR_DEBUGGING_MODE diff --git a/code/datums/diseases/heart_failure.dm b/code/datums/diseases/heart_failure.dm index aabb9ed144..ddccee3661 100644 --- a/code/datums/diseases/heart_failure.dm +++ b/code/datums/diseases/heart_failure.dm @@ -37,7 +37,7 @@ to_chat(H, "You feel [pick("full", "nauseated", "sweaty", "weak", "tired", "short on breath", "uneasy")].") if(3 to 4) if(!sound) - H.playsound_local(H, 'sound/health/slowbeat.ogg',40,0, channel = CHANNEL_HEARTBEAT) + H.playsound_local(H, 'sound/health/slowbeat.ogg', 40, FALSE, channel = CHANNEL_HEARTBEAT, use_reverb = FALSE) sound = TRUE if(prob(3)) to_chat(H, "You feel a sharp pain in your chest!") @@ -53,7 +53,7 @@ H.emote("cough") if(5) H.stop_sound_channel(CHANNEL_HEARTBEAT) - H.playsound_local(H, 'sound/effects/singlebeat.ogg', 100, 0) + H.playsound_local(H, 'sound/effects/singlebeat.ogg', 100, FALSE, use_reverb = FALSE) if(H.stat == CONSCIOUS) H.visible_message("[H] clutches at [H.p_their()] chest as if [H.p_their()] heart is stopping!") H.adjustStaminaLoss(60) diff --git a/code/datums/looping_sounds/_looping_sound.dm b/code/datums/looping_sounds/_looping_sound.dm index 8bee4f3d1c..6af3b3c993 100644 --- a/code/datums/looping_sounds/_looping_sound.dm +++ b/code/datums/looping_sounds/_looping_sound.dm @@ -18,8 +18,12 @@ var/list/atom/output_atoms var/mid_sounds var/mid_length + ///Override for volume of start sound + var/start_volume var/start_sound var/start_length + ///Override for volume of end sound + var/end_volume var/end_sound var/chance var/volume = 100 @@ -27,10 +31,9 @@ var/max_loops var/direct var/extra_range = 0 - var/falloff - + var/falloff_exponent var/timerid - var/init_timerid + var/falloff_distance /datum/looping_sound/New(list/_output_atoms=list(), start_immediately=FALSE, _direct=FALSE) if(!mid_sounds) @@ -51,16 +54,13 @@ /datum/looping_sound/proc/start(atom/add_thing) if(add_thing) output_atoms |= add_thing - if(timerid || init_timerid) + if(timerid) return on_start() /datum/looping_sound/proc/stop(atom/remove_thing) if(remove_thing) output_atoms -= remove_thing - if(init_timerid) - deltimer(init_timerid) - init_timerid = null if(!timerid) return on_stop() @@ -76,18 +76,18 @@ if(!timerid) timerid = addtimer(CALLBACK(src, .proc/sound_loop, world.time), mid_length, TIMER_CLIENT_TIME | TIMER_STOPPABLE | TIMER_LOOP) -/datum/looping_sound/proc/play(soundfile) +/datum/looping_sound/proc/play(soundfile, volume_override) var/list/atoms_cache = output_atoms var/sound/S = sound(soundfile) if(direct) S.channel = SSsounds.random_available_channel() - S.volume = volume + S.volume = volume_override || volume //Use volume as fallback if theres no override for(var/i in 1 to atoms_cache.len) var/atom/thing = atoms_cache[i] if(direct) SEND_SOUND(thing, S) else - playsound(thing, S, volume, vary, extra_range, falloff) + playsound(thing, S, volume, vary, extra_range, falloff_exponent = falloff_exponent, falloff_distance = falloff_distance) /datum/looping_sound/proc/get_sound(starttime, _mid_sounds) . = _mid_sounds || mid_sounds @@ -97,10 +97,10 @@ /datum/looping_sound/proc/on_start() var/start_wait = 0 if(start_sound) - play(start_sound) + play(start_sound, start_volume) start_wait = start_length - init_timerid = addtimer(CALLBACK(src, .proc/sound_loop), start_wait, TIMER_CLIENT_TIME | TIMER_STOPPABLE) + addtimer(CALLBACK(src, .proc/sound_loop), start_wait, TIMER_CLIENT_TIME) /datum/looping_sound/proc/on_stop() if(end_sound) - play(end_sound) + play(end_sound, end_volume) diff --git a/code/datums/looping_sounds/machinery_sounds.dm b/code/datums/looping_sounds/machinery_sounds.dm index 4f6996bfdd..f7a3b46118 100644 --- a/code/datums/looping_sounds/machinery_sounds.dm +++ b/code/datums/looping_sounds/machinery_sounds.dm @@ -4,7 +4,7 @@ mid_sounds = list('sound/machines/shower/shower_mid1.ogg'=1,'sound/machines/shower/shower_mid2.ogg'=1,'sound/machines/shower/shower_mid3.ogg'=1) mid_length = 10 end_sound = 'sound/machines/shower/shower_end.ogg' - volume = 10 + volume = 20 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -12,6 +12,28 @@ mid_sounds = list('sound/machines/sm/supermatter1.ogg'=1,'sound/machines/sm/supermatter2.ogg'=1,'sound/machines/sm/supermatter3.ogg'=1) mid_length = 10 volume = 1 + extra_range = 25 + falloff_exponent = 10 + falloff_distance = 5 + vary = TRUE + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/datum/looping_sound/destabilized_crystal + mid_sounds = list('sound/machines/sm/loops/delamming.ogg' = 1) + mid_length = 60 + volume = 55 + extra_range = 15 + vary = TRUE + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// /datum/looping_sound/hypertorus +// mid_sounds = list('sound/machines/hypertorus/loops/hypertorus_nominal.ogg' = 1) +// mid_length = 60 +// volume = 55 +// extra_range = 15 +// vary = TRUE /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -32,7 +54,22 @@ mid_sounds = list('sound/machines/fryer/deep_fryer_1.ogg' = 1, 'sound/machines/fryer/deep_fryer_2.ogg' = 1) mid_length = 2 end_sound = 'sound/machines/fryer/deep_fryer_emerge.ogg' - volume = 5 + volume = 15 + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +/datum/looping_sound/grill + mid_sounds = list('sound/machines/grill/grillsizzle.ogg' = 1) + mid_length = 18 + volume = 50 + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/datum/looping_sound/deep_fryer + mid_length = 2 + mid_sounds = list('sound/machines/fryer/deep_fryer_1.ogg' = 1, 'sound/machines/fryer/deep_fryer_2.ogg' = 1) + volume = 30 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -46,9 +83,39 @@ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -/datum/looping_sound/grill - mid_length = 2 - mid_sounds = list('sound/machines/fryer/deep_fryer_1.ogg' = 1, 'sound/machines/fryer/deep_fryer_2.ogg' = 1) - volume = 10 +// /datum/looping_sound/jackpot +// mid_length = 11 +// mid_sounds = list('sound/machines/roulettejackpot.ogg') +// volume = 85 +// vary = TRUE -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* +/datum/looping_sound/server + mid_sounds = list('sound/machines/tcomms/tcomms_mid1.ogg'=1,'sound/machines/tcomms/tcomms_mid2.ogg'=1,'sound/machines/tcomms/tcomms_mid3.ogg'=1,'sound/machines/tcomms/tcomms_mid4.ogg'=1,\ + 'sound/machines/tcomms/tcomms_mid5.ogg'=1,'sound/machines/tcomms/tcomms_mid6.ogg'=1,'sound/machines/tcomms/tcomms_mid7.ogg'=1) + mid_length = 1.8 SECONDS + extra_range = -11 + falloff_distance = 1 + falloff_exponent = 5 + volume = 50 +*/ +// /datum/looping_sound/computer +// start_sound = 'sound/machines/computer/computer_start.ogg' +// start_length = 7.2 SECONDS +// start_volume = 10 +// mid_sounds = list('sound/machines/computer/computer_mid1.ogg'=1, 'sound/machines/computer/computer_mid2.ogg'=1) +// mid_length = 1.8 SECONDS +// end_sound = 'sound/machines/computer/computer_end.ogg' +// end_volume = 10 +// volume = 2 +// falloff_exponent = 5 //Ultra quiet very fast +// extra_range = -12 +// falloff_distance = 1 //Instant falloff after initial tile + +// /datum/looping_sound/gravgen +// mid_sounds = list('sound/machines/gravgen/gravgen_mid1.ogg'=1,'sound/machines/gravgen/gravgen_mid2.ogg'=1,'sound/machines/gravgen/gravgen_mid3.ogg'=1,'sound/machines/gravgen/gravgen_mid4.ogg'=1,) +// mid_length = 1.8 SECONDS +// extra_range = 10 +// volume = 70 +// falloff_distance = 5 +// falloff_exponent = 20 diff --git a/code/game/machinery/recycler.dm b/code/game/machinery/recycler.dm index 706d2bb9bf..2ffd556dc1 100644 --- a/code/game/machinery/recycler.dm +++ b/code/game/machinery/recycler.dm @@ -100,51 +100,54 @@ eat(AM) . = ..() -/obj/machinery/recycler/proc/eat(atom/AM0) - if(stat & (BROKEN|NOPOWER) || safety_mode) +/obj/machinery/recycler/proc/eat(atom/movable/AM0, sound=TRUE) + if(stat & (BROKEN|NOPOWER)) return + if(safety_mode) + return + if(!isturf(AM0.loc)) + return //I don't know how you called Crossed() but stop it. - var/list/to_eat + var/list/to_eat = AM0.GetAllContents() - to_eat = list(AM0) + var/living_detected = FALSE //technically includes silicons as well but eh + var/list/nom = list() + var/list/crunchy_nom = list() //Mobs have to be handled differently so they get a different list instead of checking them multiple times. - var/items_recycled = 0 - var/buzz = FALSE for(var/i in to_eat) var/atom/movable/AM = i - if(QDELETED(AM)) - continue - var/obj/item/bodypart/head/as_head = AM - var/obj/item/mmi/as_mmi = AM - var/brain_holder = istype(AM, /obj/item/organ/brain) || (istype(as_head) && as_head.brain) || (istype(as_mmi) && as_mmi.brain) || istype(AM, /obj/item/dullahan_relay) - if(brain_holder) - if(obj_flags & EMAGGED) - continue - else - emergency_stop(AM) - return + if(istype(AM, /obj/item)) + var/obj/item/bodypart/head/as_head = AM + var/obj/item/mmi/as_mmi = AM + if(istype(AM, /obj/item/organ/brain) || (istype(as_head) && as_head.brain) || (istype(as_mmi) && as_mmi.brain) || istype(AM, /obj/item/dullahan_relay)) + living_detected = TRUE + nom += AM else if(isliving(AM)) - if((obj_flags & EMAGGED)||((!allowed(AM))&&(!ishuman(AM)))) - to_eat += crush_living(AM) - else - emergency_stop(AM) - return - else if(isitem(AM)) - var/obj/O = AM - if(O.resistance_flags & INDESTRUCTIBLE) - buzz = TRUE - O.forceMove(loc) - else - to_eat += recycle_item(AM) - items_recycled++ - else - buzz = TRUE - AM.forceMove(loc) - - if(items_recycled) - playsound(src, item_recycle_sound, 50, 1) - if(buzz) - playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0) + living_detected = TRUE + crunchy_nom += AM + var/not_eaten = to_eat.len - nom.len - crunchy_nom.len + if(living_detected) // First, check if we have any living beings detected. + if(obj_flags & EMAGGED) + for(var/CRUNCH in crunchy_nom) // Eat them and keep going because we don't care about safety. + if(isliving(CRUNCH)) // MMIs and brains will get eaten like normal items + crush_living(CRUNCH) + else // Stop processing right now without eating anything. + emergency_stop() + return + for(var/nommed in nom) + recycle_item(nommed) + if(nom.len && sound) + playsound(src, item_recycle_sound, (50 + nom.len*5), TRUE, nom.len, ignore_walls = (nom.len - 10)) // As a substitute for playing 50 sounds at once. + if(not_eaten) + playsound(src, 'sound/machines/buzz-sigh.ogg', (50 + not_eaten*5), FALSE, not_eaten, ignore_walls = (not_eaten - 10)) // Ditto. + if(!ismob(AM0)) + AM0.moveToNullspace() + qdel(AM0) + else // Lets not move a mob to nullspace and qdel it, yes? + for(var/i in AM0.contents) + var/atom/movable/content = i + content.moveToNullspace() + qdel(content) /obj/machinery/recycler/proc/recycle_item(obj/item/I) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 1c75f1e533..b98054655c 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -11,7 +11,7 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb name = "item" icon = 'icons/obj/items_and_weapons.dmi' blocks_emissive = EMISSIVE_BLOCK_GENERIC - + attack_hand_speed = 0 attack_hand_is_action = FALSE attack_hand_unwieldlyness = 0 @@ -428,18 +428,19 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb /obj/item/proc/talk_into(mob/M, input, channel, spans, datum/language/language) return ITALICS | REDUCE_RANGE -/obj/item/proc/dropped(mob/user) +/// Called when a mob drops an item. +/obj/item/proc/dropped(mob/user, silent = FALSE) SHOULD_CALL_PARENT(TRUE) - current_equipped_slot = null for(var/X in actions) var/datum/action/A = X A.Remove(user) if(item_flags & DROPDEL) qdel(src) item_flags &= ~IN_INVENTORY - if(SEND_SIGNAL(src, COMSIG_ITEM_DROPPED,user) & COMPONENT_DROPPED_RELOCATION) - . = ITEM_RELOCATED_BY_DROPPED - user.update_equipment_speed_mods() + SEND_SIGNAL(src, COMSIG_ITEM_DROPPED,user) + // if(!silent) + // playsound(src, drop_sound, DROP_SOUND_VOLUME, ignore_walls = FALSE) + user?.update_equipment_speed_mods() // called just as an item is picked up (loc is not yet changed) /obj/item/proc/pickup(mob/user) @@ -473,23 +474,32 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb over.MouseDrop_T(src,usr) return -// called after an item is placed in an equipment slot -// user is mob that equipped it -// slot uses the slot_X defines found in setup.dm -// for items that can be placed in multiple slots -// note this isn't called during the initial dressing of a player -/obj/item/proc/equipped(mob/user, slot) +/** + * Called after an item is placed in an equipment slot. + * + * Note that hands count as slots. + * + * Arguments: + * * user is mob that equipped it + * * slot uses the slot_X defines found in setup.dm for items that can be placed in multiple slots + * * Initial is used to indicate whether or not this is the initial equipment (job datums etc) or just a player doing it + */ +/obj/item/proc/equipped(mob/user, slot, initial = FALSE) SHOULD_CALL_PARENT(TRUE) - . = SEND_SIGNAL(src, COMSIG_ITEM_EQUIPPED, user, slot) - current_equipped_slot = slot - if(!(. & COMPONENT_NO_GRANT_ACTIONS)) - for(var/X in actions) - var/datum/action/A = X - if(item_action_slot_check(slot, user, A)) //some items only give their actions buttons when in a specific slot. - A.Grant(user) + SEND_SIGNAL(src, COMSIG_ITEM_EQUIPPED, user, slot) + for(var/X in actions) + var/datum/action/A = X + if(item_action_slot_check(slot, user, A)) //some items only give their actions buttons when in a specific slot. + A.Grant(user) item_flags |= IN_INVENTORY + // if(!initial) + // if(equip_sound && (slot_flags & slot)) + // playsound(src, equip_sound, EQUIP_SOUND_VOLUME, TRUE, ignore_walls = FALSE) + // else if(slot == ITEM_SLOT_HANDS) + // playsound(src, pickup_sound, PICKUP_SOUND_VOLUME, ignore_walls = FALSE) user.update_equipment_speed_mods() + //Overlays for the worn overlay so you can overlay while you overlay //eg: ammo counters, primed grenade flashing, etc. //"icon_file" is used automatically for inhands etc. to make sure it gets the right inhand file @@ -656,6 +666,8 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb else playsound(hit_atom, 'sound/weapons/throwtap.ogg', 1, volume, -1) + // else + // playsound(src, drop_sound, YEET_SOUND_VOLUME, ignore_walls = FALSE) return hit_atom.hitby(src, 0, itempush, throwingdatum=throwingdatum) /obj/item/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, messy_throw = TRUE) diff --git a/code/modules/admin/sound_emitter.dm b/code/modules/admin/sound_emitter.dm index 56c778dc85..ad9c995aa1 100644 --- a/code/modules/admin/sound_emitter.dm +++ b/code/modules/admin/sound_emitter.dm @@ -52,11 +52,9 @@ edit_emitter(user) /obj/effect/sound_emitter/AltClick(mob/user) - . = ..() if(check_rights_for(user.client, R_SOUNDS)) activate(user) - to_chat(user, "Sound emitter activated.") - return TRUE + to_chat(user, "Sound emitter activated.", confidential = TRUE) /obj/effect/sound_emitter/proc/edit_emitter(mob/user) var/dat = "" @@ -84,20 +82,20 @@ if(!new_label) return maptext = new_label - to_chat(user, "Label set to [maptext].") + to_chat(user, "Label set to [maptext].", confidential = TRUE) if(href_list["edit_sound_file"]) var/new_file = input(user, "Choose a sound file.", "Sound Emitter") as null|sound if(!new_file) return sound_file = new_file - to_chat(user, "New sound file set to [sound_file].") + to_chat(user, "New sound file set to [sound_file].", confidential = TRUE) if(href_list["edit_volume"]) var/new_volume = input(user, "Choose a volume.", "Sound Emitter", sound_volume) as null|num if(isnull(new_volume)) return new_volume = clamp(new_volume, 0, 100) sound_volume = new_volume - to_chat(user, "Volume set to [sound_volume]%.") + to_chat(user, "Volume set to [sound_volume]%.", confidential = TRUE) if(href_list["edit_mode"]) var/new_mode var/mode_list = list("Local (normal sound)" = SOUND_EMITTER_LOCAL, "Direct (not affected by environment/location)" = SOUND_EMITTER_DIRECT) @@ -105,7 +103,7 @@ if(!new_mode) return motus_operandi = mode_list[new_mode] - to_chat(user, "Mode set to [motus_operandi].") + to_chat(user, "Mode set to [motus_operandi].", confidential = TRUE) if(href_list["edit_range"]) var/new_range var/range_list = list("Radius (all mobs within a radius)" = SOUND_EMITTER_RADIUS, "Z-Level (all mobs on the same z)" = SOUND_EMITTER_ZLEVEL, "Global (all players)" = SOUND_EMITTER_GLOBAL) @@ -113,14 +111,14 @@ if(!new_range) return emitter_range = range_list[new_range] - to_chat(user, "Range set to [emitter_range].") + to_chat(user, "Range set to [emitter_range].", confidential = TRUE) if(href_list["edit_radius"]) var/new_radius = input(user, "Choose a radius.", "Sound Emitter", sound_volume) as null|num if(isnull(new_radius)) return new_radius = clamp(new_radius, 0, 127) play_radius = new_radius - to_chat(user, "Audible radius set to [play_radius].") + to_chat(user, "Audible radius set to [play_radius].", confidential = TRUE) if(href_list["play"]) activate(user) edit_emitter(user) //Refresh the UI to see our changes diff --git a/code/modules/admin/verbs/playsound.dm b/code/modules/admin/verbs/playsound.dm index 6e188a6c7a..c9a5cafd9b 100644 --- a/code/modules/admin/verbs/playsound.dm +++ b/code/modules/admin/verbs/playsound.dm @@ -4,12 +4,10 @@ if(!check_rights(R_SOUNDS)) return + var/freq = 1 var/vol = input(usr, "What volume would you like the sound to play at?",, 100) as null|num if(!vol) return - var/freq = input(usr, "What frequency would you like the sound to play at?",, 1) as null|num - if(!freq) - freq = 1 vol = clamp(vol, 1, 100) var/sound/admin_sound = new() @@ -18,14 +16,14 @@ admin_sound.channel = CHANNEL_ADMIN admin_sound.frequency = freq admin_sound.wait = 1 - admin_sound.repeat = 0 + admin_sound.repeat = FALSE admin_sound.status = SOUND_STREAM admin_sound.volume = vol var/res = alert(usr, "Show the title of this song to the players?",, "Yes","No", "Cancel") switch(res) if("Yes") - to_chat(world, "An admin played: [S]") + to_chat(world, "An admin played: [S]", confidential = TRUE) if("Cancel") return @@ -49,7 +47,7 @@ log_admin("[key_name(src)] played a local sound [S]") message_admins("[key_name_admin(src)] played a local sound [S]") - playsound(get_turf(src.mob), S, 50, 0, 0) + playsound(get_turf(src.mob), S, 50, FALSE, FALSE) SSblackbox.record_feedback("tally", "admin_verb", 1, "Play Local Sound") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! /client/proc/play_web_sound() diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm index 7a34af4d13..28ec6c016e 100644 --- a/code/modules/antagonists/changeling/changeling.dm +++ b/code/modules/antagonists/changeling/changeling.dm @@ -358,7 +358,7 @@ to_chat(owner.current, "You are [changelingID], a changeling! You have absorbed and taken the form of a human.") to_chat(owner.current, "Use say \"[MODE_TOKEN_CHANGELING] message\" to communicate with your fellow changelings.") to_chat(owner.current, "You must complete the following tasks:") - owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ling_aler.ogg', 100, FALSE, pressure_affected = FALSE) + owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ling_aler.ogg', 100, FALSE, pressure_affected = FALSE, use_reverb = FALSE) owner.announce_objectives() diff --git a/code/modules/antagonists/clockcult/clockcult.dm b/code/modules/antagonists/clockcult/clockcult.dm index b6ed7dfe65..0c25e28870 100644 --- a/code/modules/antagonists/clockcult/clockcult.dm +++ b/code/modules/antagonists/clockcult/clockcult.dm @@ -60,7 +60,7 @@ owner.current.visible_message("[owner.current]'s eyes glow a blazing yellow!", null, null, 7, owner.current) //don't show the owner this message to_chat(owner.current, "Assist your new companions in their righteous efforts. Your goal is theirs, and theirs yours. You serve the Clockwork \ Justiciar above all else. Perform his every whim without hesitation.") - owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/clockcultalr.ogg', 70, FALSE, pressure_affected = FALSE) + owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/clockcultalr.ogg', 70, FALSE, pressure_affected = FALSE, use_reverb = FALSE) /datum/antagonist/clockcult/on_gain() var/mob/living/current = owner.current diff --git a/code/modules/antagonists/cult/cult.dm b/code/modules/antagonists/cult/cult.dm index a2ec4a47a4..2e8962178c 100644 --- a/code/modules/antagonists/cult/cult.dm +++ b/code/modules/antagonists/cult/cult.dm @@ -61,7 +61,7 @@ /datum/antagonist/cult/greet() to_chat(owner, "You are a member of the cult!") - owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/bloodcult.ogg', 100, FALSE, pressure_affected = FALSE)//subject to change + owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/bloodcult.ogg', 100, FALSE, pressure_affected = FALSE, use_reverb = FALSE)//subject to change owner.announce_objectives() /datum/antagonist/cult/on_gain() diff --git a/code/modules/antagonists/nukeop/nukeop.dm b/code/modules/antagonists/nukeop/nukeop.dm index 652b19a8e7..c618edf862 100644 --- a/code/modules/antagonists/nukeop/nukeop.dm +++ b/code/modules/antagonists/nukeop/nukeop.dm @@ -43,7 +43,7 @@ return TRUE /datum/antagonist/nukeop/greet() - owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ops.ogg',100,0) + owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ops.ogg',100,0, use_reverb = FALSE) to_chat(owner, "You are a [nuke_team ? nuke_team.syndicate_name : "syndicate"] agent!") owner.announce_objectives() @@ -171,7 +171,7 @@ owner.current.real_name = "Syndicate [title]" /datum/antagonist/nukeop/leader/greet() - owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ops.ogg',100,0) + owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ops.ogg',100,0, use_reverb = FALSE) to_chat(owner, "You are the Syndicate [title] for this mission. You are responsible for the distribution of telecrystals and your ID is the only one who can open the launch bay doors.") to_chat(owner, "If you feel you are not up to this task, give your ID to another operative.") to_chat(owner, "In your hand you will find a special item capable of triggering a greater challenge for your team. Examine it carefully and consult with your fellow operatives before activating it.") diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm index 47a9c59274..fa0876c324 100644 --- a/code/modules/antagonists/traitor/datum_traitor.dm +++ b/code/modules/antagonists/traitor/datum_traitor.dm @@ -114,7 +114,7 @@ if(traitor_kind.finalize_traitor(src)) if(should_equip) equip(silent) - owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/tatoralert.ogg', 100, FALSE, pressure_affected = FALSE) + owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/tatoralert.ogg', 100, FALSE, pressure_affected = FALSE, use_reverb = FALSE) /datum/antagonist/traitor/antag_panel_objectives() . += "Traitor class: [traitor_kind.employer]
" diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index fbf2d27c31..823f759e67 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -911,10 +911,10 @@ if(!istype(apc) || QDELETED(apc) || apc.stat & BROKEN) to_chat(src, "Hack aborted. The designated APC no longer exists on the power network.") - playsound(get_turf(src), 'sound/machines/buzz-two.ogg', 50, 1) + playsound(get_turf(src), 'sound/machines/buzz-two.ogg', 50, TRUE, ignore_walls = FALSE) else if(apc.aidisabled) to_chat(src, "Hack aborted. \The [apc] is no longer responding to our systems.") - playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 50, 1) + playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 50, TRUE, ignore_walls = FALSE) else malf_picker.processing_time += 10 @@ -923,7 +923,7 @@ apc.locked = TRUE apc.coverlocked = TRUE - playsound(get_turf(src), 'sound/machines/ding.ogg', 50, 1) + playsound(get_turf(src), 'sound/machines/ding.ogg', 50, TRUE, ignore_walls = FALSE) to_chat(src, "Hack complete. \The [apc] is now under your exclusive control.") apc.update_icon() diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm index f385b640aa..1e82a601ea 100644 --- a/code/modules/power/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -348,11 +348,11 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) /obj/machinery/power/supermatter_crystal/proc/alarm() switch(get_status()) if(SUPERMATTER_DELAMINATING) - playsound(src, 'sound/misc/bloblarm.ogg', 100) + playsound(src, 'sound/misc/bloblarm.ogg', 100, FALSE, 40, 30, falloff_distance = 10) if(SUPERMATTER_EMERGENCY) - playsound(src, 'sound/machines/engine_alert1.ogg', 100) + playsound(src, 'sound/machines/engine_alert1.ogg', 100, FALSE, 30, 30, falloff_distance = 10) if(SUPERMATTER_DANGER) - playsound(src, 'sound/machines/engine_alert2.ogg', 100) + playsound(src, 'sound/machines/engine_alert2.ogg', 100, FALSE, 30, 30, falloff_distance = 10) if(SUPERMATTER_WARNING) playsound(src, 'sound/machines/terminal_alert.ogg', 75) diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 1c3a0d230f..22f6ed4572 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -158,7 +158,7 @@ user.UseStaminaBuffer(safe_cost) if(suppressed) - playsound(user, fire_sound, 10, 1) + playsound(user, fire_sound, 10, TRUE, ignore_walls = FALSE, extrarange = SILENCED_SOUND_EXTRARANGE, falloff_distance = 0) else playsound(user, fire_sound, 50, 1) if(message) diff --git a/sound/machines/grill/grillsizzle.ogg b/sound/machines/grill/grillsizzle.ogg new file mode 100644 index 0000000000000000000000000000000000000000..056ce45941c413c848322b316bba91df8bfd134b GIT binary patch literal 30763 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 literal 0 HcmV?d00001