diff --git a/code/__DEFINES/sound.dm b/code/__DEFINES/sound.dm
index 333efc90e0b..c3f7780b917 100644
--- a/code/__DEFINES/sound.dm
+++ b/code/__DEFINES/sound.dm
@@ -6,11 +6,14 @@
#define CHANNEL_HEARTBEAT 1020 //sound channel for heartbeats
#define CHANNEL_BUZZ 1019
#define CHANNEL_AMBIENCE 1018
+#define CHANNEL_ENGINE 1017 // Engine ambient sounds
+
+#define USER_VOLUME(M, C) M?.client?.prefs.get_channel_volume(C)
//THIS SHOULD ALWAYS BE THE LOWEST ONE!
//KEEP IT UPDATED
-#define CHANNEL_HIGHEST_AVAILABLE 1017
+#define CHANNEL_HIGHEST_AVAILABLE 1016
#define MAX_INSTRUMENT_CHANNELS (128 * 6)
diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm
index ee1530df81b..282ad53cd06 100644
--- a/code/__HELPERS/global_lists.dm
+++ b/code/__HELPERS/global_lists.dm
@@ -84,13 +84,13 @@
continue
if(!use_name)
- error("Loadout - Missing display name: [G]")
+ stack_trace("Loadout - Missing display name: [G]")
continue
if(!initial(G.cost))
- error("Loadout - Missing cost: [G]")
+ stack_trace("Loadout - Missing cost: [G]")
continue
if(!initial(G.path))
- error("Loadout - Missing path definition: [G]")
+ stack_trace("Loadout - Missing path definition: [G]")
continue
if(!GLOB.loadout_categories[use_category])
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index 35388b7b824..3056485d755 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -2116,6 +2116,8 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
return "White Noise"
if(CHANNEL_AMBIENCE)
return "Ambience"
+ if(CHANNEL_ENGINE)
+ return "Engine Ambience"
/proc/slot_bitfield_to_slot(input_slot_flags) // Kill off this garbage ASAP; slot flags and clothing flags should be IDENTICAL. GOSH DARN IT. Doesn't work with ears or pockets, either.
switch(input_slot_flags)
diff --git a/code/datums/looping_sounds/looping_sound.dm b/code/datums/looping_sounds/looping_sound.dm
index 5e019439bc4..33fb5595c24 100644
--- a/code/datums/looping_sounds/looping_sound.dm
+++ b/code/datums/looping_sounds/looping_sound.dm
@@ -31,6 +31,8 @@
var/falloff_exponent
var/muted = TRUE
var/falloff_distance
+ /// Channel of the audio, random otherwise
+ var/channel
/datum/looping_sound/New(list/_output_atoms = list(), start_immediately = FALSE, _direct = FALSE)
if(!mid_sounds)
@@ -75,14 +77,16 @@
var/list/atoms_cache = output_atoms
var/sound/S = sound(soundfile)
if(direct)
- S.channel = SSsounds.random_available_channel()
- S.volume = volume
+ S.channel = channel || SSsounds.random_available_channel()
for(var/i in 1 to atoms_cache.len)
var/atom/thing = atoms_cache[i]
if(direct)
+ if(ismob(thing))
+ var/mob/M = thing
+ S.volume = volume * (USER_VOLUME(M, channel) || 1)
SEND_SOUND(thing, S)
else
- playsound(thing, S, volume, vary, extra_range, falloff_exponent = falloff_exponent, falloff_distance = falloff_distance)
+ playsound(thing, S, volume, vary, extra_range, falloff_exponent = falloff_exponent, falloff_distance = falloff_distance, channel = channel)
/datum/looping_sound/proc/get_sound(looped, _mid_sounds)
if(!_mid_sounds)
diff --git a/code/datums/looping_sounds/machinery_sounds.dm b/code/datums/looping_sounds/machinery_sounds.dm
index 280aa5fab60..432e2709335 100644
--- a/code/datums/looping_sounds/machinery_sounds.dm
+++ b/code/datums/looping_sounds/machinery_sounds.dm
@@ -16,3 +16,4 @@
falloff_exponent = 10
falloff_distance = 5
vary = TRUE
+ channel = CHANNEL_ENGINE
diff --git a/code/game/gamemodes/miniantags/guardian/guardian.dm b/code/game/gamemodes/miniantags/guardian/guardian.dm
index b0194c53f33..c2a72b12b1e 100644
--- a/code/game/gamemodes/miniantags/guardian/guardian.dm
+++ b/code/game/gamemodes/miniantags/guardian/guardian.dm
@@ -250,10 +250,9 @@
var/name_list = list("Aries", "Leo", "Sagittarius", "Taurus", "Virgo", "Capricorn", "Gemini", "Libra", "Aquarius", "Cancer", "Scorpio", "Pisces")
/obj/item/guardiancreator/attack_self(mob/living/user)
- for(var/mob/living/simple_animal/hostile/guardian/G in GLOB.alive_mob_list)
- if(G.summoner == user)
- to_chat(user, "You already have a [mob_name]!")
- return
+ if(has_guardian(user))
+ to_chat(user, "You already have a [mob_name]!")
+ return
if(user.mind && (user.mind.changeling || user.mind.vampire))
to_chat(user, "[ling_failure]")
return
@@ -285,6 +284,10 @@
if(candidates.len)
theghost = pick(candidates)
+ if(has_guardian(user))
+ to_chat(user, "You already have a [mob_name]!")
+ used = FALSE
+ return
spawn_guardian(user, theghost.key, guardian_type)
else
to_chat(user, "[failure_message]")
@@ -295,6 +298,13 @@
if(used)
. += "[used_message]"
+/obj/item/guardiancreator/proc/has_guardian(mob/living/user)
+ for(var/mob/living/simple_animal/hostile/guardian/G in GLOB.alive_mob_list)
+ if(G.summoner == user)
+ return TRUE
+ return FALSE
+
+
/obj/item/guardiancreator/proc/spawn_guardian(mob/living/user, key, guardian_type)
var/pickedtype = /mob/living/simple_animal/hostile/guardian/punch
switch(guardian_type)
diff --git a/code/game/machinery/tcomms/nttc.dm b/code/game/machinery/tcomms/nttc.dm
index d6534690b0b..0576bbe7e41 100644
--- a/code/game/machinery/tcomms/nttc.dm
+++ b/code/game/machinery/tcomms/nttc.dm
@@ -279,9 +279,14 @@
if(toggle_command_bold)
var/job = tcm.sender_job
if((job in ert_jobs) || (job in heads) || (job in cc_jobs))
- for(var/datum/multilingual_say_piece/S in message_pieces)
- if(S.message)
- S.message = "[capitalize(S.message)]" // This only capitalizes the first word
+ for(var/I in 1 to length(message_pieces))
+ var/datum/multilingual_say_piece/S = message_pieces[I]
+ if(!S.message)
+ continue
+ if(I == 1 && !istype(S.speaking, /datum/language/noise)) // Capitalise the first section only, unless it's an emote.
+ S.message = "[capitalize(S.message)]"
+ S.message = "[S.message]" // Make everything bolded
+
// Language Conversion
if(setting_language && valid_languages[setting_language])
diff --git a/code/game/objects/effects/landmarks.dm b/code/game/objects/effects/landmarks.dm
index 0f373bfe851..4a00dfda86d 100644
--- a/code/game/objects/effects/landmarks.dm
+++ b/code/game/objects/effects/landmarks.dm
@@ -164,10 +164,9 @@
new /obj/item/clothing/shoes/jackboots(src.loc)
qdel(src)
-/obj/effect/landmark/costume/nyangirl/New()
+/obj/effect/landmark/costume/schoolgirl/New()
. = ..()
new /obj/item/clothing/under/schoolgirl(src.loc)
- new /obj/item/clothing/head/kitty(src.loc)
qdel(src)
/obj/effect/landmark/costume/maid/New()
diff --git a/code/game/objects/items/weapons/twohanded.dm b/code/game/objects/items/weapons/twohanded.dm
index b267b51d7d9..a7ac1d632c7 100644
--- a/code/game/objects/items/weapons/twohanded.dm
+++ b/code/game/objects/items/weapons/twohanded.dm
@@ -638,7 +638,7 @@
/obj/item/twohanded/singularityhammer
name = "singularity hammer"
desc = "The pinnacle of close combat technology, the hammer harnesses the power of a miniaturized singularity to deal crushing blows."
- icon_state = "mjollnir0"
+ icon_state = "singulohammer0"
flags = CONDUCT
slot_flags = SLOT_BACK
force = 5
@@ -665,7 +665,7 @@
charged++
/obj/item/twohanded/singularityhammer/update_icon() //Currently only here to fuck with the on-mob icons.
- icon_state = "mjollnir[wielded]"
+ icon_state = "singulohammer[wielded]"
..()
/obj/item/twohanded/singularityhammer/proc/vortex(turf/pull, mob/wielder)
diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm
index d287c2f5bbf..5bce42875fe 100644
--- a/code/game/objects/structures/tables_racks.dm
+++ b/code/game/objects/structures/tables_racks.dm
@@ -591,7 +591,7 @@
verbs -= /obj/structure/table/verb/do_flip
typecache_can_hold = typecacheof(typecache_can_hold)
for(var/atom/movable/held in get_turf(src))
- if(is_type_in_typecache(held, typecache_can_hold))
+ if(!held.anchored && held.move_resist != INFINITY && is_type_in_typecache(held, typecache_can_hold))
held_items += held.UID()
/obj/structure/table/tray/Move(NewLoc, direct)
diff --git a/code/modules/client/preference/loadout/loadout_uniform.dm b/code/modules/client/preference/loadout/loadout_uniform.dm
index 2911e64e87c..e188431f719 100644
--- a/code/modules/client/preference/loadout/loadout_uniform.dm
+++ b/code/modules/client/preference/loadout/loadout_uniform.dm
@@ -4,7 +4,7 @@
slot = slot_w_uniform
sort_category = "Uniforms and Casual Dress"
-/datum/gear/uniform/suits
+/datum/gear/uniform/suit
subtype_path = /datum/gear/uniform/suit
//there's a lot more colors than I thought there were @_@
diff --git a/code/modules/client/preference/preferences.dm b/code/modules/client/preference/preferences.dm
index 7c45d7ce88a..5a838c3ac9a 100644
--- a/code/modules/client/preference/preferences.dm
+++ b/code/modules/client/preference/preferences.dm
@@ -192,6 +192,7 @@ GLOBAL_LIST_INIT(special_role_times, list( //minimum age (in days) for accounts
"1020" = 100, // CHANNEL_HEARTBEAT
"1019" = 100, // CHANNEL_BUZZ
"1018" = 100, // CHANNEL_AMBIENCE
+ "1017" = 100, // CHANNEL_ENGINE
)
/// The volume mixer save timer handle. Used to debounce the DB call to save, to avoid spamming.
var/volume_mixer_saving = null
diff --git a/code/modules/hydroponics/grown/onion.dm b/code/modules/hydroponics/grown/onion.dm
index cff3fcafdba..8594c6f37ea 100644
--- a/code/modules/hydroponics/grown/onion.dm
+++ b/code/modules/hydroponics/grown/onion.dm
@@ -37,6 +37,7 @@
plantname = "Red Onion Sprouts"
weed_chance = 1
product = /obj/item/reagent_containers/food/snacks/grown/onion/red
+ mutatelist = list()
reagents_add = list("vitamin" = 0.04, "plantmatter" = 0.1, "onionjuice" = 0.05)
/obj/item/reagent_containers/food/snacks/grown/onion/red
diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm
index 5d505554c84..0cc682eae32 100644
--- a/code/modules/power/supermatter/supermatter.dm
+++ b/code/modules/power/supermatter/supermatter.dm
@@ -377,9 +377,9 @@
if(last_accent_sound < world.time && prob(20))
var/aggression = min(((damage / 800) * (power / 2500)), 1.0) * 100
if(damage >= 300)
- playsound(src, "smdelam", max(50, aggression), FALSE, 40, 30, falloff_distance = 10)
+ playsound(src, "smdelam", max(50, aggression), FALSE, 40, 30, falloff_distance = 10, channel = CHANNEL_ENGINE)
else
- playsound(src, "smcalm", max(50, aggression), FALSE, 25, 25, falloff_distance = 10)
+ playsound(src, "smcalm", max(50, aggression), FALSE, 25, 25, falloff_distance = 10, channel = CHANNEL_ENGINE)
var/next_sound = round((100 - aggression) * 5)
last_accent_sound = world.time + max(SUPERMATTER_ACCENT_SOUND_MIN_COOLDOWN, next_sound)
@@ -568,7 +568,7 @@
zap_count += 1
if(zap_count >= 1)
- playsound(src.loc, 'sound/weapons/emitter2.ogg', 100, TRUE, extrarange = 10)
+ playsound(src.loc, 'sound/weapons/emitter2.ogg', 100, TRUE, extrarange = 10, channel = CHANNEL_ENGINE)
for(var/i in 1 to zap_count)
supermatter_zap(src, range, clamp(power*2, 4000, 20000), flags)
@@ -807,7 +807,7 @@
icon_state = "darkmatter"
/obj/machinery/power/supermatter_crystal/proc/supermatter_pull(turf/center, pull_range = 3)
- playsound(center, 'sound/weapons/marauder.ogg', 100, TRUE, extrarange = pull_range - world.view)
+ playsound(center, 'sound/weapons/marauder.ogg', 100, TRUE, extrarange = pull_range - world.view, channel = CHANNEL_ENGINE)
for(var/atom/movable/P in orange(pull_range,center))
if((P.anchored || P.move_resist >= MOVE_FORCE_EXTREMELY_STRONG)) //move resist memes.
if(istype(P, /obj/structure/closet))
diff --git a/code/modules/power/tesla/energy_ball.dm b/code/modules/power/tesla/energy_ball.dm
index a840c583128..02eaa84183e 100644
--- a/code/modules/power/tesla/energy_ball.dm
+++ b/code/modules/power/tesla/energy_ball.dm
@@ -65,7 +65,7 @@
move_the_basket_ball(4 + length(orbiting_balls) * 1.5)
- playsound(loc, 'sound/magic/lightningbolt.ogg', 100, TRUE, extrarange = 30)
+ playsound(loc, 'sound/magic/lightningbolt.ogg', 100, TRUE, extrarange = 30, channel = CHANNEL_ENGINE)
pixel_x = 0
pixel_y = 0
@@ -112,7 +112,7 @@
energy_to_lower = energy_to_raise - 20
energy_to_raise = energy_to_raise * 1.25
- playsound(src.loc, 'sound/magic/lightning_chargeup.ogg', 100, TRUE, extrarange = 30)
+ playsound(src.loc, 'sound/magic/lightning_chargeup.ogg', 100, TRUE, extrarange = 30, channel = CHANNEL_ENGINE)
addtimer(CALLBACK(src, .proc/new_mini_ball), 100)
else if(energy < energy_to_lower && length(orbiting_balls))
diff --git a/icons/mob/inhands/items_lefthand.dmi b/icons/mob/inhands/items_lefthand.dmi
index b2db69f2703..0564a4b7c7b 100644
Binary files a/icons/mob/inhands/items_lefthand.dmi and b/icons/mob/inhands/items_lefthand.dmi differ
diff --git a/icons/mob/inhands/items_righthand.dmi b/icons/mob/inhands/items_righthand.dmi
index 94b06f7c3d6..f9c0a0d13a8 100644
Binary files a/icons/mob/inhands/items_righthand.dmi and b/icons/mob/inhands/items_righthand.dmi differ
diff --git a/icons/obj/drinks.dmi b/icons/obj/drinks.dmi
index 74f0f92a37d..6d30e966c31 100644
Binary files a/icons/obj/drinks.dmi and b/icons/obj/drinks.dmi differ
diff --git a/icons/obj/items.dmi b/icons/obj/items.dmi
index 73dd8193e1a..23c3dcd676c 100644
Binary files a/icons/obj/items.dmi and b/icons/obj/items.dmi differ