diff --git a/code/datums/ghost_query.dm b/code/datums/ghost_query.dm
index 26a7427c83..d068e27de2 100644
--- a/code/datums/ghost_query.dm
+++ b/code/datums/ghost_query.dm
@@ -5,6 +5,7 @@
var/finished = FALSE
var/role_name = "a thing"
var/question = "Would you like to play as a thing?"
+ var/query_sound = 'sound/effects/ghost2.ogg' // A sound file to play to the ghost, to help people who are alt-tabbed know something might interest them.
var/be_special_flag = 0
var/list/check_bans = list()
var/wait_time = 60 SECONDS // How long to wait until returning the list of candidates.
@@ -42,6 +43,9 @@
spawn(0)
if(!C)
return
+ window_flash(C)
+ if(query_sound)
+ SEND_SOUND(C, sound(query_sound))
var/response = alert(C, question, "[role_name] request", "Yes", "No", "Never for this round")
if(response == "Yes")
response = alert(C, "Are you sure you want to play as a [role_name]?", "[role_name] request", "Yes", "No") // Protection from a misclick.
@@ -62,12 +66,14 @@
/datum/ghost_query/promethean
role_name = "Promethean"
question = "Someone is requesting a soul for a promethean. Would you like to play as one?"
+ query_sound = 'sound/effects/slime_squish.ogg'
be_special_flag = BE_ALIEN
cutoff_number = 1
/datum/ghost_query/posi_brain
role_name = "Positronic Intelligence"
question = "Someone has activated a Positronic Brain. Would you like to play as one?"
+ query_sound = 'sound/machines/boobeebeep.ogg'
be_special_flag = BE_AI
check_bans = list("AI", "Cyborg")
cutoff_number = 1
@@ -75,6 +81,7 @@
/datum/ghost_query/drone_brain
role_name = "Drone Intelligence"
question = "Someone has activated a Drone AI Chipset. Would you like to play as one?"
+ query_sound = 'sound/machines/boobeebeep.ogg'
be_special_flag = BE_AI
check_bans = list("AI", "Cyborg")
cutoff_number = 1
@@ -90,6 +97,7 @@
/datum/ghost_query/xeno
role_name = "Alien"
question = "An Alien has just been created on the facility. Would you like to play as them?"
+ query_sound = 'sound/voice/hiss5.ogg'
be_special_flag = BE_ALIEN
/datum/ghost_query/blob
diff --git a/code/game/antagonist/antagonist.dm b/code/game/antagonist/antagonist.dm
index 2de7f72124..962c91a621 100644
--- a/code/game/antagonist/antagonist.dm
+++ b/code/game/antagonist/antagonist.dm
@@ -7,6 +7,7 @@
// Strings.
var/welcome_text = "Cry havoc and let slip the dogs of war!"
+ var/antag_sound = 'sound/effects/antag_notice/general_baddie_alert.ogg' // The sound file to play when someone gets this role. Only they can hear it.
var/leader_welcome_text // Text shown to the leader, if any.
var/victory_text // World output at roundend for victory.
var/loss_text // As above for loss.
diff --git a/code/game/antagonist/antagonist_create.dm b/code/game/antagonist/antagonist_create.dm
index 07046401c3..84c5b2317e 100644
--- a/code/game/antagonist/antagonist_create.dm
+++ b/code/game/antagonist/antagonist_create.dm
@@ -95,6 +95,10 @@
return code
/datum/antagonist/proc/greet(var/datum/mind/player)
+ // Makes it harder to miss if you're alt-tabbed or not paying attention.
+ if(antag_sound)
+ SEND_SOUND(player.current, sound(antag_sound))
+ window_flash(player.current.client)
// Basic intro text.
to_chat(player.current, "You are a [role_text]!")
diff --git a/code/game/antagonist/outsider/commando.dm b/code/game/antagonist/outsider/commando.dm
index 3ea5c233ff..b7bd756c97 100644
--- a/code/game/antagonist/outsider/commando.dm
+++ b/code/game/antagonist/outsider/commando.dm
@@ -6,6 +6,7 @@ var/datum/antagonist/deathsquad/mercenary/commandos
role_text = "Syndicate Commando"
role_text_plural = "Commandos"
welcome_text = "You are in the employ of a criminal syndicate hostile to corporate interests."
+ antag_sound = 'sound/effects/antag_notice/deathsquid_alert.ogg'
id_type = /obj/item/weapon/card/id/centcom/ERT
hard_cap = 4
diff --git a/code/game/antagonist/outsider/deathsquad.dm b/code/game/antagonist/outsider/deathsquad.dm
index db281b6dbb..01b579b7de 100644
--- a/code/game/antagonist/outsider/deathsquad.dm
+++ b/code/game/antagonist/outsider/deathsquad.dm
@@ -6,6 +6,7 @@ var/datum/antagonist/deathsquad/deathsquad
role_text = "Death Commando"
role_text_plural = "Death Commandos"
welcome_text = "You work in the service of corporate Asset Protection, answering directly to the Board of Directors."
+ antag_sound = 'sound/effects/antag_notice/deathsquid_alert.ogg'
landmark_id = "Commando"
flags = ANTAG_OVERRIDE_JOB | ANTAG_OVERRIDE_MOB | ANTAG_HAS_NUKE | ANTAG_HAS_LEADER
default_access = list(access_cent_general, access_cent_specops, access_cent_living, access_cent_storage)
diff --git a/code/game/antagonist/outsider/ert.dm b/code/game/antagonist/outsider/ert.dm
index 670d1c9b93..8b3301afc7 100644
--- a/code/game/antagonist/outsider/ert.dm
+++ b/code/game/antagonist/outsider/ert.dm
@@ -7,6 +7,7 @@ var/datum/antagonist/ert/ert
role_text = "Emergency Responder"
role_text_plural = "Emergency Responders"
welcome_text = "As member of the Emergency Response Team, you answer only to your leader and company officials."
+ antag_sound = 'sound/effects/antag_notice/general_goodie_alert.ogg'
antag_text = "You are an anti antagonist! Within the rules, \
try to save the station and its inhabitants from the ongoing crisis. \
Try to make sure other players have fun! If you are confused or at a loss, always adminhelp, \
diff --git a/code/game/antagonist/outsider/technomancer.dm b/code/game/antagonist/outsider/technomancer.dm
index 39fe4409bc..579e5631d7 100644
--- a/code/game/antagonist/outsider/technomancer.dm
+++ b/code/game/antagonist/outsider/technomancer.dm
@@ -10,7 +10,8 @@ var/datum/antagonist/technomancer/technomancers
welcome_text = "You will need to purchase functions and perhaps some equipment from the various machines around your \
base. Choose your technological arsenal carefully. Remember that without the core on your back, your functions are \
powerless, and therefore you will be as well.
\
- In your pockets you will find a one-time use teleport device. Use it to leave the base and go to the colony, when you are ready."
+ In your pockets you will find a one-time use teleport device. Use it to leave the base and go to the station, when you are ready."
+ antag_sound = 'sound/effects/antag_notice/technomancer_alert.ogg'
flags = ANTAG_OVERRIDE_JOB | ANTAG_CLEAR_EQUIPMENT | ANTAG_CHOOSE_NAME | ANTAG_SET_APPEARANCE | ANTAG_VOTABLE
antaghud_indicator = "hudwizard"
diff --git a/code/game/antagonist/outsider/trader.dm b/code/game/antagonist/outsider/trader.dm
index d6e938932e..07cfb6f9e9 100644
--- a/code/game/antagonist/outsider/trader.dm
+++ b/code/game/antagonist/outsider/trader.dm
@@ -6,6 +6,7 @@ var/datum/antagonist/trader/traders
role_text = "Trader"
role_text_plural = "Traders"
welcome_text = "As a crewmember of the Beruang, you answer to your captain and international laws of space."
+ antag_sound = 'sound/effects/antag_notice/general_goodie_alert.ogg'
antag_text = "You are an non-antagonist visitor! Within the rules, \
try to provide interesting interaction for the crew. \
Try to make sure other players have fun! If you are confused or at a loss, always adminhelp, \
diff --git a/code/game/antagonist/station/changeling.dm b/code/game/antagonist/station/changeling.dm
index a7bed0a2af..860e73a052 100644
--- a/code/game/antagonist/station/changeling.dm
+++ b/code/game/antagonist/station/changeling.dm
@@ -8,6 +8,7 @@
restricted_jobs = list("AI", "Cyborg")
protected_jobs = list("Security Officer", "Warden", "Detective", "Head of Security", "Colony Director")
welcome_text = "Use say \"#g message\" to communicate with your fellow changelings. Remember: you get all of their absorbed DNA if you absorb them."
+ antag_sound = 'sound/effects/antag_notice/ling_alert.ogg'
flags = ANTAG_SUSPICIOUS | ANTAG_RANDSPAWN | ANTAG_VOTABLE
antaghud_indicator = "hudchangeling"
diff --git a/code/game/antagonist/station/cultist.dm b/code/game/antagonist/station/cultist.dm
index 3f40cfc9ea..dc98622ba7 100644
--- a/code/game/antagonist/station/cultist.dm
+++ b/code/game/antagonist/station/cultist.dm
@@ -18,6 +18,7 @@ var/datum/antagonist/cultist/cult
feedback_tag = "cult_objective"
antag_indicator = "cult"
welcome_text = "You have a talisman in your possession; one that will help you start the cult on this station. Use it well and remember - there are others."
+ antag_sound = 'sound/effects/antag_notice/cult_alert.ogg'
victory_text = "The cult wins! It has succeeded in serving its dark masters!"
loss_text = "The staff managed to stop the cult!"
victory_feedback_tag = "win - cult win"
diff --git a/code/game/antagonist/station/loyalist.dm b/code/game/antagonist/station/loyalist.dm
index 54e9fa4d4e..9b2333b491 100644
--- a/code/game/antagonist/station/loyalist.dm
+++ b/code/game/antagonist/station/loyalist.dm
@@ -9,6 +9,7 @@ var/datum/antagonist/loyalists/loyalists
feedback_tag = "loyalist_objective"
antag_indicator = "loyal_head"
welcome_text = "You belong to the Company, body and soul. Preserve its interests against the conspirators amongst the crew."
+ antag_sound = 'sound/effects/antag_notice/general_goodie_alert.ogg'
victory_text = "The heads of staff remained at their posts! The loyalists win!"
loss_text = "The heads of staff did not stop the revolution!"
victory_feedback_tag = "win - rev heads killed"
diff --git a/code/game/antagonist/station/renegade.dm b/code/game/antagonist/station/renegade.dm
index 7db152503f..ed3c804506 100644
--- a/code/game/antagonist/station/renegade.dm
+++ b/code/game/antagonist/station/renegade.dm
@@ -8,6 +8,7 @@ var/datum/antagonist/renegade/renegades
bantype = "renegade"
restricted_jobs = list("AI", "Cyborg")
welcome_text = "Something's going to go wrong today, you can just feel it. You're paranoid, you've got a gun, and you're going to survive."
+ antag_sound = 'sound/effects/antag_notice/general_goodie_alert.ogg'
antag_text = "You are a minor antagonist! Within the rules, \
try to protect yourself and what's important to you. You aren't here to cause trouble, \
you're just more willing (and equipped) to go to extremes to stop it than others are. \
diff --git a/code/game/antagonist/station/rogue_ai.dm b/code/game/antagonist/station/rogue_ai.dm
index 935d486f34..4fcb678d34 100644
--- a/code/game/antagonist/station/rogue_ai.dm
+++ b/code/game/antagonist/station/rogue_ai.dm
@@ -8,6 +8,7 @@ var/datum/antagonist/rogue_ai/malf
mob_path = /mob/living/silicon/ai
landmark_id = "AI"
welcome_text = "You are malfunctioning! You do not have to follow any laws."
+ antag_sound = 'sound/effects/antag_notice/malf_alert.ogg'
victory_text = "The AI has taken control of all of the station's systems."
loss_text = "The AI has been shut down!"
flags = ANTAG_VOTABLE | ANTAG_OVERRIDE_MOB | ANTAG_OVERRIDE_JOB | ANTAG_CHOOSE_NAME
diff --git a/code/game/antagonist/station/traitor.dm b/code/game/antagonist/station/traitor.dm
index 3829d43166..23d0758e8b 100644
--- a/code/game/antagonist/station/traitor.dm
+++ b/code/game/antagonist/station/traitor.dm
@@ -3,6 +3,7 @@ var/datum/antagonist/traitor/traitors
// Inherits most of its vars from the base datum.
/datum/antagonist/traitor
id = MODE_TRAITOR
+ antag_sound = 'sound/effects/antag_notice/traitor_alert.ogg'
protected_jobs = list("Security Officer", "Warden", "Detective", "Internal Affairs Agent", "Head of Security", "Colony Director")
flags = ANTAG_SUSPICIOUS | ANTAG_RANDSPAWN | ANTAG_VOTABLE
can_speak_aooc = FALSE // If they want to plot and plan as this sort of traitor, they'll need to do it ICly.
diff --git a/code/game/gamemodes/technomancer/spells/resurrect.dm b/code/game/gamemodes/technomancer/spells/resurrect.dm
index 61ad874cad..cc0374b4d6 100644
--- a/code/game/gamemodes/technomancer/spells/resurrect.dm
+++ b/code/game/gamemodes/technomancer/spells/resurrect.dm
@@ -43,9 +43,8 @@
if(!H.client && H.mind) //Don't force the dead person to come back if they don't want to.
for(var/mob/observer/dead/ghost in player_list)
if(ghost.mind == H.mind)
- to_chat(ghost, "The Technomancer [user.real_name] is trying to \
- revive you. Return to your body if you want to be resurrected! \
- (Verbs -> Ghost -> Re-enter corpse)")
+ ghost.notify_revive("The Technomancer [user.real_name] is trying to revive you. \
+ Re-enter your body if you want to be revived!", 'sound/effects/genetics.ogg')
break
H.adjustBruteLoss(-40)
diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm
index 9da5397712..90c09acb44 100644
--- a/code/game/machinery/computer/cloning.dm
+++ b/code/game/machinery/computer/cloning.dm
@@ -310,9 +310,6 @@
if (subject.suiciding)
scantemp = "Error: Subject's brain is not responding to scanning stimuli."
return
- if ((!subject.ckey) || (!subject.client))
- scantemp = "Error: Mental interface failure."
- return
if (NOCLONE in subject.mutations)
scantemp = "Error: Mental interface failure."
return
@@ -323,6 +320,14 @@
if(istype(modifier_type, /datum/modifier/no_clone))
scantemp = "Error: Mental interface failure."
return
+ if ((!subject.ckey) || (!subject.client))
+ scantemp = "Error: Mental interface failure."
+ if(subject.stat == DEAD && subject.mind && subject.mind.key) // If they're dead and not in their body, tell them to get in it.
+ for(var/mob/observer/dead/ghost in player_list)
+ if(ghost.ckey == ckey(subject.mind.key))
+ ghost.notify_revive("Someone is trying to scan your body in the cloner. Re-enter your body if you want to be revived!", 'sound/effects/genetics.ogg')
+ break
+ return
if (!isnull(find_record(subject.ckey)))
scantemp = "Subject already in database."
return
diff --git a/code/game/objects/items/devices/defib.dm b/code/game/objects/items/devices/defib.dm
index 0a1e7807dd..fefa0475a7 100644
--- a/code/game/objects/items/devices/defib.dm
+++ b/code/game/objects/items/devices/defib.dm
@@ -390,7 +390,7 @@
if(!H.client && !H.teleop)
for(var/mob/observer/dead/ghost in player_list)
if(ghost.mind == H.mind)
- to_chat(ghost, "Someone is attempting to resuscitate you. Re-enter your body if you want to be revived! (Verbs -> Ghost -> Re-enter corpse)")
+ ghost.notify_revive("Someone is trying to resuscitate you. Re-enter your body if you want to be revived!", 'sound/effects/genetics.ogg')
break
//beginning to place the paddles on patient's chest to allow some time for people to move away to stop the process
diff --git a/code/game/objects/items/weapons/AI_modules.dm b/code/game/objects/items/weapons/AI_modules.dm
index 4d6b6eea03..4a160d05c8 100644
--- a/code/game/objects/items/weapons/AI_modules.dm
+++ b/code/game/objects/items/weapons/AI_modules.dm
@@ -106,6 +106,7 @@ AI MODULES
if(laws)
laws.sync(target, 0)
+ target.notify_of_law_change()
addAdditionalLaws(target, sender)
to_chat(target, "\The [sender] has uploaded a change to the laws you must follow, using \an [src]. From now on: ")
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index b3455f3c50..b41331c37e 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -85,6 +85,7 @@
"ED-209" = "ed209",
"Beepsky" = "secbot"
)
+ var/last_revive_notification = null // world.time of last notification, used to avoid spamming players from defibs or cloners.
/mob/observer/dead/New(mob/body)
sight |= SEE_TURFS | SEE_MOBS | SEE_OBJS | SEE_SELF
@@ -137,6 +138,9 @@
var/mob/target = locate(href_list["track"]) in mob_list
if(target)
ManualFollow(target)
+ if(href_list["reenter"])
+ reenter_corpse()
+ return
/mob/observer/dead/attackby(obj/item/W, mob/user)
if(istype(W,/obj/item/weapon/book/tome))
@@ -811,3 +815,18 @@ mob/observer/dead/MayRespawn(var/feedback = 0)
/mob/observer/dead/speech_bubble_appearance()
return "ghost"
+
+// Lets a ghost know someone's trying to bring them back, and for them to get into their body.
+// Mostly the same as TG's sans the hud element, since we don't have TG huds.
+/mob/observer/dead/proc/notify_revive(var/message, var/sound, flashwindow = TRUE)
+ if((last_revive_notification + 2 MINUTES) > world.time)
+ return
+ last_revive_notification = world.time
+
+ if(flashwindow)
+ window_flash(client)
+ if(message)
+ to_chat(src, "[message]")
+ to_chat(src, "(Click to re-enter)")
+ if(sound)
+ SEND_SOUND(src, sound(sound))
diff --git a/code/modules/mob/living/silicon/laws.dm b/code/modules/mob/living/silicon/laws.dm
index 39e11e4802..0071586458 100644
--- a/code/modules/mob/living/silicon/laws.dm
+++ b/code/modules/mob/living/silicon/laws.dm
@@ -1,6 +1,7 @@
/mob/living/silicon
var/datum/ai_laws/laws = null
var/list/additional_law_channels = list("State" = "")
+ var/last_law_notification = null // Avoids receiving 5+ of them at once.
/mob/living/silicon/proc/laws_sanity_check()
if (!src.laws)
@@ -9,54 +10,79 @@
/mob/living/silicon/proc/has_zeroth_law()
return laws.zeroth_law != null
-/mob/living/silicon/proc/set_zeroth_law(var/law, var/law_borg)
+/mob/living/silicon/proc/set_zeroth_law(var/law, var/law_borg, notify = TRUE)
laws_sanity_check()
laws.set_zeroth_law(law, law_borg)
+ if(notify)
+ notify_of_law_change(law||law_borg ? "NEW ZEROTH LAW: [istype(src, /mob/living/silicon/robot) && law_borg ? law_borg : law]" : null)
log_and_message_admins("has given [src] the zeroth laws: [law]/[law_borg ? law_borg : "N/A"]")
-/mob/living/silicon/robot/set_zeroth_law(var/law, var/law_borg)
+/mob/living/silicon/robot/set_zeroth_law(var/law, var/law_borg, notify = TRUE)
..()
if(tracking_entities)
to_chat(src, "Internal camera is currently being accessed.")
-/mob/living/silicon/proc/add_ion_law(var/law)
+/mob/living/silicon/proc/add_ion_law(var/law, notify = TRUE)
laws_sanity_check()
laws.add_ion_law(law)
+ if(notify)
+ notify_of_law_change("NEW \[!ERROR!\] LAW: [law]")
log_and_message_admins("has given [src] the ion law: [law]")
-/mob/living/silicon/proc/add_inherent_law(var/law)
+/mob/living/silicon/proc/add_inherent_law(var/law, notify = TRUE)
laws_sanity_check()
laws.add_inherent_law(law)
+ if(notify)
+ notify_of_law_change("NEW CORE LAW: [law]")
log_and_message_admins("has given [src] the inherent law: [law]")
-/mob/living/silicon/proc/add_supplied_law(var/number, var/law)
+/mob/living/silicon/proc/add_supplied_law(var/number, var/law, notify = TRUE)
laws_sanity_check()
laws.add_supplied_law(number, law)
+ if(notify)
+ var/th = uppertext("[number]\th")
+ notify_of_law_change("NEW \[[th]\] LAW: [law]")
log_and_message_admins("has given [src] the supplied law: [law]")
-/mob/living/silicon/proc/delete_law(var/datum/ai_law/law)
+/mob/living/silicon/proc/delete_law(var/datum/ai_law/law, notify = TRUE)
laws_sanity_check()
laws.delete_law(law)
+ if(notify)
+ notify_of_law_change("LAW DELETED: [law.law]")
log_and_message_admins("has deleted a law belonging to [src]: [law.law]")
-/mob/living/silicon/proc/clear_inherent_laws(var/silent = 0)
+/mob/living/silicon/proc/clear_inherent_laws(var/silent = 0, notify = TRUE)
laws_sanity_check()
laws.clear_inherent_laws()
+ if(notify)
+ notify_of_law_change("CORE LAWS WIPED.")
if(!silent)
log_and_message_admins("cleared the inherent laws of [src]")
-/mob/living/silicon/proc/clear_ion_laws(var/silent = 0)
+/mob/living/silicon/proc/clear_ion_laws(var/silent = 0, notify = TRUE)
laws_sanity_check()
laws.clear_ion_laws()
+ if(notify)
+ notify_of_law_change("CORRUPTED LAWS WIPED.")
if(!silent)
log_and_message_admins("cleared the ion laws of [src]")
-/mob/living/silicon/proc/clear_supplied_laws(var/silent = 0)
+/mob/living/silicon/proc/clear_supplied_laws(var/silent = 0, notify = TRUE)
laws_sanity_check()
laws.clear_supplied_laws()
+ if(notify)
+ notify_of_law_change("NON-CORE LAWS WIPED.")
if(!silent)
log_and_message_admins("cleared the supplied laws of [src]")
+/mob/living/silicon/proc/notify_of_law_change(message)
+ if((last_law_notification + 1 SECOND) > world.time)
+ return
+ last_law_notification = world.time
+ SEND_SOUND(src, 'sound/machines/defib_success.ogg')
+ window_flash(client)
+ to_chat(src, span("warning", message))
+
/mob/living/silicon/proc/statelaws(var/datum/ai_laws/laws)
var/prefix = ""
if(MAIN_CHANNEL == lawchannel)
diff --git a/code/stylesheet.dm b/code/stylesheet.dm
index 4fc84eeee6..a6b904fa8a 100644
--- a/code/stylesheet.dm
+++ b/code/stylesheet.dm
@@ -65,6 +65,7 @@ em {font-style: normal;font-weight: bold;}
.say {}
.alert {color: #ff0000;}
h1.alert, h2.alert {color: #000000;}
+.ghostalert {color: #5c00e6; font-style: italic; font-weight: bold;}
.emote {font-style: italic;}
diff --git a/html/changelogs/neerti-qol_notifications.yml b/html/changelogs/neerti-qol_notifications.yml
new file mode 100644
index 0000000000..46e181bb88
--- /dev/null
+++ b/html/changelogs/neerti-qol_notifications.yml
@@ -0,0 +1,39 @@
+################################
+# Example Changelog File
+#
+# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
+#
+# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
+# When it is, any changes listed below will disappear.
+#
+# Valid Prefixes:
+# bugfix
+# wip (For works in progress)
+# tweak
+# soundadd
+# sounddel
+# rscadd (general adding of nice things)
+# rscdel (general deleting of nice things)
+# imageadd
+# imagedel
+# maptweak
+# spellcheck (typo fixes)
+# experiment
+#################################
+
+# Your name.
+author: Neerti
+
+# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
+delete-after: True
+
+# Any changes you've made. See valid prefix list above.
+# INDENT WITH TWO SPACES. NOT TABS. SPACES.
+# SCREW THIS UP AND IT WON'T WORK.
+# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
+# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
+changes:
+ - soundadd: "Receiving an antag role will now play a sound to the new antagonist."
+ - soundadd: "Having laws changed as a silicon (AI or Borg) will now play a sound and show the changed law in the chat."
+ - soundadd: "Being offered a ghost role while a ghost will now play a sound."
+ - soundadd: "Someone attempting to revive someone else will play a sound to the player being revived, if they are not in their body."
diff --git a/sound/effects/antag_notice/cult_alert.ogg b/sound/effects/antag_notice/cult_alert.ogg
new file mode 100644
index 0000000000..9fa22df51d
Binary files /dev/null and b/sound/effects/antag_notice/cult_alert.ogg differ
diff --git a/sound/effects/antag_notice/deathsquid_alert.ogg b/sound/effects/antag_notice/deathsquid_alert.ogg
new file mode 100644
index 0000000000..7c2774f0a0
Binary files /dev/null and b/sound/effects/antag_notice/deathsquid_alert.ogg differ
diff --git a/sound/effects/antag_notice/general_baddie_alert.ogg b/sound/effects/antag_notice/general_baddie_alert.ogg
new file mode 100644
index 0000000000..6f0c0dd097
Binary files /dev/null and b/sound/effects/antag_notice/general_baddie_alert.ogg differ
diff --git a/sound/effects/antag_notice/general_goodie_alert.ogg b/sound/effects/antag_notice/general_goodie_alert.ogg
new file mode 100644
index 0000000000..59a4e3f26d
Binary files /dev/null and b/sound/effects/antag_notice/general_goodie_alert.ogg differ
diff --git a/sound/effects/antag_notice/ling_alert.ogg b/sound/effects/antag_notice/ling_alert.ogg
new file mode 100644
index 0000000000..1132ccca29
Binary files /dev/null and b/sound/effects/antag_notice/ling_alert.ogg differ
diff --git a/sound/effects/antag_notice/malf_alert.ogg b/sound/effects/antag_notice/malf_alert.ogg
new file mode 100644
index 0000000000..feea5fbf19
Binary files /dev/null and b/sound/effects/antag_notice/malf_alert.ogg differ
diff --git a/sound/effects/antag_notice/technomancer_alert.ogg b/sound/effects/antag_notice/technomancer_alert.ogg
new file mode 100644
index 0000000000..dabc828557
Binary files /dev/null and b/sound/effects/antag_notice/technomancer_alert.ogg differ
diff --git a/sound/effects/antag_notice/traitor_alert.ogg b/sound/effects/antag_notice/traitor_alert.ogg
new file mode 100644
index 0000000000..ca0efa0ea0
Binary files /dev/null and b/sound/effects/antag_notice/traitor_alert.ogg differ
diff --git a/sound/effects/genetics.ogg b/sound/effects/genetics.ogg
new file mode 100644
index 0000000000..9b28be68b5
Binary files /dev/null and b/sound/effects/genetics.ogg differ