"}
+ "} //NSV13 - TEXT AMENDED, "GENERAL RECORDS" - Roleplaying Records
else
dat += " General Record Lost! "
if((istype(active2, /datum/data/record) && GLOB.data_core.security.Find(active2)))
dat += "Security Data"
+ dat += " Security Records: View" //NSV13 - Roleplaying Records
dat += " Criminal Status: [active2.fields["criminal"]]"
dat += "
Citations: Add New"
@@ -455,6 +457,21 @@ What a mess.*/
if(usr.contents.Find(src) || (in_range(src, usr) && isturf(loc)) || issilicon(usr) || IsAdminGhost(usr))
usr.set_machine(src)
switch(href_list["choice"])
+ //NSV13 - Roleplaying Records - Start
+ if("View Past Security")
+ if(istype(active2, /datum/data/record))
+ temp = "
"
+
+ dat += "Set Silicon Examine Text"
+ if(length(active_character.silicon_flavor_text) <= 40)
+ if(!length(active_character.silicon_flavor_text))
+ dat += "\[...\]"
+ else
+ dat += "[active_character.silicon_flavor_text]"
+ else
+ dat += "[copytext_char(active_character.silicon_flavor_text, 1, 40)]... "
+
+ dat += "
"
+
+ dat += "
"
+ dat += "
"
+
+ dat += "
General Record
"
+ dat += "Set General Record "
+
+ if(length(active_character.general_record) <= 40)
+ if(!length(active_character.general_record))
+ dat += "\[...\]"
+ else
+ dat += "[html_encode(active_character.general_record)]"
+ else
+ dat += "[copytext_char(active_character.general_record, 1, 40)]..."
+
+ dat += " "
+
+
+ dat += "
Medical Record
"
+ dat += "Set Medical Record "
+
+ if(length(active_character.medical_record) <= 40)
+ if(!length(active_character.medical_record))
+ dat += "\[...\]"
+ else
+ dat += "[html_encode(active_character.medical_record)]"
+ else
+ dat += "[copytext_char(active_character.medical_record, 1, 40)]..."
+
+ dat += " "
+
+
+ dat += "
Security Record
"
+ dat += "Set Security Record "
+
+ if(length(active_character.security_record) <= 40)
+ if(!length(active_character.security_record))
+ dat += "\[...\]"
+ else
+ dat += "[html_encode(active_character.security_record)]"
+ else
+ dat += "[copytext_char(active_character.security_record, 1, 40)]..."
+
+ dat += " "
+ dat += "
"
+
+ dat += "
"
+ dat += "
Background Information
"
+ dat += "Set Background Information "
+
+ if(length(active_character.background_info) <= 40)
+ if(!length(active_character.background_info))
+ dat += "\[...\]"
+ else
+ dat += "[html_encode(active_character.background_info)]"
+ else
+ dat += "[copytext_char(active_character.background_info, 1, 40)]..."
+
+ dat += "
"
+ //NSV13 - Roleplay Tab - End
dat += "
"
if(!IS_GUEST_KEY(user.key))
@@ -1689,7 +1764,33 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("syndiecrew")
var/client/C = (istype(user, /client)) ? user : user.client
C.select_syndie_role()
- //Nsv13 end
+ //Nsv13 - Roleplay Stuff
+ if("silicon_flavor_text")
+ var/msg = input(usr, "Set the flavor text in your 'examine' verb. This is for describing what people can tell by looking at your character.", "Silicon Flavor Text", active_character.silicon_flavor_text) as message|null
+ if(!isnull(msg))
+ active_character.silicon_flavor_text = html_decode(strip_html(msg))
+
+ if("general_record")
+ var/msg = input(usr, "Set your general record. This is more or less public information, available from security, medical and command consoles", "General Record", active_character.general_record) as message|null
+ if(!isnull(msg))
+ active_character.general_record = html_decode(strip_html(msg))
+
+ if("medical_record")
+ var/msg = input(usr, "Set your medical record. ", "Medical Record", active_character.medical_record) as message|null
+ if(!isnull(msg))
+ active_character.medical_record = html_decode(strip_html(msg))
+
+ if("security_record")
+ var/msg = input(usr, "Set your security record. ", "Medical Record", active_character.security_record) as message|null
+ if(!isnull(msg))
+ active_character.security_record = html_decode(strip_html(msg))
+
+ if("background_info")
+ var/msg = input(usr, "Set your background information. (Where you come from, which culture were you raised in and why you are working here etc.)", "Background Info", active_character.background_info) as message|null
+ if(!isnull(msg))
+ active_character.background_info = html_decode(strip_html(msg))
+
+ //NSV13 - END
if ("preferred_map")
var/maplist = list()
var/default = "Default"
diff --git a/code/modules/client/preferences2/character_save.dm b/code/modules/client/preferences2/character_save.dm
index 22e62b3bb53..c831dc098e2 100644
--- a/code/modules/client/preferences2/character_save.dm
+++ b/code/modules/client/preferences2/character_save.dm
@@ -69,7 +69,13 @@
var/preferred_squad = "Able"
//NSV13 - Pilots
var/preferred_pilot_role = PILOT_COMBAT
-
+ //NSV13 - Silicon Flavor Text
+ var/silicon_flavor_text = ""
+ //NSV13 - Background Information
+ var/general_record = ""
+ var/security_record = ""
+ var/medical_record = ""
+ var/background_info = ""
/datum/character_save/New()
real_name = get_default_name()
@@ -148,12 +154,22 @@
SAFE_READ_QUERY(31, loadout_tmp)
equipped_gear = json_decode(loadout_tmp)
- //NSV13 squads
+ //NSV13 - Start
SAFE_READ_QUERY(32, preferred_squad)
- //NSV13 pilot role
SAFE_READ_QUERY(33, preferred_pilot_role)
+ SAFE_READ_QUERY(34, silicon_flavor_text)
+
+ SAFE_READ_QUERY(35, general_record)
+
+ SAFE_READ_QUERY(36, security_record)
+
+ SAFE_READ_QUERY(37, medical_record)
+
+ SAFE_READ_QUERY(38, background_info)
+ //NSV13 - Stop
+
//Sanitize. Please dont put query reads below this point. Please.
real_name = reject_bad_name(real_name, pref_species.allow_numbers_in_name)
@@ -234,6 +250,13 @@
all_quirks = SANITIZE_LIST(all_quirks)
+ //NSV13 - Roleplay Stuff - Start
+ silicon_flavor_text = html_decode(strip_html(silicon_flavor_text))
+ general_record = sanitize_text(general_record)
+ security_record = sanitize_text(security_record)
+ medical_record = sanitize_text(medical_record)
+ background_info = sanitize_text(background_info)
+
return TRUE
#undef SAFE_READ_QUERY
@@ -298,7 +321,7 @@
if(IS_GUEST_KEY(C.ckey))
return
- // Get ready for a disgusting query //NSV13 adds squads and pilot role prefs
+ // Get ready for a disgusting query //NSV13 adds squads, pilot role and roleplaying prefs
var/datum/DBQuery/insert_query = SSdbcore.NewQuery({"
REPLACE INTO [format_table_name("characters")] (
slot,
@@ -334,7 +357,12 @@
all_quirks,
equipped_gear,
preferred_squad,
- preferred_pilot_role
+ preferred_pilot_role,
+ silicon_flavor_text,
+ general_record,
+ security_record,
+ medical_record,
+ background_info
) VALUES (
:slot,
:ckey,
@@ -369,7 +397,12 @@
:all_quirks,
:equipped_gear,
:preferred_squad,
- :preferred_pilot_role
+ :preferred_pilot_role,
+ :silicon_flavor_text,
+ :general_record,
+ :security_record,
+ :medical_record,
+ :background_info
)
"}, list(
// Now for the above but in a fucking monsterous list
@@ -406,7 +439,12 @@
"all_quirks" = json_encode(all_quirks),
"equipped_gear" = json_encode(equipped_gear),
"preferred_squad" = preferred_squad,
- "preferred_pilot_role" = preferred_pilot_role
+ "preferred_pilot_role" = preferred_pilot_role,
+ "silicon_flavor_text" = silicon_flavor_text,
+ "general_record" = general_record,
+ "security_record" = security_record,
+ "medical_record" = medical_record,
+ "background_info" = background_info
))
if(!insert_query.warn_execute())
diff --git a/code/modules/client/preferences2/preferences2.dm b/code/modules/client/preferences2/preferences2.dm
index a016737c572..649800fc7aa 100644
--- a/code/modules/client/preferences2/preferences2.dm
+++ b/code/modules/client/preferences2/preferences2.dm
@@ -214,7 +214,8 @@
all_quirks,
equipped_gear,
preferred_squad,
- preferred_pilot_role
+ preferred_pilot_role,
+ silicon_flavor_text
FROM [format_table_name("characters")] WHERE
ckey=:ckey
"}, list("ckey" = parent.ckey))
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index c00a3b10a9d..d2265c955cb 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -17,7 +17,7 @@
if(HAS_TRAIT(L, TRAIT_PROSOPAGNOSIA))
obscure_name = TRUE
- var/apparent_species
+ var/apparent_species
//NSV13 - add rank to name
var/display_name = ""
if(CONFIG_GET(flag/show_ranks))
@@ -359,6 +359,10 @@
. += "\[Medical evaluation\] "
if(traitstring)
. += "Detected physiological traits:\n[traitstring]"
+ //NSV13 - Roleplaying Records - Start
+ . += "\[View medical records\]"
+ . += "\[View general records\]"
+ //NSV13 - Roleplaying Records - End
if(HAS_TRAIT(user, TRAIT_SECURITY_HUD))
if(!user.stat && user != src)
@@ -370,13 +374,32 @@
criminal = R.fields["criminal"]
. += "Criminal status:\[[criminal]\]"
- . += jointext(list("Security record:\[View\]",
+ . += jointext(list("Security record:\[View security records\]", //NSV13 - Roleplaying Records
"\[Add citation\]",
"\[Add crime\]",
"\[View comment log\]",
"\[Add comment\]"), "")
+
+ . += jointext(list("General record:\[View general records\]"), "") //NSV13 - Roleplaying Records
else if(isobserver(user) && traitstring)
. += "Traits: [traitstring]"
+
+ //NSV13 - Roleplaying Records - Start
+ if(client && user.client.holder && isobserver(user))
+ var/line = ""
+ if(!(client.prefs.active_character.general_record == ""))
+ line += "\[GEN\]"
+ if(!(client.prefs.active_character.security_record == ""))
+ line += "\[SEC\]"
+ if(!(client.prefs.active_character.medical_record == ""))
+ line += "\[MED\]"
+ if(!(client.prefs.active_character.background_info == ""))
+ line += "\[BG\]"
+
+ if(!(line == ""))
+ . += "*---------*"
+ . += line
+ //NSV13 - Roleplaying Records - End
. += "*---------*"
/mob/living/proc/status_effect_examines(pronoun_replacement) //You can include this in any mob's examine() to show the examine texts of status effects!
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 94f98b46f35..f29b1ca6252 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -170,17 +170,20 @@
var/perpname = get_face_name(get_id_name(""))
if(!HAS_TRAIT(H, TRAIT_SECURITY_HUD) && !HAS_TRAIT(H, TRAIT_MEDICAL_HUD))
return
- var/datum/data/record/R = find_record("name", perpname, GLOB.data_core.general)
+ //NSV13 - Roleplaying Records - Changed ALL the references to the variable R to these three records below here - Start
+ var/datum/data/record/general_record = find_record("name", perpname, GLOB.data_core.general)
+ var/datum/data/record/med_record = find_record("name", perpname, GLOB.data_core.medical)
+ var/datum/data/record/sec_record = find_record("name", perpname, GLOB.data_core.security)
if(href_list["photo_front"] || href_list["photo_side"])
- if(!R)
+ if(!general_record)
return
if(!H.canUseHUD())
return
var/obj/item/photo/P = null
if(href_list["photo_front"])
- P = R.fields["photo_front"]
+ P = general_record.fields["photo_front"]
else if(href_list["photo_side"])
- P = R.fields["photo_side"]
+ P = general_record.fields["photo_side"]
if(P)
P.show(H)
return
@@ -236,27 +239,31 @@
to_chat(H, "ERROR: Invalid access")
return
if(href_list["p_stat"])
- var/health_status = input(usr, "Specify a new physical status for this person.", "Medical HUD", R.fields["p_stat"]) in list("Active", "Physically Unfit", "*Unconscious*", "*Deceased*", "Cancel")
- if(!R)
+ var/health_status = input(usr, "Specify a new physical status for this person.", "Medical HUD", general_record.fields["p_stat"]) in list("Active", "Physically Unfit", "*Unconscious*", "*Deceased*", "Cancel")
+ if(!general_record)
return
if(!H.canUseHUD())
return
if(!HAS_TRAIT(H, TRAIT_MEDICAL_HUD))
return
if(health_status && health_status != "Cancel")
- R.fields["p_stat"] = health_status
+ general_record.fields["p_stat"] = health_status
return
if(href_list["m_stat"])
- var/health_status = input(usr, "Specify a new mental status for this person.", "Medical HUD", R.fields["m_stat"]) in list("Stable", "*Watch*", "*Unstable*", "*Insane*", "Cancel")
- if(!R)
+ var/health_status = input(usr, "Specify a new mental status for this person.", "Medical HUD", general_record.fields["m_stat"]) in list("Stable", "*Watch*", "*Unstable*", "*Insane*", "Cancel")
+ if(!general_record)
return
if(!H.canUseHUD())
return
if(!HAS_TRAIT(H, TRAIT_MEDICAL_HUD))
return
if(health_status && health_status != "Cancel")
- R.fields["m_stat"] = health_status
+ general_record.fields["m_stat"] = health_status
return
+ if(href_list["medrecords"])
+ to_chat(usr, " Medical Record:[med_record.fields["past_records"]]")
+ if(href_list["genrecords"])
+ to_chat(usr, "General Record: [general_record.fields["past_records"]]")
return //Medical HUD ends here.
if(href_list["hud"] == "s")
@@ -282,31 +289,30 @@
if(!perpname)
to_chat(H, "ERROR: Can not identify target.")
return
- R = find_record("name", perpname, GLOB.data_core.security)
- if(!R)
+ if(!sec_record)
to_chat(usr, "ERROR: Unable to locate data core entry for target.")
return
if(href_list["status"])
- var/setcriminal = input(usr, "Specify a new criminal status for this person.", "Security HUD", R.fields["criminal"]) in list("None", "Arrest", "Search", "Monitor", "Incarcerated", "Paroled", "Discharged", "Cancel")
+ var/setcriminal = input(usr, "Specify a new criminal status for this person.", "Security HUD", sec_record.fields["criminal"]) in list("None", "Arrest", "Search", "Monitor", "Incarcerated", "Paroled", "Discharged", "Cancel")
if(setcriminal != "Cancel")
- if(!R)
+ if(!sec_record)
return
if(!H.canUseHUD())
return
if(!HAS_TRAIT(H, TRAIT_SECURITY_HUD))
return
- investigate_log("[key_name(src)] has been set from [R.fields["criminal"]] to [setcriminal] by [key_name(usr)].", INVESTIGATE_RECORDS)
- R.fields["criminal"] = setcriminal
+ investigate_log("[key_name(src)] has been set from [sec_record.fields["criminal"]] to [setcriminal] by [key_name(usr)].", INVESTIGATE_RECORDS)
+ sec_record.fields["criminal"] = setcriminal
sec_hud_set_security_status()
return
- if(href_list["view"])
+ if(href_list["viewsec"])
if(!H.canUseHUD())
return
if(!HAS_TRAIT(H, TRAIT_SECURITY_HUD))
return
- to_chat(usr, "Name: [R.fields["name"]] Criminal Status: [R.fields["criminal"]]")
- for(var/datum/data/crime/c in R.fields["crim"])
+ to_chat(usr, "Name: [sec_record.fields["name"]] Criminal Status: [sec_record.fields["criminal"]]")
+ for(var/datum/data/crime/c in sec_record.fields["crim"])
to_chat(usr, "Crime: [c.crimeName]")
if (c.crimeDetails)
to_chat(usr, "Details: [c.crimeDetails]")
@@ -314,14 +320,22 @@
to_chat(usr, "Details:\[Add details]")
to_chat(usr, "Added by [c.author] at [c.time]")
to_chat(usr, "----------")
- to_chat(usr, "Notes: [R.fields["notes"]]")
+ to_chat(usr, "Notes: [sec_record.fields["notes"]]")
+ to_chat(usr, " Security Record:[sec_record.fields["past_records"]]")
return
+ if(href_list["genrecords"])
+ if(!H.canUseHUD())
+ return
+ if(!HAS_TRAIT(H, TRAIT_SECURITY_HUD))
+ return
+ to_chat(usr, "General Record: [general_record.fields["past_records"]]")
+
if(href_list["add_citation"])
var/maxFine = CONFIG_GET(number/maxfine)
var/t1 = stripped_input("Please input citation crime:", "Security HUD", "", null)
var/fine = FLOOR(input("Please input citation fine, up to [maxFine]:", "Security HUD", 50) as num|null, 1)
- if(!R || !t1 || !fine || !allowed_access)
+ if(!sec_record || !t1 || !fine || !allowed_access)
return
if(!H.canUseHUD())
return
@@ -334,7 +348,7 @@
var/crime = GLOB.data_core.createCrimeEntry(t1, "", allowed_access, station_time_timestamp(), fine)
for (var/obj/item/pda/P in GLOB.PDAs)
- if(P.owner == R.fields["name"])
+ if(P.owner == sec_record.fields["name"])
var/message = "You have been fined [fine] credits for '[t1]'. Fines may be paid at security."
var/datum/signal/subspace/messaging/pda/signal = new(src, list(
"name" = "Security Citation",
@@ -345,35 +359,35 @@
))
signal.send_to_receivers()
usr.log_message("(PDA: Citation Server) sent \"[message]\" to [signal.format_target()]", LOG_PDA)
- GLOB.data_core.addCitation(R.fields["id"], crime)
- investigate_log("New Citation: [t1] Fine: [fine] | Added to [R.fields["name"]] by [key_name(usr)]", INVESTIGATE_RECORDS)
+ GLOB.data_core.addCitation(sec_record.fields["id"], crime)
+ investigate_log("New Citation: [t1] Fine: [fine] | Added to [sec_record.fields["name"]] by [key_name(usr)]", INVESTIGATE_RECORDS)
return
if(href_list["add_crime"])
var/t1 = stripped_input("Please input crime name:", "Security HUD", "", null)
- if(!R || !t1 || !allowed_access)
+ if(!sec_record || !t1 || !allowed_access)
return
if(!H.canUseHUD())
return
if(!HAS_TRAIT(H, TRAIT_SECURITY_HUD))
return
var/crime = GLOB.data_core.createCrimeEntry(t1, null, allowed_access, station_time_timestamp())
- GLOB.data_core.addCrime(R.fields["id"], crime)
- investigate_log("New Crime: [t1] | Added to [R.fields["name"]] by [key_name(usr)]", INVESTIGATE_RECORDS)
+ GLOB.data_core.addCrime(sec_record.fields["id"], crime)
+ investigate_log("New Crime: [t1] | Added to [sec_record.fields["name"]] by [key_name(usr)]", INVESTIGATE_RECORDS)
to_chat(usr, "Successfully added a crime.")
return
if(href_list["add_details"])
var/t1 = stripped_input(usr, "Please input crime details:", "Secure. records", "", null)
- if(!R || !t1 || !allowed_access)
+ if(!sec_record || !t1 || !allowed_access)
return
if(!H.canUseHUD())
return
if(!HAS_TRAIT(H, TRAIT_SECURITY_HUD))
return
if(href_list["cdataid"])
- GLOB.data_core.addCrimeDetails(R.fields["id"], href_list["cdataid"], t1)
- investigate_log("New Crime details: [t1] | Added to [R.fields["name"]] by [key_name(usr)]", INVESTIGATE_RECORDS)
+ GLOB.data_core.addCrimeDetails(sec_record.fields["id"], href_list["cdataid"], t1)
+ investigate_log("New Crime details: [t1] | Added to [sec_record.fields["name"]] by [key_name(usr)]", INVESTIGATE_RECORDS)
to_chat(usr, "Successfully added details.")
return
@@ -384,26 +398,27 @@
return
to_chat(usr, "Comments/Log:")
var/counter = 1
- while(R.fields[text("com_[]", counter)])
- to_chat(usr, R.fields[text("com_[]", counter)])
+ while(sec_record.fields[text("com_[]", counter)])
+ to_chat(usr, sec_record.fields[text("com_[]", counter)])
to_chat(usr, "----------")
counter++
return
if(href_list["add_comment"])
var/t1 = stripped_multiline_input("Add Comment:", "Secure. records", null, null)
- if (!R || !t1 || !allowed_access)
+ if (!sec_record || !t1 || !allowed_access)
return
if(!H.canUseHUD())
return
if(!HAS_TRAIT(H, TRAIT_SECURITY_HUD))
return
var/counter = 1
- while(R.fields[text("com_[]", counter)])
+ while(sec_record.fields[text("com_[]", counter)])
counter++
- R.fields[text("com_[]", counter)] = text("Made by [] on [] [], [] []", allowed_access, station_time_timestamp(), time2text(world.realtime, "MMM DD"), GLOB.year_integer+YEAR_OFFSET, t1) //NSV13 edit: year offset change
+ sec_record.fields[text("com_[]", counter)] = text("Made by [] on [] [], [] []", allowed_access, station_time_timestamp(), time2text(world.realtime, "MMM DD"), GLOB.year_integer+YEAR_OFFSET, t1) //NSV13 edit: year offset change
to_chat(usr, "Successfully added comment.")
return
+ //NSV13 - Roleplaying Records - End
..() //end of this massive fucking chain. TODO: make the hud chain not spooky.
@@ -496,10 +511,11 @@
//Check for arrest warrant
if(judgment_criteria & JUDGE_RECORDCHECK)
+ //NSV13 - Roleplaying Records - Start
var/perpname = get_face_name(get_id_name())
- var/datum/data/record/R = find_record("name", perpname, GLOB.data_core.security)
- if(R && R.fields["criminal"])
- switch(R.fields["criminal"])
+ var/datum/data/record/sec_record = find_record("name", perpname, GLOB.data_core.security)
+ if(sec_record && sec_record.fields["criminal"])
+ switch(sec_record.fields["criminal"])
if("Arrest")
threatcount += 5
if("Incarcerated")
@@ -510,6 +526,7 @@
threatcount += 1
if("Search")
threatcount += 2
+ //NSV13 - Roleplaying Records - End
//Check for dresscode violations
if(istype(head, /obj/item/clothing/head/wizard) || istype(head, /obj/item/clothing/head/helmet/space/hardsuit/wizard))
@@ -663,9 +680,11 @@
/mob/living/carbon/human/replace_records_name(oldname,newname) // Only humans have records right now, move this up if changed.
for(var/list/L in list(GLOB.data_core.general,GLOB.data_core.medical,GLOB.data_core.security,GLOB.data_core.locked))
- var/datum/data/record/R = find_record("name", oldname, L)
- if(R)
- R.fields["name"] = newname
+ //NSV13 - Roleplaying Records - Start
+ var/datum/data/record/general_record = find_record("name", oldname, L)
+ if(general_record)
+ general_record.fields["name"] = newname
+ //NSV13 - Roleplaying Records - End
/mob/living/carbon/human/get_total_tint()
. = ..()
diff --git a/code/modules/mob/living/silicon/examine.dm b/code/modules/mob/living/silicon/examine.dm
index 7de281de5f2..a8f0845e8a8 100644
--- a/code/modules/mob/living/silicon/examine.dm
+++ b/code/modules/mob/living/silicon/examine.dm
@@ -4,3 +4,15 @@
. += "[src] has the following laws:"
for(var/law in laws.get_law_list(include_zeroth = TRUE))
. += law
+
+ //NSV13 - Silicon Flavor Text - Start
+ if(client)
+ var/line
+ if(length(client.prefs.active_character.silicon_flavor_text))
+ var/message = client.prefs.active_character.silicon_flavor_text
+ if(length_char(message) <= 40)
+ line = "[message]"
+ else
+ line = "[copytext_char(message, 1, 37)]... More..."
+ . += line
+ //NS13 - Silicon Flavor Text - End
diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm
index 2b11ed16a43..4c9716fb50b 100644
--- a/code/modules/mob/living/silicon/silicon.dm
+++ b/code/modules/mob/living/silicon/silicon.dm
@@ -231,6 +231,14 @@
if (href_list["printlawtext"]) // this is kinda backwards
to_chat(usr, href_list["printlawtext"])
+ //NSV13 - Silicon Flavor Text - Start
+ if(href_list["lookup_info"])
+ if(client && length(client.prefs.active_character.silicon_flavor_text))
+ var/datum/browser/popup = new(usr, "[name]'s flavor text", "[name]'s Flavor Text", 500, 200)
+ popup.set_content(text("[][]", "[name]'s flavor text", replacetext(client.prefs.active_character.silicon_flavor_text, "\n", " ")))
+ popup.open()
+ return
+ //NSV13 - Silicon Flavor Text - End
return
From c87aa8349a0aa4849364e9aea764af7aa3589da7 Mon Sep 17 00:00:00 2001
From: Bobbanz1 <59128051+Bobbanz1@users.noreply.github.com>
Date: Thu, 12 Jan 2023 14:11:57 +0100
Subject: [PATCH 02/15] simple html strip
---
code/modules/client/preferences.dm | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 569a557e4bb..7ddafb343fb 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -1768,27 +1768,27 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if("silicon_flavor_text")
var/msg = input(usr, "Set the flavor text in your 'examine' verb. This is for describing what people can tell by looking at your character.", "Silicon Flavor Text", active_character.silicon_flavor_text) as message|null
if(!isnull(msg))
- active_character.silicon_flavor_text = html_decode(strip_html(msg))
+ active_character.silicon_flavor_text = html_decode(strip_html_simple(msg))
if("general_record")
var/msg = input(usr, "Set your general record. This is more or less public information, available from security, medical and command consoles", "General Record", active_character.general_record) as message|null
if(!isnull(msg))
- active_character.general_record = html_decode(strip_html(msg))
+ active_character.general_record = html_decode(strip_html_simple(msg))
if("medical_record")
var/msg = input(usr, "Set your medical record. ", "Medical Record", active_character.medical_record) as message|null
if(!isnull(msg))
- active_character.medical_record = html_decode(strip_html(msg))
+ active_character.medical_record = html_decode(strip_html_simple(msg))
if("security_record")
var/msg = input(usr, "Set your security record. ", "Medical Record", active_character.security_record) as message|null
if(!isnull(msg))
- active_character.security_record = html_decode(strip_html(msg))
+ active_character.security_record = html_decode(strip_html_simple(msg))
if("background_info")
var/msg = input(usr, "Set your background information. (Where you come from, which culture were you raised in and why you are working here etc.)", "Background Info", active_character.background_info) as message|null
if(!isnull(msg))
- active_character.background_info = html_decode(strip_html(msg))
+ active_character.background_info = html_decode(strip_html_simple(msg))
//NSV13 - END
if ("preferred_map")
From 3e862aabb35eaca670e58639a142b3da7d2a976a Mon Sep 17 00:00:00 2001
From: Bobbanz1 <59128051+Bobbanz1@users.noreply.github.com>
Date: Thu, 12 Jan 2023 14:26:07 +0100
Subject: [PATCH 03/15] Changes made in response to Cube
---
code/modules/client/preferences.dm | 37 +++++++++----------
.../client/preferences2/character_save.dm | 13 ++-----
.../mob/living/carbon/human/examine.dm | 2 -
3 files changed, 21 insertions(+), 31 deletions(-)
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 7ddafb343fb..633c065818a 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -134,7 +134,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/shop_name = "[CONFIG_GET(string/metacurrency_name)] Shop"
dat += "[shop_name]"
dat += "OOC Preferences"
- dat += "Character Roleplay" //NSV13 - Roleplay Tab
+ dat += "Roleplay Settings" //NSV13 - Roleplay Tab
dat += "
"
@@ -812,6 +812,23 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += ""
if(4) //NSV13 - Roleplay Tab - Start
+ dat += "
"
+ var/name
+ var/unspaced_slots = 0
+ for(var/datum/character_save/CS as anything in character_saves)
+ unspaced_slots++
+ if(unspaced_slots > 4)
+ dat += " "
+ unspaced_slots = 0
+ name = CS.real_name
+ if(!name)
+ name = "Character [CS.slot_number]"
+ if(CS.slot_locked)
+ dat += "[name] (Locked) "
+ else
+ dat += "[name] "
+ dat += "
"
+
dat += "
Flavor Text
"
dat += "
"
@@ -870,19 +887,6 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += " "
dat += "
"
-
- dat += "
"
- dat += "
Background Information
"
- dat += "Set Background Information "
-
- if(length(active_character.background_info) <= 40)
- if(!length(active_character.background_info))
- dat += "\[...\]"
- else
- dat += "[html_encode(active_character.background_info)]"
- else
- dat += "[copytext_char(active_character.background_info, 1, 40)]..."
-
dat += "
"
//NSV13 - Roleplay Tab - End
dat += "
"
@@ -1785,11 +1789,6 @@ GLOBAL_LIST_EMPTY(preferences_datums)
if(!isnull(msg))
active_character.security_record = html_decode(strip_html_simple(msg))
- if("background_info")
- var/msg = input(usr, "Set your background information. (Where you come from, which culture were you raised in and why you are working here etc.)", "Background Info", active_character.background_info) as message|null
- if(!isnull(msg))
- active_character.background_info = html_decode(strip_html_simple(msg))
-
//NSV13 - END
if ("preferred_map")
var/maplist = list()
diff --git a/code/modules/client/preferences2/character_save.dm b/code/modules/client/preferences2/character_save.dm
index c831dc098e2..9acf24a5c5d 100644
--- a/code/modules/client/preferences2/character_save.dm
+++ b/code/modules/client/preferences2/character_save.dm
@@ -75,7 +75,6 @@
var/general_record = ""
var/security_record = ""
var/medical_record = ""
- var/background_info = ""
/datum/character_save/New()
real_name = get_default_name()
@@ -166,8 +165,6 @@
SAFE_READ_QUERY(36, security_record)
SAFE_READ_QUERY(37, medical_record)
-
- SAFE_READ_QUERY(38, background_info)
//NSV13 - Stop
//Sanitize. Please dont put query reads below this point. Please.
@@ -255,7 +252,6 @@
general_record = sanitize_text(general_record)
security_record = sanitize_text(security_record)
medical_record = sanitize_text(medical_record)
- background_info = sanitize_text(background_info)
return TRUE
@@ -361,8 +357,7 @@
silicon_flavor_text,
general_record,
security_record,
- medical_record,
- background_info
+ medical_record
) VALUES (
:slot,
:ckey,
@@ -401,8 +396,7 @@
:silicon_flavor_text,
:general_record,
:security_record,
- :medical_record,
- :background_info
+ :medical_record
)
"}, list(
// Now for the above but in a fucking monsterous list
@@ -443,8 +437,7 @@
"silicon_flavor_text" = silicon_flavor_text,
"general_record" = general_record,
"security_record" = security_record,
- "medical_record" = medical_record,
- "background_info" = background_info
+ "medical_record" = medical_record
))
if(!insert_query.warn_execute())
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index d2265c955cb..5ff1e7cc8aa 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -393,8 +393,6 @@
line += "\[SEC\]"
if(!(client.prefs.active_character.medical_record == ""))
line += "\[MED\]"
- if(!(client.prefs.active_character.background_info == ""))
- line += "\[BG\]"
if(!(line == ""))
. += "*---------*"
From 8946cb5563be258229e266365f127b789939229f Mon Sep 17 00:00:00 2001
From: Bobbanz1
Date: Thu, 12 Jan 2023 19:57:36 +0100
Subject: [PATCH 04/15] Ports ExaminePanel from Skyrat
---
code/datums/outfit.dm | 33 ++++++++++++
code/modules/mob/living/carbon/human/dummy.dm | 23 ++++++++
.../mob/living/carbon/human/examine.dm | 6 +++
code/modules/mob/living/carbon/human/human.dm | 7 +++
.../mob/living/carbon/human/human_defines.dm | 3 ++
.../mob/living/carbon/human/human_helpers.dm | 8 +++
code/modules/mob/living/silicon/examine.dm | 11 ++--
code/modules/mob/living/silicon/silicon.dm | 10 ++--
nsv13.dme | 1 +
.../modules/mob/living/carbon/examine_tgui.dm | 52 +++++++++++++++++++
tgui/packages/tgui/components/Box.tsx | 2 +
tgui/packages/tgui/interfaces/ExaminePanel.js | 46 ++++++++++++++++
12 files changed, 189 insertions(+), 13 deletions(-)
create mode 100644 nsv13/code/modules/mob/living/carbon/examine_tgui.dm
create mode 100644 tgui/packages/tgui/interfaces/ExaminePanel.js
diff --git a/code/datums/outfit.dm b/code/datums/outfit.dm
index b9a4a18cea6..c369392f0e1 100755
--- a/code/datums/outfit.dm
+++ b/code/datums/outfit.dm
@@ -359,3 +359,36 @@
implants += imptype
accessory = text2path(outfit_data["accessory"])
return TRUE
+
+//NSV13
+/**
+ * Copies the outfit from a human to itself.
+ **/
+/datum/outfit/proc/copy_outfit_from_target(mob/living/carbon/human/H)
+ if(!istype(H))
+ return
+ if(H.back)
+ back = H.back.type
+ if(H.wear_id)
+ id = H.wear_id.type
+ if(H.w_uniform)
+ uniform = H.w_uniform.type
+ if(H.wear_suit)
+ suit = H.wear_suit.type
+ if(H.wear_mask)
+ mask = H.wear_mask.type
+ if(H.wear_neck)
+ neck = H.wear_neck.type
+ if(H.head)
+ head = H.head.type
+ if(H.shoes)
+ shoes = H.shoes.type
+ if(H.gloves)
+ gloves = H.gloves.type
+ if(H.ears)
+ ears = H.ears.type
+ if(H.glasses)
+ glasses = H.glasses.type
+ if(H.belt)
+ belt = H.belt.type
+ return TRUE
diff --git a/code/modules/mob/living/carbon/human/dummy.dm b/code/modules/mob/living/carbon/human/dummy.dm
index 904b27adb9a..1b6c3a48fd1 100644
--- a/code/modules/mob/living/carbon/human/dummy.dm
+++ b/code/modules/mob/living/carbon/human/dummy.dm
@@ -47,3 +47,26 @@ GLOBAL_LIST_EMPTY(dummy_mob_list)
if(istype(D))
D.wipe_state()
D.in_use = FALSE
+
+//NSV13 - Roleplay Stuff
+/proc/generate_dummy_lookalike(slotkey, mob/target)
+ if(!istype(target))
+ return generate_or_wait_for_human_dummy(slotkey)
+
+ var/mob/living/carbon/human/dummy/copycat = generate_or_wait_for_human_dummy(slotkey)
+
+ if(iscarbon(target))
+ var/mob/living/carbon/carbon_target = target
+ carbon_target.dna.transfer_identity(copycat, transfer_SE = TRUE)
+
+ if(ishuman(target))
+ var/mob/living/carbon/human/human_target = target
+ human_target.copy_clothing_prefs(copycat)
+
+ copycat.updateappearance(icon_update=TRUE, mutcolor_update=TRUE, mutations_overlay_update=TRUE)
+ else
+ //even if target isn't a carbon, if they have a client we can make the
+ //dummy look like what their human would look like based on their prefs
+ target?.client?.prefs?.active_character.copy_to(copycat, icon_updates=TRUE, roundstart_checks=FALSE)
+
+ return copycat
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index 5ff1e7cc8aa..ad6d2a23d94 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -385,6 +385,12 @@
. += "Traits: [traitstring]"
//NSV13 - Roleplaying Records - Start
+ if(!skipface)
+ var/line = "Examine closely..."
+
+ if(line)
+ . += line
+
if(client && user.client.holder && isobserver(user))
var/line = ""
if(!(client.prefs.active_character.general_record == ""))
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index f29b1ca6252..39c2ebc0ade 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -162,6 +162,13 @@
to_chat(usr, "You can't reach that! Something is covering it.")
return
+ //NSV13 - Roleplaying Stuff
+ if(href_list["lookup_info"])
+ switch(href_list["lookup_info"])
+ if("open_examine_panel")
+ tgui.holder = src
+ tgui.ui_interact(usr) //datum has a tgui component, here we open the window
+
///////HUDs///////
if(href_list["hud"])
if(!ishuman(usr))
diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm
index 0d54786f75b..c80afa98bce 100644
--- a/code/modules/mob/living/carbon/human/human_defines.dm
+++ b/code/modules/mob/living/carbon/human/human_defines.dm
@@ -57,3 +57,6 @@
var/lastpuke = 0
var/last_fire_update
var/account_id
+
+ ///The Examine Panel TGUI. //NSV13
+ var/datum/examine_panel/tgui = new() //create the datum
diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm
index a1f6f5b3d17..69b2ba7d35d 100644
--- a/code/modules/mob/living/carbon/human/human_helpers.dm
+++ b/code/modules/mob/living/carbon/human/human_helpers.dm
@@ -205,3 +205,11 @@
return TRUE
if(isclothing(wear_mask) && (wear_mask.clothing_flags & SCAN_BOOZEPOWER))
return TRUE
+
+///copies over clothing preferences like underwear to another human //NSV13
+/mob/living/carbon/human/proc/copy_clothing_prefs(mob/living/carbon/human/destination)
+ destination.underwear = underwear
+ destination.underwear_color = underwear_color
+ destination.undershirt = undershirt
+ destination.socks = socks
+ destination.jumpsuit_style = jumpsuit_style
diff --git a/code/modules/mob/living/silicon/examine.dm b/code/modules/mob/living/silicon/examine.dm
index a8f0845e8a8..5a3d7207e4d 100644
--- a/code/modules/mob/living/silicon/examine.dm
+++ b/code/modules/mob/living/silicon/examine.dm
@@ -7,12 +7,7 @@
//NSV13 - Silicon Flavor Text - Start
if(client)
- var/line
- if(length(client.prefs.active_character.silicon_flavor_text))
- var/message = client.prefs.active_character.silicon_flavor_text
- if(length_char(message) <= 40)
- line = "[message]"
- else
- line = "[copytext_char(message, 1, 37)]... More..."
- . += line
+ var/line = "Examine closely..."
+ if(line)
+ . += line
//NS13 - Silicon Flavor Text - End
diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm
index 4c9716fb50b..28e49dc5146 100644
--- a/code/modules/mob/living/silicon/silicon.dm
+++ b/code/modules/mob/living/silicon/silicon.dm
@@ -55,6 +55,9 @@
mobchatspan = "centcom"
+ //NSV13 - Roleplay Stuff
+ var/datum/examine_panel/tgui = new() //create the datum
+
/mob/living/silicon/Initialize(mapload)
. = ..()
GLOB.silicon_mobs += src
@@ -233,11 +236,8 @@
//NSV13 - Silicon Flavor Text - Start
if(href_list["lookup_info"])
- if(client && length(client.prefs.active_character.silicon_flavor_text))
- var/datum/browser/popup = new(usr, "[name]'s flavor text", "[name]'s Flavor Text", 500, 200)
- popup.set_content(text("[][]", "[name]'s flavor text", replacetext(client.prefs.active_character.silicon_flavor_text, "\n", " ")))
- popup.open()
- return
+ tgui.holder = src
+ tgui.ui_interact(usr) //datum has a tgui component, here we open the window
//NSV13 - Silicon Flavor Text - End
return
diff --git a/nsv13.dme b/nsv13.dme
index c408c6765a5..d6f55ecb104 100644
--- a/nsv13.dme
+++ b/nsv13.dme
@@ -3827,6 +3827,7 @@
#include "nsv13\code\modules\mob\mob_helpers.dm"
#include "nsv13\code\modules\mob\dead\observer\oberserver.dm"
#include "nsv13\code\modules\mob\living\carbon\carbon.dm"
+#include "nsv13\code\modules\mob\living\carbon\examine_tgui.dm"
#include "nsv13\code\modules\mob\living\carbon\human\nsv_emotes.dm"
#include "nsv13\code\modules\mob\living\carbon\human\species_types\nanotrasen_knpc.dm"
#include "nsv13\code\modules\mob\living\carbon\human\species_types\other_knpc.dm"
diff --git a/nsv13/code/modules/mob/living/carbon/examine_tgui.dm b/nsv13/code/modules/mob/living/carbon/examine_tgui.dm
new file mode 100644
index 00000000000..e641469f62e
--- /dev/null
+++ b/nsv13/code/modules/mob/living/carbon/examine_tgui.dm
@@ -0,0 +1,52 @@
+/datum/examine_panel
+ /// Mob that the examine panel belongs to.
+ var/mob/living/holder
+ /// The screen containing the appearance of the mob
+ var/atom/movable/screen/examine_panel_screen/examine_panel_screen
+
+/datum/examine_panel/ui_state(mob/user)
+ return GLOB.always_state
+
+
+/datum/examine_panel/ui_close(mob/user)
+ user.client.clear_map(examine_panel_screen.assigned_map)
+
+
+/atom/movable/screen/examine_panel_screen
+ name = "examine panel screen"
+
+/datum/examine_panel/ui_interact(mob/user, datum/tgui/ui)
+ if(!examine_panel_screen)
+ examine_panel_screen = new
+ examine_panel_screen.name = "screen"
+ examine_panel_screen.assigned_map = "examine_panel_[REF(holder)]_map"
+ examine_panel_screen.del_on_map_removal = FALSE
+ examine_panel_screen.screen_loc = "[examine_panel_screen.assigned_map]:1,1"
+
+ var/mutable_appearance/current_mob_appearance = new(holder)
+ current_mob_appearance.setDir(SOUTH)
+ current_mob_appearance.transform = matrix() // We reset their rotation, in case they're lying down.
+
+ // In case they're pixel-shifted, we bring 'em back!
+ current_mob_appearance.pixel_x = 0
+ current_mob_appearance.pixel_y = 0
+
+ examine_panel_screen.cut_overlays()
+ examine_panel_screen.add_overlay(current_mob_appearance)
+
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ user.client.register_map_obj(examine_panel_screen)
+ ui = new(user, src, "ExaminePanel")
+ ui.open()
+
+/datum/examine_panel/ui_data(mob/user)
+ var/list/data = list()
+
+ var/flavor_text
+ if(issilicon(holder))
+ flavor_text = user.client.prefs.active_character.silicon_flavor_text
+ data["character_name"] = holder.name
+ data["assigned_map"] = examine_panel_screen.assigned_map
+ data["flavor_text"] = flavor_text
+ return data
diff --git a/tgui/packages/tgui/components/Box.tsx b/tgui/packages/tgui/components/Box.tsx
index 613ea47d708..2053f91e5c8 100644
--- a/tgui/packages/tgui/components/Box.tsx
+++ b/tgui/packages/tgui/components/Box.tsx
@@ -38,6 +38,7 @@ export interface BoxProps {
bold?: BooleanLike;
italic?: BooleanLike;
nowrap?: BooleanLike;
+ preserveWhitespace?: BooleanLike;
m?: string | BooleanLike;
mx?: string | BooleanLike;
my?: string | BooleanLike;
@@ -163,6 +164,7 @@ const styleMapperByPropName = {
bold: mapBooleanPropTo('font-weight', 'bold'),
italic: mapBooleanPropTo('font-style', 'italic'),
nowrap: mapBooleanPropTo('white-space', 'nowrap'),
+ preserveWhitespace: mapBooleanPropTo('white-space', 'pre'),
// Margins
m: mapDirectionalUnitPropTo('margin', halfUnit, [
'top', 'bottom', 'left', 'right',
diff --git a/tgui/packages/tgui/interfaces/ExaminePanel.js b/tgui/packages/tgui/interfaces/ExaminePanel.js
new file mode 100644
index 00000000000..a145a18831b
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/ExaminePanel.js
@@ -0,0 +1,46 @@
+import { useBackend } from '../backend';
+import { Stack, Section, ByondUi } from '../components';
+import { Window } from '../layouts';
+
+export const ExaminePanel = (props, context) => {
+ const { act, data } = useBackend(context);
+ const {
+ character_name,
+ assigned_map,
+ flavor_text,
+ } = data;
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+ {flavor_text}
+
+
+
+
+
+
+
+ );
+};
From 1d1c8817aa9d9ba9eb86572eadd8eb058f375c10 Mon Sep 17 00:00:00 2001
From: Bobbanz1
Date: Fri, 13 Jan 2023 17:59:06 +0100
Subject: [PATCH 05/15] Removed uncaught mention of background info
---
SQL/beestation_schema.sql | 1 -
1 file changed, 1 deletion(-)
diff --git a/SQL/beestation_schema.sql b/SQL/beestation_schema.sql
index 1a003d5ca1f..1ed5988b11f 100644
--- a/SQL/beestation_schema.sql
+++ b/SQL/beestation_schema.sql
@@ -121,7 +121,6 @@ CREATE TABLE IF NOT EXISTS `SS13_characters` (
`general_record` MEDIUMTEXT NOT NULL COLLATE 'utf8mb4_general_ci',
`security_record` MEDIUMTEXT NOT NULL COLLATE 'utf8mb4_general_ci',
`medical_record` MEDIUMTEXT NOT NULL COLLATE 'utf8mb4_general_ci',
- `background_info` MEDIUMTEXT NOT NULL COLLATE 'utf8mb4_general_ci',
PRIMARY KEY (`slot`, `ckey`) USING BTREE
) COLLATE='utf8mb4_general_ci' ENGINE=InnoDB;
From 08d388080095d0b6f47e5f76bc8eec38df97a0bf Mon Sep 17 00:00:00 2001
From: Bobbanz1
Date: Fri, 13 Jan 2023 18:48:32 +0100
Subject: [PATCH 06/15] Attempts to incorporate the flavor text with the
examine panel
---
code/datums/dna.dm | 5 ++--
code/modules/client/preferences.dm | 10 ++++---
code/modules/client/verbs/looc.dm | 29 +------------------
code/modules/mob/living/carbon/carbon.dm | 6 ----
.../mob/living/carbon/human/examine.dm | 12 --------
code/modules/mob/mob.dm | 6 ----
.../modules/mob/living/carbon/examine_tgui.dm | 8 +++++
7 files changed, 17 insertions(+), 59 deletions(-)
diff --git a/code/datums/dna.dm b/code/datums/dna.dm
index 12d5e72895a..e72e480e4b5 100644
--- a/code/datums/dna.dm
+++ b/code/datums/dna.dm
@@ -40,7 +40,7 @@
return ..()
-/datum/dna/proc/transfer_identity(mob/living/carbon/destination, transfer_SE = FALSE)
+/datum/dna/proc/transfer_identity(mob/living/carbon/human/destination, transfer_SE = FALSE)
if(!istype(destination))
return
destination.dna.unique_enzymes = unique_enzymes
@@ -51,7 +51,7 @@
destination.dna.features = features.Copy()
destination.dna.real_name = real_name
destination.dna.temporary_mutations = temporary_mutations.Copy()
- destination.flavour_text = destination.dna.features["flavour_text"] //Update the flavor_text to use new dna text //NSV13
+ destination.flavour_text = destination.client.prefs.active_character.flavor_text //Update the flavor_text to use new dna text //NSV13
if(transfer_SE)
destination.dna.mutation_index = mutation_index
destination.dna.default_mutation_genes = default_mutation_genes
@@ -348,7 +348,6 @@
//Do not use force_transfer_mutations for stuff like cloners without some precautions, otherwise some conditional mutations could break (timers, drill hat etc)
if(newfeatures)
dna.features = newfeatures
- flavour_text = dna.features["flavour_text"] //Update the flavor_text to use new dna text //NSV13
if(mrace)
var/datum/species/newrace = new mrace.type
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 7fd67131f90..0cdd22667f6 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -832,7 +832,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "
Flavor Text
"
dat += "
"
- dat += "Set Flavor Text"
+ dat += "Set Flavor Text "
if(length(active_character.flavor_text) <= 40)
if(!length(active_character.flavor_text))
dat += "\[...\]"
@@ -841,7 +841,9 @@ GLOBAL_LIST_EMPTY(preferences_datums)
else
dat += "[copytext_char(active_character.flavor_text, 1, 40)]... "
- dat += "Set Silicon Examine Text"
+ dat += " "
+
+ dat += "Set Silicon Examine Text "
if(length(active_character.silicon_flavor_text) <= 40)
if(!length(active_character.silicon_flavor_text))
dat += "\[...\]"
@@ -1779,9 +1781,9 @@ GLOBAL_LIST_EMPTY(preferences_datums)
C.select_syndie_role()
//NSV13 - Roleplay Stuff
if("flavor_text")
- var/msg = capped_multiline_input(usr, "Set the flavor text for your 'examine' verb.\nThe rules are the following;\nNo Memes.\nNothing that people can't see at a glance.\nNothing that's Out Of Character.\nNothing that breaks the game.", "Flavor Text", active_character.flavor_text)
+ var/msg = input(usr, "Set the flavor text for your 'examine' verb.\nThe rules are the following;\nNo Memes.\nNothing that people can't see at a glance.\nNothing that's Out Of Character.\nNothing that breaks the game.", "Flavor Text", active_character.flavor_text)
if(msg)
- active_character.flavor_text = html_decode(strip_html(msg))
+ active_character.flavor_text = html_decode(strip_html_simple(msg))
if("silicon_flavor_text")
var/msg = input(usr, "Set the flavor text in your 'examine' verb. This is for describing what people can tell by looking at your character.", "Silicon Flavor Text", active_character.silicon_flavor_text) as message|null
diff --git a/code/modules/client/verbs/looc.dm b/code/modules/client/verbs/looc.dm
index 2c1b824f4ab..556e2be0b2b 100644
--- a/code/modules/client/verbs/looc.dm
+++ b/code/modules/client/verbs/looc.dm
@@ -103,34 +103,7 @@
////////////////////FLAVOUR TEXT NSV13////////////////////
/mob
var/flavour_text = ""
-
-/mob/proc/update_flavor_text()
- set src in usr
-
- if(usr != src)
- usr << "No."
- var/msg = sanitize(input(usr,"Set the flavor text in your 'examine' verb. Can also be used for OOC notes about your character.","Flavour Text",html_decode(flavour_text)) as message|null)
-
- if(msg)
- msg = copytext(msg, 1, MAX_MESSAGE_LEN)
- msg = html_encode(msg)
-
- flavour_text = msg
-
-/mob/proc/warn_flavor_changed()
- if(flavour_text && flavour_text != "") // don't spam people that don't use it!
- src << "
OOC Warning:
"
- src << "Your flavor text is likely out of date! Change"
-
-/mob/proc/print_flavor_text()
- if(flavour_text && flavour_text != "")
- var/msg = replacetext(flavour_text, "\n", " ")
- if(length(msg) <= 100)
- return "[msg]"
- else
- return "[copytext(msg, 1, 97)]... More..."
-
-//Needed for LOOC and flavour text
+//NSV13 - flavour text - Don't think this thing actually does anything - END
/mob/proc/get_top_level_mob()
if(istype(src.loc,/mob)&&src.loc!=src)
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 2047ae49b93..65d3221101b 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -983,9 +983,3 @@
if(mood)
if(mood.sanity < SANITY_UNSTABLE)
return TRUE
-
-//NSV13
-/mob/living/carbon/proc/update_flavor_text_feature(new_text)
- if(!dna)
- return
- dna.features["flavour_text"] = new_text
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index 04923e57d4f..ad6d2a23d94 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -384,18 +384,6 @@
else if(isobserver(user) && traitstring)
. += "Traits: [traitstring]"
- //NSV13 START
- //No flavor text unless the face can be seen. Prevents certain metagaming with impersonation.
- var/invisible_man = skipface || get_visible_name() == "Unknown"
- if(invisible_man)
- . += "...?"
- else
- var/flavor = print_flavor_text()
- if(flavor)
- . += flavor
- //NSV13 STOP
-
-
//NSV13 - Roleplaying Records - Start
if(!skipface)
var/line = "Examine closely..."
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index b61752df2cc..a8ba283a1e8 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -746,12 +746,6 @@
unset_machine()
src << browse(null, t1)
- //NSV13 START
- if(href_list["flavor_more"])
- usr << browse(text("[][]", name, replacetext(flavour_text, "\n", " ")), text("window=[];size=500x200", name))
- onclose(usr, "[name]")
- //NSV13 STOP
-
if(href_list["item"] && usr.canUseTopic(src, BE_CLOSE, NO_DEXTERY))
var/slot = text2num(href_list["item"])
var/hand_index = text2num(href_list["hand_index"])
diff --git a/nsv13/code/modules/mob/living/carbon/examine_tgui.dm b/nsv13/code/modules/mob/living/carbon/examine_tgui.dm
index e641469f62e..e0297e3a57e 100644
--- a/nsv13/code/modules/mob/living/carbon/examine_tgui.dm
+++ b/nsv13/code/modules/mob/living/carbon/examine_tgui.dm
@@ -44,8 +44,16 @@
var/list/data = list()
var/flavor_text
+ var/obscured
+
if(issilicon(holder))
flavor_text = user.client.prefs.active_character.silicon_flavor_text
+
+ if(ishuman(holder))
+ var/mob/living/carbon/human/holder_human = holder
+ obscured = (holder_human.wear_mask && (holder_human.wear_mask.flags_inv & HIDEFACE)) || (holder_human.head && (holder_human.head.flags_inv & HIDEFACE))
+ flavor_text = obscured ? "Obscured" : holder_human.flavour_text
+
data["character_name"] = holder.name
data["assigned_map"] = examine_panel_screen.assigned_map
data["flavor_text"] = flavor_text
From 0f3b5338b72f43484e4ace6e751585b26fe4d7a6 Mon Sep 17 00:00:00 2001
From: Bobbanz1
Date: Fri, 13 Jan 2023 19:44:39 +0100
Subject: [PATCH 07/15] More stuff
---
code/modules/client/preferences.dm | 2 +-
code/modules/mob/living/carbon/human/human.dm | 2 +-
.../modules/mob/living/carbon/examine_tgui.dm | 5 ++++-
tgui/packages/tgui/interfaces/ExaminePanel.js | 22 +++++++++++--------
4 files changed, 19 insertions(+), 12 deletions(-)
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 0cdd22667f6..0c8b5668838 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -1781,7 +1781,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
C.select_syndie_role()
//NSV13 - Roleplay Stuff
if("flavor_text")
- var/msg = input(usr, "Set the flavor text for your 'examine' verb.\nThe rules are the following;\nNo Memes.\nNothing that people can't see at a glance.\nNothing that's Out Of Character.\nNothing that breaks the game.", "Flavor Text", active_character.flavor_text)
+ var/msg = input(usr, "Set the flavor text for your 'examine' verb.\nThe rules are the following;\nNo Memes.\nNothing that people can't see at a glance.\nNothing that's Out Of Character.\nNothing that breaks the game.", "Flavor Text", active_character.flavor_text) as message|null
if(msg)
active_character.flavor_text = html_decode(strip_html_simple(msg))
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 39c2ebc0ade..78b83b38d1c 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -328,7 +328,7 @@
to_chat(usr, "Added by [c.author] at [c.time]")
to_chat(usr, "----------")
to_chat(usr, "Notes: [sec_record.fields["notes"]]")
- to_chat(usr, " Security Record:[sec_record.fields["past_records"]]")
+ to_chat(usr, " Security Record: [sec_record.fields["past_records"]]")
return
if(href_list["genrecords"])
diff --git a/nsv13/code/modules/mob/living/carbon/examine_tgui.dm b/nsv13/code/modules/mob/living/carbon/examine_tgui.dm
index e0297e3a57e..9dbb9c97951 100644
--- a/nsv13/code/modules/mob/living/carbon/examine_tgui.dm
+++ b/nsv13/code/modules/mob/living/carbon/examine_tgui.dm
@@ -54,7 +54,10 @@
obscured = (holder_human.wear_mask && (holder_human.wear_mask.flags_inv & HIDEFACE)) || (holder_human.head && (holder_human.head.flags_inv & HIDEFACE))
flavor_text = obscured ? "Obscured" : holder_human.flavour_text
- data["character_name"] = holder.name
+ var/name = obscured ? "Unknown" : holder.name
+
+ data["obscured"] = obscured ? TRUE : FALSE
+ data["character_name"] = name
data["assigned_map"] = examine_panel_screen.assigned_map
data["flavor_text"] = flavor_text
return data
diff --git a/tgui/packages/tgui/interfaces/ExaminePanel.js b/tgui/packages/tgui/interfaces/ExaminePanel.js
index a145a18831b..801feed38b3 100644
--- a/tgui/packages/tgui/interfaces/ExaminePanel.js
+++ b/tgui/packages/tgui/interfaces/ExaminePanel.js
@@ -6,6 +6,7 @@ export const ExaminePanel = (props, context) => {
const { act, data } = useBackend(context);
const {
character_name,
+ obscured,
assigned_map,
flavor_text,
} = data;
@@ -17,16 +18,19 @@ export const ExaminePanel = (props, context) => {
theme="admin">
-
+
-
+ {!obscured
+ && (
+
+ )}
From ceeb69ef36cc108898cd00bb582661ecc6343fb8 Mon Sep 17 00:00:00 2001
From: Bobbanz1 <59128051+Bobbanz1@users.noreply.github.com>
Date: Sat, 4 Feb 2023 21:18:57 +0100
Subject: [PATCH 08/15] One FUCK UP
---
code/modules/client/preferences2/character_save.dm | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/code/modules/client/preferences2/character_save.dm b/code/modules/client/preferences2/character_save.dm
index f23cac186c3..60276445bc3 100644
--- a/code/modules/client/preferences2/character_save.dm
+++ b/code/modules/client/preferences2/character_save.dm
@@ -361,7 +361,7 @@
preferred_squad,
preferred_pilot_role,
flavor_text,
- silicon_flavor_text
+ silicon_flavor_text,
general_record,
security_record,
medical_record,
From f22fa832bd9186e1cce9fbf8e2b893939c5a6e77 Mon Sep 17 00:00:00 2001
From: Bobbanz1 <59128051+Bobbanz1@users.noreply.github.com>
Date: Sat, 4 Feb 2023 21:35:29 +0100
Subject: [PATCH 09/15] Sensitive SQL stuff
---
code/modules/client/preferences2/character_save.dm | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/code/modules/client/preferences2/character_save.dm b/code/modules/client/preferences2/character_save.dm
index 60276445bc3..dd1c0d17577 100644
--- a/code/modules/client/preferences2/character_save.dm
+++ b/code/modules/client/preferences2/character_save.dm
@@ -364,7 +364,7 @@
silicon_flavor_text,
general_record,
security_record,
- medical_record,
+ medical_record
) VALUES (
:slot,
:ckey,
From 88f6bb36cb02e592f09fa25675805ed9a08a9890 Mon Sep 17 00:00:00 2001
From: Bobbanz1
Date: Sat, 15 Jul 2023 19:59:32 +0200
Subject: [PATCH 10/15] Fixes some issues that were discovered in the test
merge. That's all the review stuff done!
---
code/datums/datacore.dm | 6 ++--
code/datums/outfit.dm | 33 -------------------
.../mob/living/carbon/human/examine.dm | 12 -------
tgui/packages/tgui/components/Box.tsx | 4 +--
tgui/packages/tgui/interfaces/ExaminePanel.js | 5 ++-
5 files changed, 9 insertions(+), 51 deletions(-)
diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm
index 82974d87127..34a71559d57 100644
--- a/code/datums/datacore.dm
+++ b/code/datums/datacore.dm
@@ -263,7 +263,7 @@
G.fields["photo_front"] = photo_front
G.fields["photo_side"] = photo_side
//NSV13 - Roleplaying Records General Records - Start
- if(C && C.prefs.active_character && C.prefs.active_character.general_record)
+ if(C?.prefs?.active_character?.general_record)
G.fields["past_records"] = C.prefs.active_character.general_record
else
G.fields["past_records"] = ""
@@ -286,7 +286,7 @@
M.fields["cdi_d"] = "No diseases have been diagnosed at the moment."
M.fields["notes"] = "No notes."
//NSV13 - Roleplaying Records Medical Records - Start
- if(C && C.prefs.active_character && C.prefs.active_character.medical_record)
+ if(C?.prefs?.active_character?.medical_record)
M.fields["past_records"] = C.prefs.active_character.medical_record
else
M.fields["past_records"] = ""
@@ -302,7 +302,7 @@
S.fields["crim"] = list()
S.fields["notes"] = "No notes."
//NSV13 - Roleplaying Records Security Records - Start
- if(C && C.prefs.active_character && C.prefs.active_character.security_record)
+ if(C?.prefs?.active_character?.security_record)
S.fields["past_records"] = C.prefs.active_character.security_record
else
S.fields["past_records"] = ""
diff --git a/code/datums/outfit.dm b/code/datums/outfit.dm
index c369392f0e1..b9a4a18cea6 100755
--- a/code/datums/outfit.dm
+++ b/code/datums/outfit.dm
@@ -359,36 +359,3 @@
implants += imptype
accessory = text2path(outfit_data["accessory"])
return TRUE
-
-//NSV13
-/**
- * Copies the outfit from a human to itself.
- **/
-/datum/outfit/proc/copy_outfit_from_target(mob/living/carbon/human/H)
- if(!istype(H))
- return
- if(H.back)
- back = H.back.type
- if(H.wear_id)
- id = H.wear_id.type
- if(H.w_uniform)
- uniform = H.w_uniform.type
- if(H.wear_suit)
- suit = H.wear_suit.type
- if(H.wear_mask)
- mask = H.wear_mask.type
- if(H.wear_neck)
- neck = H.wear_neck.type
- if(H.head)
- head = H.head.type
- if(H.shoes)
- shoes = H.shoes.type
- if(H.gloves)
- gloves = H.gloves.type
- if(H.ears)
- ears = H.ears.type
- if(H.glasses)
- glasses = H.glasses.type
- if(H.belt)
- belt = H.belt.type
- return TRUE
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index ad6d2a23d94..6d8e78bf809 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -391,18 +391,6 @@
if(line)
. += line
- if(client && user.client.holder && isobserver(user))
- var/line = ""
- if(!(client.prefs.active_character.general_record == ""))
- line += "\[GEN\]"
- if(!(client.prefs.active_character.security_record == ""))
- line += "\[SEC\]"
- if(!(client.prefs.active_character.medical_record == ""))
- line += "\[MED\]"
-
- if(!(line == ""))
- . += "*---------*"
- . += line
//NSV13 - Roleplaying Records - End
. += "*---------*"
diff --git a/tgui/packages/tgui/components/Box.tsx b/tgui/packages/tgui/components/Box.tsx
index 2053f91e5c8..8714306afc2 100644
--- a/tgui/packages/tgui/components/Box.tsx
+++ b/tgui/packages/tgui/components/Box.tsx
@@ -38,7 +38,7 @@ export interface BoxProps {
bold?: BooleanLike;
italic?: BooleanLike;
nowrap?: BooleanLike;
- preserveWhitespace?: BooleanLike;
+ preserveWhitespace?: BooleanLike; // NSV13 - Roleplaying Flavor Text
m?: string | BooleanLike;
mx?: string | BooleanLike;
my?: string | BooleanLike;
@@ -164,7 +164,7 @@ const styleMapperByPropName = {
bold: mapBooleanPropTo('font-weight', 'bold'),
italic: mapBooleanPropTo('font-style', 'italic'),
nowrap: mapBooleanPropTo('white-space', 'nowrap'),
- preserveWhitespace: mapBooleanPropTo('white-space', 'pre'),
+ preserveWhitespace: mapBooleanPropTo('white-space', 'pre-wrap'), // NSV13 - Roleplaying Flavor Text
// Margins
m: mapDirectionalUnitPropTo('margin', halfUnit, [
'top', 'bottom', 'left', 'right',
diff --git a/tgui/packages/tgui/interfaces/ExaminePanel.js b/tgui/packages/tgui/interfaces/ExaminePanel.js
index 801feed38b3..98202988ea4 100644
--- a/tgui/packages/tgui/interfaces/ExaminePanel.js
+++ b/tgui/packages/tgui/interfaces/ExaminePanel.js
@@ -36,7 +36,10 @@ export const ExaminePanel = (props, context) => {
-
{flavor_text}
From 49a2589ccacda0cf730f09778498f26203f99901 Mon Sep 17 00:00:00 2001
From: Bobbanz1
Date: Wed, 26 Jul 2023 20:26:45 +0200
Subject: [PATCH 11/15] PULL DAH LEVER KRONK
---
SQL/beestation_schema.sql | 1 +
code/__DEFINES/antagonists.dm | 5 +
code/__DEFINES/preferences.dm | 6 +-
code/__DEFINES/role_preferences.dm | 238 ++++++++++++++----
code/__HELPERS/game.dm | 43 ++--
code/_globalvars/lists/poll_ignore.dm | 61 ++---
code/controllers/subsystem/job.dm | 7 +-
code/controllers/subsystem/pai.dm | 6 +-
code/datums/brain_damage/imaginary_friend.dm | 4 +-
code/datums/brain_damage/split_personality.dm | 4 +-
code/datums/diseases/transformation.dm | 5 +-
code/game/gamemodes/brother/traitor_bro.dm | 4 +-
code/game/gamemodes/changeling/changeling.dm | 19 +-
.../game/gamemodes/changeling/traitor_chan.dm | 21 +-
code/game/gamemodes/clock_cult/clockcult.dm | 6 +-
code/game/gamemodes/cult/cult.dm | 6 +-
code/game/gamemodes/devil/devil_game_mode.dm | 6 +-
code/game/gamemodes/dynamic/dynamic.dm | 9 -
.../gamemodes/dynamic/dynamic_rulesets.dm | 26 +-
.../dynamic/dynamic_rulesets_latejoin.dm | 31 +--
.../dynamic/dynamic_rulesets_midround.dm | 51 ++--
.../dynamic/dynamic_rulesets_roundstart.dm | 41 ++-
.../gamemodes/dynamic/dynamic_simulations.dm | 5 -
code/game/gamemodes/dynamic/readme.md | 1 -
.../gamemodes/eldritch_cult/eldritch_cult.dm | 6 +-
code/game/gamemodes/game_mode.dm | 92 ++++---
code/game/gamemodes/gangs/gangs.dm | 4 +-
code/game/gamemodes/hivemind/hivemind.dm | 6 +-
code/game/gamemodes/incursion/incursion.dm | 9 +-
code/game/gamemodes/nuclear/nuclear.dm | 8 +-
code/game/gamemodes/overthrow/overthrow.dm | 5 +-
code/game/gamemodes/revolution/revolution.dm | 6 +-
code/game/gamemodes/traitor/double_agents.dm | 4 +-
code/game/gamemodes/traitor/traitor.dm | 19 +-
code/game/gamemodes/wizard/wizard.dm | 6 +-
code/game/machinery/cloning.dm | 2 +-
.../machinery/porta_turret/portable_turret.dm | 4 +-
code/game/objects/effects/anomalies.dm | 2 +-
code/game/objects/items/holy_weapons.dm | 2 +-
.../objects/structures/ghost_role_spawners.dm | 118 +--------
code/game/objects/structures/spawner.dm | 2 +-
code/modules/admin/antag_panel.dm | 16 +-
code/modules/admin/fun_balloon.dm | 2 +-
code/modules/admin/secrets.dm | 4 +-
code/modules/admin/sql_ban_system.dm | 40 ++-
code/modules/admin/verbs/one_click_antag.dm | 41 ++-
code/modules/admin/verbs/randomverbs.dm | 4 +-
.../antagonists/_common/antag_datum.dm | 18 +-
.../antagonists/_common/antag_spawner.dm | 8 +-
code/modules/antagonists/abductor/abductor.dm | 3 +-
.../antagonists/ashwalker/ashwalker.dm | 2 +-
code/modules/antagonists/blob/blob.dm | 2 +-
code/modules/antagonists/blob/blob_mobs.dm | 4 +-
.../blob/blobstrains/explosive_lattice.dm | 2 +-
code/modules/antagonists/blob/overmind.dm | 4 +-
code/modules/antagonists/blob/powers.dm | 8 +-
.../antagonists/blob/structures/_blob.dm | 2 +-
.../blood_contract/blood_contract.dm | 2 +
.../antagonists/brainwashing/brainwashing.dm | 2 +-
code/modules/antagonists/brother/brother.dm | 10 +-
.../antagonists/changeling/changeling.dm | 3 +-
.../antagonists/changeling/powers/teratoma.dm | 2 +-
.../antagonists/changeling/teratoma.dm | 3 +-
.../antagonists/clock_cult/mobs/cogscarab.dm | 5 -
.../scriptures/sigil_of_vitality.dm | 2 +-
.../clock_cult/scriptures/summon_marauder.dm | 2 +-
.../clock_cult/servant_of_ratvar.dm | 3 +-
.../clock_cult/structure/eminence_beacon.dm | 2 +-
code/modules/antagonists/creep/creep.dm | 2 +-
code/modules/antagonists/cult/cult.dm | 3 +-
code/modules/antagonists/cult/cult_comms.dm | 2 +-
code/modules/antagonists/cult/runes.dm | 2 +-
code/modules/antagonists/devil/devil.dm | 2 +-
code/modules/antagonists/devil/imp/imp.dm | 1 +
.../devil/sintouched/sintouched.dm | 1 +
.../eldritch_cult/eldritch_antag.dm | 3 +-
.../eldritch_cult/eldritch_monster_antag.dm | 2 +-
code/modules/antagonists/ert/ert.dm | 1 +
code/modules/antagonists/gang/gang.dm | 2 +-
.../antagonists/greentext/greentext.dm | 1 +
code/modules/antagonists/guardian/guardian.dm | 1 +
.../antagonists/highlander/highlander.dm | 1 +
code/modules/antagonists/hivemind/hivemind.dm | 5 +-
code/modules/antagonists/hivemind/vessel.dm | 4 +-
.../antagonists/incursion/incursion.dm | 12 +-
.../antagonists/magic_servant/servant.dm | 1 +
code/modules/antagonists/morph/morph.dm | 2 +-
code/modules/antagonists/morph/morph_antag.dm | 1 +
code/modules/antagonists/ninja/ninja.dm | 2 +-
code/modules/antagonists/nukeop/nukeop.dm | 5 +-
code/modules/antagonists/official/official.dm | 1 +
.../antagonists/overthrow/overthrow.dm | 2 +-
code/modules/antagonists/pirate/pirate.dm | 2 +-
code/modules/antagonists/revenant/revenant.dm | 2 +-
.../antagonists/revenant/revenant_antag.dm | 1 +
.../revenant/revenant_spawn_event.dm | 2 +-
.../antagonists/revolution/revolution.dm | 7 +-
.../role_preference/_role_preference.dm | 27 ++
.../role_preference/role_antagonists.dm | 43 ++++
.../role_preference/role_changeling.dm | 3 +
.../role_preference/role_midrounds.dm | 69 +++++
.../role_preference/role_operative.dm | 7 +
.../role_preference/role_traitor.dm | 7 +
.../role_preference/role_wizard.dm | 7 +
.../roundstart_special/special_antagonist.dm | 11 +-
code/modules/antagonists/santa/santa.dm | 1 +
.../antagonists/separatist/separatist.dm | 1 +
.../antagonists/slaughter/slaughter_antag.dm | 2 +-
.../antagonists/slaughter/slaughterevent.dm | 2 +-
.../antagonists/survivalist/survivalist.dm | 1 +
.../antagonists/traitor/datum_traitor.dm | 8 +-
.../traitor/equipment/contractor.dm | 2 +-
.../antagonists/traitor/traitor_spawner.dm | 6 +-
.../antagonists/valentines/heartbreaker.dm | 1 +
.../antagonists/valentines/valentine.dm | 1 +
.../antagonists/wishgranter/wishgranter.dm | 1 +
.../antagonists/wizard/equipment/soulstone.dm | 2 +-
code/modules/antagonists/wizard/wizard.dm | 7 +-
code/modules/antagonists/xeno/xeno.dm | 2 +-
code/modules/awaymissions/corpse.dm | 80 ++----
.../awaymissions/mission_code/Academy.dm | 7 +-
.../awaymissions/mission_code/snowdin.dm | 2 +-
code/modules/client/preferences.dm | 169 +++++++++----
.../client/preferences2/character_save.dm | 23 +-
.../client/preferences2/preferences2.dm | 16 +-
code/modules/client/preferences_toggles.dm | 9 -
code/modules/clothing/outfits/vr.dm | 2 +-
code/modules/events/abductor.dm | 2 +-
code/modules/events/alien_infestation.dm | 2 +-
code/modules/events/blob.dm | 2 +-
code/modules/events/creep_awakening.dm | 2 +-
code/modules/events/devil.dm | 2 +-
code/modules/events/fugitive_spawning.dm | 2 +-
code/modules/events/ghost_role.dm | 4 +-
code/modules/events/holiday/xmas.dm | 2 +-
code/modules/events/nightmare.dm | 2 +-
code/modules/events/operative.dm | 2 +-
code/modules/events/pirates.dm | 2 +-
code/modules/events/sentience.dm | 2 +-
code/modules/events/space_dragon.dm | 2 +-
code/modules/events/special_antag_event.dm | 15 +-
code/modules/events/wizard/imposter.dm | 2 +-
.../food_and_drinks/food/snacks_meat.dm | 2 +-
code/modules/guardian/guardian.dm | 4 +-
code/modules/guardian/guardianbuilder.dm | 2 +-
code/modules/guardian/standarrow.dm | 2 +-
code/modules/jobs/jobs.dm | 2 +-
.../modules/mob/dead/new_player/new_player.dm | 4 +-
.../mob/dead/observer/notificationprefs.dm | 53 ----
code/modules/mob/living/carbon/alien/alien.dm | 2 +-
.../modules/mob/living/carbon/alien/organs.dm | 4 +-
.../carbon/alien/special/alien_embryo.dm | 2 +-
code/modules/mob/living/living_sentience.dm | 17 +-
.../modules/mob/living/silicon/robot/robot.dm | 2 +-
.../living/simple_animal/bot/SuperBeepsky.dm | 2 +-
.../friendly/drone/drones_as_items.dm | 6 -
.../friendly/drone/extra_drone_types.dm | 2 +-
.../living/simple_animal/guardian/guardian.dm | 4 +-
.../mob/living/simple_animal/hostile/alien.dm | 2 +-
.../mob/living/simple_animal/hostile/carp.dm | 2 +-
.../hostile/mining_mobs/elites/elite.dm | 2 +-
.../living/simple_animal/hostile/syndicate.dm | 4 +-
.../living/simple_animal/hostile/wizard.dm | 2 +-
.../mob/living/simple_animal/slime/slime.dm | 2 +-
code/modules/mob/mob_helpers.dm | 6 +-
code/modules/ninja/ninja_event.dm | 2 +-
code/modules/projectiles/projectile/magic.dm | 6 +-
code/modules/religion/rites.dm | 6 +-
.../xenobiology/crossbreeding/warping.dm | 2 +-
.../research/xenobiology/xenobiology.dm | 2 +-
code/modules/ruins/lavaland_ruin_code.dm | 3 +-
.../ruins/spaceruin_code/hilbertshotel.dm | 1 +
.../objective_types/assassination.dm | 2 +-
.../objective_types/vip_extraction.dm | 2 +-
code/modules/shuttle/syndicate.dm | 2 +-
code/modules/unit_tests/_unit_tests.dm | 2 +
code/modules/unit_tests/antag_datums.dm | 15 ++
.../unit_tests/dynamic_ruleset_sanity.dm | 11 +
code/modules/unit_tests/gamemode_sanity.dm | 20 ++
.../traits/xenoartifact_minors.dm | 3 +-
config/dbconfig.txt | 4 +-
config/dynamic.json | 19 +-
html/admin/banpanel.css | 18 +-
nsv13.dme | 9 +-
nsv13/code/game/gamemodes/bloodling.dm | 31 +--
nsv13/code/game/gamemodes/pvp/pvp.dm | 4 +-
nsv13/code/game/gamemodes/pvp/roles.dm | 6 +-
.../spawners/custom_ghost_role_spawners.dm | 2 +-
nsv13/code/modules/antagonists/bloodling.dm | 3 +-
.../role_preference/role_antagonists.dm | 7 +
nsv13/code/modules/cargo/objective_cargo.dm | 2 +-
.../overmap/boarding/ghost_role_spawners.dm | 22 ++
.../interfaces/NotificationPreferences.js | 41 ---
193 files changed, 1197 insertions(+), 914 deletions(-)
create mode 100644 code/modules/antagonists/role_preference/_role_preference.dm
create mode 100644 code/modules/antagonists/role_preference/role_antagonists.dm
create mode 100644 code/modules/antagonists/role_preference/role_changeling.dm
create mode 100644 code/modules/antagonists/role_preference/role_midrounds.dm
create mode 100644 code/modules/antagonists/role_preference/role_operative.dm
create mode 100644 code/modules/antagonists/role_preference/role_traitor.dm
create mode 100644 code/modules/antagonists/role_preference/role_wizard.dm
delete mode 100644 code/modules/mob/dead/observer/notificationprefs.dm
create mode 100644 code/modules/unit_tests/antag_datums.dm
create mode 100644 code/modules/unit_tests/gamemode_sanity.dm
create mode 100644 nsv13/code/modules/antagonists/role_preference/role_antagonists.dm
delete mode 100644 tgui/packages/tgui/interfaces/NotificationPreferences.js
diff --git a/SQL/beestation_schema.sql b/SQL/beestation_schema.sql
index 632d928b17a..ea6af3a19df 100644
--- a/SQL/beestation_schema.sql
+++ b/SQL/beestation_schema.sql
@@ -122,6 +122,7 @@ CREATE TABLE IF NOT EXISTS `SS13_characters` (
`general_record` MEDIUMTEXT NOT NULL COLLATE 'utf8mb4_general_ci',
`security_record` MEDIUMTEXT NOT NULL COLLATE 'utf8mb4_general_ci',
`medical_record` MEDIUMTEXT NOT NULL COLLATE 'utf8mb4_general_ci',
+ `role_preferences` MEDIUMTEXT NOT NULL COLLATE 'utf8mb4_general_ci',
PRIMARY KEY (`slot`, `ckey`) USING BTREE
) COLLATE='utf8mb4_general_ci' ENGINE=InnoDB;
diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm
index 6620df43f48..93f62654284 100644
--- a/code/__DEFINES/antagonists.dm
+++ b/code/__DEFINES/antagonists.dm
@@ -76,6 +76,11 @@
#define IS_HERETIC(mob) (mob.mind?.has_antag_datum(/datum/antagonist/heretic))
#define IS_HERETIC_MONSTER(mob) (mob.mind?.has_antag_datum(/datum/antagonist/heretic_monster))
+#define FACTION_SYNDICATE "Syndicate"
+#define FACTION_BLOB "Blob"
+#define FACTION_ALIEN "Xenomorph"
+#define FACTION_WIZARD "Wizard"
+
#define PATH_SIDE "Side"
#define PATH_ASH "Ash"
diff --git a/code/__DEFINES/preferences.dm b/code/__DEFINES/preferences.dm
index 003ccf3e3db..7fc49bbf376 100644
--- a/code/__DEFINES/preferences.dm
+++ b/code/__DEFINES/preferences.dm
@@ -6,7 +6,7 @@
#define PREFTOGGLE_SOUND_LOBBY (1<<3)
#define PREFTOGGLE_MEMBER_PUBLIC (1<<4)
#define PREFTOGGLE_INTENT_STYLE (1<<5)
-#define PREFTOGGLE_MIDROUND_ANTAG (1<<6)
+//#define PREFTOGGLE_MIDROUND_ANTAG (1<<6)
#define PREFTOGGLE_SOUND_INSTRUMENTS (1<<7)
#define PREFTOGGLE_SOUND_SHIP_AMBIENCE (1<<8)
#define PREFTOGGLE_SOUND_PRAYERS (1<<9)
@@ -27,7 +27,7 @@
#define PREFTOGGLE_RUNECHAT_NONMOBS (1<<22)
#define PREFTOGGLE_RUNECHAT_EMOTES (1<<23)
-#define TOGGLES_DEFAULT (PREFTOGGLE_SOUND_ADMINHELP|PREFTOGGLE_SOUND_MIDI|PREFTOGGLE_SOUND_AMBIENCE|PREFTOGGLE_SOUND_LOBBY|PREFTOGGLE_MEMBER_PUBLIC|PREFTOGGLE_INTENT_STYLE|PREFTOGGLE_MIDROUND_ANTAG|PREFTOGGLE_SOUND_INSTRUMENTS|PREFTOGGLE_SOUND_SHIP_AMBIENCE|PREFTOGGLE_SOUND_PRAYERS|PREFTOGGLE_SOUND_ANNOUNCEMENTS|PREFTOGGLE_OUTLINE_ENABLED|PREFTOGGLE_RUNECHAT_GLOBAL|PREFTOGGLE_RUNECHAT_NONMOBS|PREFTOGGLE_RUNECHAT_EMOTES)
+#define TOGGLES_DEFAULT (PREFTOGGLE_SOUND_ADMINHELP|PREFTOGGLE_SOUND_MIDI|PREFTOGGLE_SOUND_AMBIENCE|PREFTOGGLE_SOUND_LOBBY|PREFTOGGLE_MEMBER_PUBLIC|PREFTOGGLE_INTENT_STYLE|PREFTOGGLE_SOUND_INSTRUMENTS|PREFTOGGLE_SOUND_SHIP_AMBIENCE|PREFTOGGLE_SOUND_PRAYERS|PREFTOGGLE_SOUND_ANNOUNCEMENTS|PREFTOGGLE_OUTLINE_ENABLED|PREFTOGGLE_RUNECHAT_GLOBAL|PREFTOGGLE_RUNECHAT_NONMOBS|PREFTOGGLE_RUNECHAT_EMOTES)
// You CANNOT go above 1<<23 in BYOND due to integer limits
// Please add subsequent ones as PREFTOGGLE_2_[name]
@@ -183,7 +183,7 @@
#define PREFERENCE_TAG_PDA_COLOUR "23"
#define PREFERENCE_TAG_KEYBINDS "24"
#define PREFERENCE_TAG_PURCHASED_GEAR "25"
-#define PREFERENCE_TAG_BE_SPECIAL "26"
+#define PREFERENCE_TAG_ROLE_PREFERENCES "26"
#define PREFERENCE_TAG_PREFERRED_SYNDIE_ROLE "27" //NSV13 - syndicate crew role
// True value of max save slots (3 is default, 8 is byond member, +1 to either if you have the extra slot loadout entry). Potential max is 9
diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm
index c5ba51036ad..b670a0de4c5 100644
--- a/code/__DEFINES/role_preferences.dm
+++ b/code/__DEFINES/role_preferences.dm
@@ -4,21 +4,21 @@
+// Banning snowflake - global antag ban. Does not include ghost roles that aren't antagonists or forced antagonists
+#define BAN_ROLE_ALL_ANTAGONISTS "All Antagonists"
+
//These are synced with the Database, if you change the values of the defines
//then you MUST update the database!
-#define ROLE_SYNDICATE "Syndicate"
#define ROLE_TRAITOR "Traitor"
-#define ROLE_OPERATIVE "Operative"
+#define ROLE_OPERATIVE "Nuclear Operative"
#define ROLE_CHANGELING "Changeling"
#define ROLE_WIZARD "Wizard"
-#define ROLE_MALF "Malf AI"
+//#define ROLE_MALF "Malf AI" // Currently under traitor datum, so we can't have this separate.
#define ROLE_INCURSION "Incursion Team"
#define ROLE_EXCOMM "Excommunicated Syndicate Agent"
#define ROLE_REV "Revolutionary"
#define ROLE_REV_HEAD "Head Revolutionary"
-#define ROLE_REV_SUCCESSFUL "Victorious Revolutionary"
#define ROLE_ALIEN "Xenomorph"
-#define ROLE_PAI "pAI"
#define ROLE_CULTIST "Cultist"
#define ROLE_SERVANT_OF_RATVAR "Servant of Ratvar"
#define ROLE_HERETIC "Heretic"
@@ -28,66 +28,218 @@
#define ROLE_REVENANT "Revenant"
#define ROLE_DEVIL "Devil"
#define ROLE_BROTHER "Blood Brother"
-#define ROLE_BRAINWASHED "Brainwashed Victim"
#define ROLE_OVERTHROW "Syndicate Mutineer"
#define ROLE_HIVE "Hivemind Host"
-#define ROLE_HIVE_VESSEL "Awakened Vessel"
#define ROLE_OBSESSED "Obsessed"
-#define ROLE_SENTIENCE "Sentience Potion Spawn"
-#define ROLE_MIND_TRANSFER "Mind Transfer Potion"
-#define ROLE_POSIBRAIN "Posibrain"
-#define ROLE_DRONE "Drone"
-#define ROLE_DEATHSQUAD "Deathsquad"
-#define ROLE_LAVALAND "Lavaland"
+#define ROLE_SPACE_DRAGON "Space Dragon"
#define ROLE_INTERNAL_AFFAIRS "Internal Affairs Agent"
#define ROLE_GANG "Gangster"
#define ROLE_HOLOPARASITE "Holoparasite"
#define ROLE_TERATOMA "Teratoma"
-
+#define ROLE_MORPH "Morph"
+#define ROLE_NIGHTMARE "Nightmare"
+#define ROLE_SPACE_PIRATE "Space Pirate"
#define ROLE_SYNDI_CREW "Syndicate crew" //Nsv13 - added pvp role
#define ROLE_BLOODLING "Bloodling" //Nsv13 - Bloodling
#define ROLE_GHOSTSHIP "Ghost Ship" //NSV13 - Playable "NPC" ships
-#define ROLE_EXPERIMENTAL_CLONE "Experimental Clone"
+#define ROLE_SLAUGHTER_DEMON "Slaughter Demon"
+#define ROLE_CONTRACTOR_SUPPORT_UNIT "Contractor Support Unit"
+#define ROLE_PYRO_SLIME "Pyroclastic Anomaly Slime"
-//Missing assignment means it's not a gamemode specific role, IT'S NOT A BUG OR ERROR.
-//The gamemode specific ones are just so the gamemodes can query whether a player is old enough
-//(in game days played) to play that role
-GLOBAL_LIST_INIT(special_roles, list(
- ROLE_TRAITOR = /datum/game_mode/traitor,
- ROLE_BROTHER = /datum/game_mode/traitor/bros,
- ROLE_INCURSION = /datum/game_mode/incursion,
- ROLE_EXCOMM = /datum/game_mode/incursion,
- ROLE_OPERATIVE = /datum/game_mode/nuclear,
- ROLE_CHANGELING = /datum/game_mode/changeling,
- ROLE_WIZARD = /datum/game_mode/wizard,
- ROLE_MALF,
- ROLE_REV = /datum/game_mode/revolution,
+/// Roles that are antagonists, roundstart or not, and have passes to do.. antagonistry
+GLOBAL_LIST_INIT(antagonist_bannable_roles, list(
+ ROLE_TRAITOR,
+ ROLE_OPERATIVE,
+ ROLE_CHANGELING,
+ ROLE_WIZARD,
+// ROLE_MALF,
+ ROLE_INCURSION,
+ ROLE_EXCOMM,
+ ROLE_REV,
+ ROLE_REV_HEAD,
ROLE_ALIEN,
- ROLE_PAI,
- ROLE_CULTIST = /datum/game_mode/cult,
- ROLE_SERVANT_OF_RATVAR = /datum/game_mode/clockcult,
+ ROLE_CULTIST,
+ ROLE_SERVANT_OF_RATVAR,
+ ROLE_HERETIC,
ROLE_BLOB,
ROLE_NINJA,
- ROLE_OBSESSED,
- ROLE_REVENANT,
ROLE_ABDUCTOR,
- ROLE_DEVIL = /datum/game_mode/devil,
- ROLE_OVERTHROW = /datum/game_mode/overthrow,
- ROLE_HIVE = /datum/game_mode/hivemind,
- ROLE_INTERNAL_AFFAIRS = /datum/game_mode/traitor/internal_affairs,
- ROLE_SENTIENCE,
- ROLE_GANG = /datum/game_mode/gang,
+ ROLE_REVENANT,
+ ROLE_DEVIL,
+ ROLE_BROTHER,
+ ROLE_OVERTHROW,
+ ROLE_HIVE,
+ ROLE_OBSESSED,
+ ROLE_SPACE_DRAGON,
+ ROLE_INTERNAL_AFFAIRS,
+ ROLE_GANG,
ROLE_HOLOPARASITE,
- ROLE_HERETIC = /datum/game_mode/heretics,
- ROLE_SYNDI_CREW = /datum/game_mode/pvp, //NSV13
- ROLE_BLOODLING = /datum/game_mode/bloodling, //NSV13
+ ROLE_MORPH,
+ ROLE_NIGHTMARE,
+ ROLE_SPACE_PIRATE,
+ ROLE_SYNDI_CREW, //NSV13
+ ROLE_BLOODLING, //NSV13
ROLE_GHOSTSHIP, //NSV13
- ROLE_TERATOMA
+ ROLE_TERATOMA,
+ ROLE_SLAUGHTER_DEMON,
+ ROLE_CONTRACTOR_SUPPORT_UNIT,
))
//nsv13 - pvp + bloodling modes added here
+#define BAN_ROLE_FORCED_ANTAGONISTS "Forced Antagonists"
+
+#define ROLE_BRAINWASHED "Brainwashed Victim"
+#define ROLE_HYPNOTIZED "Hypnotized Victim"
+#define ROLE_HIVE_VESSEL "Awakened Vessel"
+
+/// Forced antagonist roles
+GLOBAL_LIST_INIT(forced_bannable_roles, list(
+ ROLE_BRAINWASHED,
+ ROLE_HYPNOTIZED,
+ ROLE_HIVE_VESSEL,
+))
+
+#define BAN_ROLE_ALL_GHOST "Non-Antagonist Ghost Roles"
+
+#define ROLE_PAI "pAI"
+#define ROLE_POSIBRAIN "Posibrain"
+#define ROLE_DRONE "Drone"
+#define ROLE_SENTIENCE "Sentience Potion Spawn"
+#define ROLE_EXPERIMENTAL_CLONE "Experimental Clone"
+#define ROLE_LAVALAND_ELITE "Lavaland Elite"
+#define ROLE_SPECTRAL_BLADE "Spectral Blade"
+#define ROLE_ASHWALKER "Ashwalker"
+#define ROLE_LIFEBRINGER "Lifebringer"
+#define ROLE_FREE_GOLEM "Free Golem"
+#define ROLE_HERMIT "Hermit"
+#define ROLE_TRANSLOCATED_VET "Translocated Vet"
+#define ROLE_LAVALAND_ESCAPED_PRISONER "Lavaland Escaped Prisoner"
+#define ROLE_BEACH_BUM "Beach Bum"
+#define ROLE_HOTEL_STAFF "Hotel Staff"
+#define ROLE_LAVALAND_SYNDICATE "Lavaland Syndicate"
+#define ROLE_DEMONIC_FRIEND "Demonic Friend"
+#define ROLE_ANCIENT_CREW "Ancient Crew"
+#define ROLE_SKELETAL_REMAINS "Skeletal Remains"
+#define ROLE_SENTIENT_ANIMAL "Sentient Animal"
+#define ROLE_HOLY_SUMMONED "Holy Summoned"
+#define ROLE_SURVIVALIST "Exploration Survivalist"
+#define ROLE_EXPLORATION_VIP "Exploration VIP"
+#define ROLE_SENTIENT_XENOARTIFACT "Sentient Xenoartifiact"
+
+/// Any ghost role that is not really an antagonist or doesn't antagonize (lavaland, sentience potion, etc)
+GLOBAL_LIST_INIT(ghost_role_bannable_roles, list(
+ ROLE_PAI,
+ ROLE_POSIBRAIN,
+ ROLE_DRONE,
+ ROLE_SENTIENCE,
+ ROLE_EXPERIMENTAL_CLONE,
+ ROLE_LAVALAND_ELITE,
+ ROLE_SPECTRAL_BLADE,
+ ROLE_ASHWALKER,
+ ROLE_LIFEBRINGER,
+ ROLE_FREE_GOLEM,
+ ROLE_HERMIT,
+ ROLE_TRANSLOCATED_VET,
+ ROLE_LAVALAND_ESCAPED_PRISONER,
+ ROLE_BEACH_BUM,
+ ROLE_HOTEL_STAFF,
+ ROLE_LAVALAND_SYNDICATE,
+ ROLE_DEMONIC_FRIEND,
+ ROLE_ANCIENT_CREW,
+ ROLE_SKELETAL_REMAINS,
+ ROLE_SENTIENT_ANIMAL,
+ ROLE_HOLY_SUMMONED,
+))
+
+#define ROLE_IMAGINARY_FRIEND "Imaginary Friend"
+#define ROLE_SPLIT_PERSONALITY "Split Personality"
+#define ROLE_MIND_TRANSFER "Mind Transfer Potion"
+#define ROLE_ERT "Emergency Response Team"
+
+/// Other roles that don't really fit any of the above, and probably shouldn't be banned with the others as a group
+/// Little to no impact on anything
+GLOBAL_LIST_INIT(other_bannable_roles, list(
+ ROLE_IMAGINARY_FRIEND,
+ ROLE_SPLIT_PERSONALITY,
+ ROLE_MIND_TRANSFER,
+ ROLE_ERT,
+))
+
+/// Do not ban this role. Oh my god. Please.
+#define UNBANNABLE_ANTAGONIST "Unbannable"
+
+/client/proc/role_preference_enabled(role_preference_key)
+ if(!ispath(role_preference_key, /datum/role_preference))
+ CRASH("Invalid role_preference_key [role_preference_key] passed to role_preference_enabled!")
+ if(!src.prefs)
+ return FALSE
+ var/list/source = src.prefs.role_preferences
+ var/datum/role_preference/pref = role_preference_key
+ if(initial(pref.per_character))
+ source = src.prefs.active_character.role_preferences_character
+ var/role_preference_value = source["[role_preference_key]"]
+ if(isnum(role_preference_value) && !role_preference_value) // explicitly disabled and not null
+ return FALSE
+ return TRUE
+
+/// If the client given is fit for a given role based on the arguments passed
+/// banning_key: ROLE_X used for this role - to check if the player is banned.
+/// role_preference_key: The /datum/role_preference typepath to check if the player has the role enabled and would like to receive the poll.
+/// poll_ignore_key: The POLL_IGNORE_X define for this role, used for temporarily disabling ghost polls for high volume roles.
+/// req_hours: The amount of living hours required to receive this role.
+/// feedback: if we should send a to_chat
+/client/proc/should_include_for_role(banning_key = BAN_ROLE_ALL_ANTAGONISTS, role_preference_key = null, poll_ignore_key = null, req_hours = 0, feedback = FALSE)
+ if(QDELETED(src) || (poll_ignore_key && GLOB.poll_ignore[poll_ignore_key] && (src.ckey in GLOB.poll_ignore[poll_ignore_key])))
+ return FALSE
+ if(role_preference_key)
+ if(!ispath(role_preference_key, /datum/role_preference))
+ CRASH("Invalid role_preference_key [role_preference_key] passed to should_include_for_role!")
+ if(!src.role_preference_enabled(role_preference_key))
+ return FALSE
+ if(banning_key)
+ if(is_banned_from(src.ckey, banning_key))
+ if(feedback)
+ to_chat(src, "You are banned from this role!")
+ return FALSE
+ if(req_hours) //minimum living hour count
+ if((src.get_exp_living(TRUE)/60) < req_hours)
+ if(feedback)
+ to_chat(src, "You do not have enough living hours to take this role ([req_hours]hrs required)!")
+ return FALSE
+ return TRUE
+
+/client/proc/can_take_ghost_spawner(banning_key = BAN_ROLE_ALL_ANTAGONISTS, use_cooldown = TRUE, is_ghost_role = FALSE, is_admin_spawned = FALSE)
+ if(!istype(src))
+ return FALSE
+ if(is_ghost_role && !(GLOB.ghost_role_flags & GHOSTROLE_SPAWNER) && !is_admin_spawned)
+ to_chat(src, "An admin has temporarily disabled non-admin ghost roles!")
+ return FALSE
+ if(!src.should_include_for_role(
+ banning_key = banning_key,
+ feedback = TRUE
+ ))
+ return FALSE
+ if(use_cooldown && src.next_ghost_role_tick > world.time)
+ to_chat(src, "You have died recently, you must wait [(src.next_ghost_role_tick - world.time)/10] seconds until you can use a ghost spawner.")
+ return FALSE
+ return TRUE
+
//Job defines for what happens when you fail to qualify for any job during job selection
#define BEOVERFLOW 1
#define BERANDOMJOB 2
#define RETURNTOLOBBY 3
+
+#define ROLE_PREFERENCE_CATEGORY_ANAGONIST "Antagonists"
+#define ROLE_PREFERENCE_CATEGORY_MIDROUND_LIVING "Midrounds (Living)"
+#define ROLE_PREFERENCE_CATEGORY_MIDROUND_GHOST "Midrounds (Ghost Poll)"
+
+GLOBAL_LIST_INIT(role_preference_entries, init_role_preference_entries())
+
+/proc/init_role_preference_entries()
+ var/list/output = list()
+ for (var/datum/role_preference/preference_type as anything in subtypesof(/datum/role_preference))
+ if (initial(preference_type.abstract_type) == preference_type)
+ continue
+ output[preference_type] = new preference_type
+ return output
diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm
index dae5cf88e73..89c70e94cc6 100644
--- a/code/__HELPERS/game.dm
+++ b/code/__HELPERS/game.dm
@@ -425,7 +425,7 @@
else
candidates -= M
-/proc/pollGhostCandidates(Question, jobbanType, datum/game_mode/gametypeCheck, be_special_flag = 0, poll_time = 300, ignore_category = null, flashwindow = TRUE, req_hours = 0)
+/proc/pollGhostCandidates(Question, jobbanType, role_preference_key, poll_time = 300, ignore_category = null, flashwindow = TRUE, req_hours = 0)
var/list/candidates = list()
if(!(GLOB.ghost_role_flags & GHOSTROLE_STATION_SENTIENCE))
return candidates
@@ -433,31 +433,30 @@
for(var/mob/dead/observer/G in GLOB.player_list)
candidates += G
- return pollCandidates(Question, jobbanType, gametypeCheck, be_special_flag, poll_time, ignore_category, flashwindow, candidates, req_hours)
+ return pollCandidates(Question, jobbanType, role_preference_key, poll_time, ignore_category, flashwindow, candidates, req_hours)
-/proc/pollCandidates(Question, jobbanType, datum/game_mode/gametypeCheck, be_special_flag = 0, poll_time = 300, ignore_category = null, flashwindow = TRUE, list/group = null, req_hours = 0)
+/proc/pollCandidates(Question, banning_key, role_preference_key = null, poll_time = 300, poll_ignore_key = null, flashwindow = TRUE, list/group = null, req_hours = 0)
var/time_passed = world.time
if (!Question)
Question = "Would you like to be a special role?"
+ if(isnull(poll_ignore_key)) // FALSE will not put one, no matter what
+ if(role_preference_key)
+ poll_ignore_key = "role_[role_preference_key]"
+ else if(banning_key)
+ poll_ignore_key = "ban_[role_preference_key]"
var/list/result = list()
for(var/m in group)
var/mob/M = m
- if(!M.key || !M.client || (ignore_category && GLOB.poll_ignore[ignore_category] && (M.ckey in GLOB.poll_ignore[ignore_category])))
+ if(QDELETED(M) || !M.key || !M.client)
continue
- if(be_special_flag)
- if(!(M.client.prefs) || !(be_special_flag in M.client.prefs.be_special))
- continue
- if(gametypeCheck)
- if(!gametypeCheck.age_check(M.client))
- continue
- if(jobbanType)
- if(QDELETED(M) || is_banned_from(M.ckey, list(jobbanType, ROLE_SYNDICATE)))
- continue
- if(req_hours) //minimum living hour count
- if((M.client.get_exp_living(TRUE)/60) < req_hours)
- continue
-
- showCandidatePollWindow(M, poll_time, Question, result, ignore_category, time_passed, flashwindow)
+ if(!M.client.should_include_for_role(
+ banning_key = banning_key,
+ role_preference_key = role_preference_key,
+ poll_ignore_key = poll_ignore_key,
+ req_hours = req_hours
+ ))
+ continue
+ showCandidatePollWindow(M, poll_time, Question, result, poll_ignore_key, time_passed, flashwindow)
sleep(poll_time)
//Check all our candidates, to make sure they didn't log off or get deleted during the wait period.
@@ -469,14 +468,14 @@
return result
-/proc/pollCandidatesForMob(Question, jobbanType, datum/game_mode/gametypeCheck, be_special_flag = 0, poll_time = 300, mob/M, ignore_category = null)
- var/list/L = pollGhostCandidates(Question, jobbanType, gametypeCheck, be_special_flag, poll_time, ignore_category)
+/proc/pollCandidatesForMob(Question, jobbanType, role_preference_key, poll_time = 300, mob/M, ignore_category = null)
+ var/list/L = pollGhostCandidates(Question, jobbanType, role_preference_key, poll_time, ignore_category)
if(QDELETED(M) || !M.loc)
return list()
return L
-/proc/pollCandidatesForMobs(Question, jobbanType, datum/game_mode/gametypeCheck, be_special_flag = 0, poll_time = 300, list/mobs, ignore_category = null)
- var/list/L = pollGhostCandidates(Question, jobbanType, gametypeCheck, be_special_flag, poll_time, ignore_category)
+/proc/pollCandidatesForMobs(Question, jobbanType, role_preference_key, poll_time = 300, list/mobs, ignore_category = null)
+ var/list/L = pollGhostCandidates(Question, jobbanType, role_preference_key, poll_time, ignore_category)
var/i=1
for(var/v in mobs)
var/atom/A = v
diff --git a/code/_globalvars/lists/poll_ignore.dm b/code/_globalvars/lists/poll_ignore.dm
index 6f15e22d270..1cca65374b0 100644
--- a/code/_globalvars/lists/poll_ignore.dm
+++ b/code/_globalvars/lists/poll_ignore.dm
@@ -1,57 +1,42 @@
//Each lists stores ckeys for "Never for this round" option category
-#define POLL_IGNORE_SENTIENCE_POTION "sentience_potion"
-#define POLL_IGNORE_POSSESSED_BLADE "possessed_blade"
#define POLL_IGNORE_ALIEN_LARVA "alien_larva"
-#define POLL_IGNORE_SYNDICATE "syndicate"
-#define POLL_IGNORE_HOLOPARASITE "holoparasite"
#define POLL_IGNORE_POSIBRAIN "posibrain"
-#define POLL_IGNORE_SPECTRAL_BLADE "spectral_blade"
-#define POLL_IGNORE_CONSTRUCT "construct"
#define POLL_IGNORE_SPIDER "spider"
#define POLL_IGNORE_ASHWALKER "ashwalker"
+#define POLL_IGNORE_BLOB_HELPER "blob_helper"
+#define POLL_IGNORE_CLOCKWORK_HELPER "clockwork_helper"
+#define POLL_IGNORE_CULT_SHADE "cult_shade"
#define POLL_IGNORE_GOLEM "golem"
-#define POLL_IGNORE_SWARMER "swarmer"
#define POLL_IGNORE_DRONE "drone"
-#define POLL_IGNORE_FUGITIVE "fugitive"
-#define POLL_IGNORE_DEFECTIVECLONE "defective_clone"
-#define POLL_IGNORE_PYROSLIME "slime"
+#define POLL_IGNORE_SWARMER "swarmer"
+#define POLL_IGNORE_SPECTRAL_BLADE "spectral_blade"
#define POLL_IGNORE_SHADE "shade"
-#define POLL_IGNORE_IMAGINARYFRIEND "imaginary_friend"
+#define POLL_IGNORE_FUGITIVE "fugitive"
#define POLL_IGNORE_SPLITPERSONALITY "split_personality"
-#define POLL_IGNORE_CONTRACTOR_SUPPORT "contractor_support"
-#define POLL_IGNORE_CLOCKWORK "clockwork"
#define POLL_IGNORE_GHOSTSHIP "ghost ships" //NSV13
-#define POLL_IGNORE_EXPERIMENTAL_CLONE "experimental_clone"
+#define POLL_IGNORE_WIZARD_HELPER "wizard_helper"
-GLOBAL_LIST_INIT(poll_ignore_desc, list(
- POLL_IGNORE_SENTIENCE_POTION = "Sentience potion",
- POLL_IGNORE_POSSESSED_BLADE = "Possessed blade",
- POLL_IGNORE_ALIEN_LARVA = "Xenomorph larva",
- POLL_IGNORE_SYNDICATE = "Syndicate",
- POLL_IGNORE_HOLOPARASITE = "Holoparasite",
- POLL_IGNORE_POSIBRAIN = "Positronic brain",
- POLL_IGNORE_SPECTRAL_BLADE = "Spectral blade",
- POLL_IGNORE_CONSTRUCT = "Construct",
- POLL_IGNORE_SPIDER = "Spiders",
- POLL_IGNORE_ASHWALKER = "Ashwalker eggs",
- POLL_IGNORE_GOLEM = "Golems",
- POLL_IGNORE_SWARMER = "Swarmer shells",
- POLL_IGNORE_DRONE = "Drone shells",
- POLL_IGNORE_FUGITIVE = "Fugitive Hunter",
- POLL_IGNORE_DEFECTIVECLONE = "Defective clone",
- POLL_IGNORE_PYROSLIME = "Slime",
- POLL_IGNORE_SHADE = "Shade",
- POLL_IGNORE_IMAGINARYFRIEND = "Imaginary Friend",
- POLL_IGNORE_SPLITPERSONALITY = "Split Personality",
- POLL_IGNORE_CONTRACTOR_SUPPORT = "Contractor Support Unit",
- POLL_IGNORE_GHOSTSHIP = "Ghost Ship", //NSV13
- POLL_IGNORE_EXPERIMENTAL_CLONE = "Experimental clone"
+GLOBAL_LIST_INIT(poll_ignore_list, list(
+ POLL_IGNORE_ALIEN_LARVA,
+ POLL_IGNORE_ASHWALKER,
+ POLL_IGNORE_BLOB_HELPER,
+ POLL_IGNORE_CLOCKWORK_HELPER,
+ POLL_IGNORE_CULT_SHADE,
+ POLL_IGNORE_GOLEM,
+ POLL_IGNORE_DRONE,
+ POLL_IGNORE_POSIBRAIN,
+ POLL_IGNORE_SPECTRAL_BLADE,
+ POLL_IGNORE_SHADE,
+ POLL_IGNORE_SPIDER,
+ POLL_IGNORE_GHOSTSHIP, //NSV13
+ POLL_IGNORE_WIZARD_HELPER,
))
+
GLOBAL_LIST_INIT(poll_ignore, init_poll_ignore())
/proc/init_poll_ignore()
. = list()
- for (var/k in GLOB.poll_ignore_desc)
+ for (var/k in GLOB.poll_ignore_list)
.[k] = list()
diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm
index bd62bf9d98e..41a29447708 100644
--- a/code/controllers/subsystem/job.dm
+++ b/code/controllers/subsystem/job.dm
@@ -137,8 +137,8 @@ SUBSYSTEM_DEF(job)
return FALSE
job.current_positions = max(0, job.current_positions - 1)
-/datum/controller/subsystem/job/proc/FindOccupationCandidates(datum/job/job, level, flag)
- JobDebug("Running FOC, Job: [job], Level: [level], Flag: [flag]")
+/datum/controller/subsystem/job/proc/FindOccupationCandidates(datum/job/job, level)
+ JobDebug("Running FOC, Job: [job], Level: [level]")
var/list/candidates = list()
for(var/mob/dead/new_player/player in unassigned)
if(QDELETED(player) || is_banned_from(player.ckey, job.title))
@@ -150,9 +150,6 @@ SUBSYSTEM_DEF(job)
if(job.required_playtime_remaining(player.client))
JobDebug("FOC player not enough xp, Player: [player]")
continue
- if(flag && (!(flag in player.client.prefs.be_special)))
- JobDebug("FOC flag failed, Player: [player], Flag: [flag], ")
- continue
if(player.mind && (job.title in player.mind.restricted_roles))
JobDebug("FOC incompatible with antagonist role, Player: [player]")
continue
diff --git a/code/controllers/subsystem/pai.dm b/code/controllers/subsystem/pai.dm
index d942dda58bd..4fc3090979d 100644
--- a/code/controllers/subsystem/pai.dm
+++ b/code/controllers/subsystem/pai.dm
@@ -149,8 +149,10 @@ SUBSYSTEM_DEF(pai)
for(var/mob/dead/observer/G in GLOB.player_list)
if(!G.key || !G.client)
continue
- if(!(ROLE_PAI in G.client.prefs.be_special))
- continue
+ //NSV13 - Disabled until Beemerge, I don't know what to put here without porting from another PR so WEH
+ //if(!(ROLE_PAI in G.client.prefs.be_special))
+ // continue
+ //NSV13 - Stop
to_chat(G, "[user] is requesting a pAI personality! Use the pAI button to submit yourself as one.")
addtimer(CALLBACK(src, PROC_REF(spam_again)), spam_delay)
var/list/available = list()
diff --git a/code/datums/brain_damage/imaginary_friend.dm b/code/datums/brain_damage/imaginary_friend.dm
index b77bd799465..ad30ac75041 100644
--- a/code/datums/brain_damage/imaginary_friend.dm
+++ b/code/datums/brain_damage/imaginary_friend.dm
@@ -46,7 +46,7 @@
if(owner.stat == DEAD || !owner.mind)
qdel(src)
return
- var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner]'s imaginary friend?", ROLE_PAI, null, null, 75, friend, POLL_IGNORE_IMAGINARYFRIEND)
+ var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner]'s imaginary friend?", ROLE_IMAGINARY_FRIEND, null, 7.5 SECONDS, friend)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
friend.key = C.key
@@ -193,7 +193,7 @@
hearers += client
if(owner_chat_map)
hearers += owner.client
-
+
var/rendered = "[name][say_quote(message)]"
var/dead_rendered = "[name] (Imaginary friend of [owner])[say_quote(message)]"
diff --git a/code/datums/brain_damage/split_personality.dm b/code/datums/brain_damage/split_personality.dm
index b2ebc6c1899..c5a8a5fd4fd 100644
--- a/code/datums/brain_damage/split_personality.dm
+++ b/code/datums/brain_damage/split_personality.dm
@@ -31,7 +31,7 @@
if(owner.stat == DEAD || !owner.mind)
qdel(src)
return
- var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner]'s split personality?", ROLE_PAI, null, null, 75, stranger_backseat, POLL_IGNORE_SPLITPERSONALITY)
+ var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner]'s split personality?", ROLE_SPLIT_PERSONALITY, null, 7.5 SECONDS, stranger_backseat)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
stranger_backseat.key = C.key
@@ -196,7 +196,7 @@
/datum/brain_trauma/severe/split_personality/brainwashing/get_ghost()
set waitfor = FALSE
- var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner]'s brainwashed mind?", null, null, null, 75, stranger_backseat)
+ var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner]'s brainwashed mind?", ROLE_TRAITOR, null, 7.5 SECONDS, stranger_backseat, ignore_category = FALSE)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
stranger_backseat.key = C.key
diff --git a/code/datums/diseases/transformation.dm b/code/datums/diseases/transformation.dm
index b60bedb1a3e..218d0255411 100644
--- a/code/datums/diseases/transformation.dm
+++ b/code/datums/diseases/transformation.dm
@@ -80,10 +80,11 @@
/datum/disease/transformation/proc/replace_banned_player(var/mob/living/new_mob) // This can run well after the mob has been transferred, so need a handle on the new mob to kill it if needed.
set waitfor = FALSE
+ affected_mob.playable_bantype = bantype
affected_mob.ghostize(TRUE,SENTIENCE_FORCE)
to_chat(affected_mob, "Your mob has been taken over by a ghost! Appeal your job ban if you want to avoid this in the future!")
- var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [affected_mob.name]?", bantype, null, bantype, 50, affected_mob)
+ var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [affected_mob.name]?", bantype, null, 7.5 SECONDS, affected_mob, ignore_category = FALSE)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(affected_mob)]) to replace a jobbanned player.")
@@ -108,7 +109,7 @@
stage5 = list("Your skin feels as if it's about to burst off!")
new_form = /mob/living/silicon/robot
infectable_biotypes = list(MOB_ORGANIC, MOB_UNDEAD, MOB_ROBOTIC)
- bantype = "Cyborg"
+ bantype = JOB_NAME_CYBORG
/datum/disease/transformation/robot/stage_act()
..()
diff --git a/code/game/gamemodes/brother/traitor_bro.dm b/code/game/gamemodes/brother/traitor_bro.dm
index 6059dba2a14..2ba9c586359 100644
--- a/code/game/gamemodes/brother/traitor_bro.dm
+++ b/code/game/gamemodes/brother/traitor_bro.dm
@@ -27,7 +27,7 @@
if(CONFIG_GET(flag/protect_heads_from_antagonist))
restricted_jobs += GLOB.command_positions
- var/list/datum/mind/possible_brothers = get_players_for_role(ROLE_BROTHER)
+ var/list/datum/mind/possible_brothers = get_players_for_role(/datum/antagonist/brother, /datum/role_preference/antagonist/blood_brother)
var/num_teams = team_amount
var/bsc = CONFIG_GET(number/brother_scaling_coeff)
@@ -40,7 +40,7 @@
var/datum/team/brother_team/team = new
var/team_size = prob(10) ? min(3, possible_brothers.len) : 2
for(var/k = 1 to team_size)
- var/datum/mind/bro = antag_pick(possible_brothers, ROLE_BROTHER)
+ var/datum/mind/bro = antag_pick(possible_brothers, /datum/role_preference/antagonist/blood_brother)
possible_brothers -= bro
antag_candidates -= bro
team.add_member(bro)
diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm
index 884e9025c74..49b9cdcf0c9 100644
--- a/code/game/gamemodes/changeling/changeling.dm
+++ b/code/game/gamemodes/changeling/changeling.dm
@@ -10,7 +10,8 @@ GLOBAL_LIST_INIT(slot2type, list("head" = /obj/item/clothing/head/changeling, "w
name = "changeling"
config_tag = "changeling"
report_type = "changeling"
- antag_flag = ROLE_CHANGELING
+ role_preference = /datum/role_preference/antagonist/changeling
+ antag_datum = /datum/antagonist/changeling
false_report_weight = 10
restricted_jobs = list(JOB_NAME_AI, JOB_NAME_CYBORG)
protected_jobs = list(JOB_NAME_SECURITYOFFICER, JOB_NAME_WARDEN, JOB_NAME_DETECTIVE, JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN)
@@ -52,7 +53,7 @@ GLOBAL_LIST_INIT(slot2type, list("head" = /obj/item/clothing/head/changeling, "w
for(var/i = 0, i < num_changelings, i++)
if(!antag_candidates.len)
break
- var/datum/mind/changeling = antag_pick(antag_candidates, ROLE_CHANGELING)
+ var/datum/mind/changeling = antag_pick(antag_candidates, /datum/role_preference/antagonist/changeling)
antag_candidates -= changeling
changelings += changeling
changeling.special_role = ROLE_CHANGELING
@@ -75,12 +76,14 @@ GLOBAL_LIST_INIT(slot2type, list("head" = /obj/item/clothing/head/changeling, "w
if(changelings.len >= changelingcap) //Caps number of latejoin antagonists
return
if(changelings.len <= (changelingcap - 2) || prob(100 - (csc * 2)))
- if(ROLE_CHANGELING in character.client.prefs.be_special)
- if(!is_banned_from(character.ckey, list(ROLE_CHANGELING, ROLE_SYNDICATE)) && !QDELETED(character))
- if(age_check(character.client))
- if(!(character.job in restricted_jobs))
- character.mind.make_Changeling()
- changelings += character.mind
+ if(!QDELETED(character) && character.client?.should_include_for_role(
+ banning_key = initial(antag_datum.banning_key),
+ role_preference_key = role_preference,
+ req_hours = initial(antag_datum.required_living_playtime)
+ ))
+ if(!(character.job in restricted_jobs))
+ character.mind.make_Changeling()
+ changelings += character.mind
/datum/game_mode/changeling/generate_report()
return "The Gorlex Marauders have announced the successful raid and destruction of Central Command containment ship #S-[rand(1111, 9999)]. This ship housed only a single prisoner - \
diff --git a/code/game/gamemodes/changeling/traitor_chan.dm b/code/game/gamemodes/changeling/traitor_chan.dm
index 95057675495..6912af56cbf 100644
--- a/code/game/gamemodes/changeling/traitor_chan.dm
+++ b/code/game/gamemodes/changeling/traitor_chan.dm
@@ -22,7 +22,7 @@
/datum/game_mode/traitor/changeling/can_start()
if(!..())
return 0
- possible_changelings = get_players_for_role(ROLE_CHANGELING)
+ possible_changelings = get_players_for_role(/datum/antagonist/changeling, /datum/role_preference/antagonist/changeling)
if(possible_changelings.len < required_enemies)
return 0
return 1
@@ -37,7 +37,7 @@
if(CONFIG_GET(flag/protect_heads_from_antagonist))
restricted_jobs += GLOB.command_positions
- var/list/datum/mind/possible_changelings = get_players_for_role(ROLE_CHANGELING)
+ var/list/datum/mind/possible_changelings = get_players_for_role(/datum/antagonist/changeling, /datum/role_preference/antagonist/changeling)
var/num_changelings = 1
@@ -51,7 +51,7 @@
for(var/j = 0, j < num_changelings, j++)
if(!possible_changelings.len)
break
- var/datum/mind/changeling = antag_pick(possible_changelings, ROLE_CHANGELING)
+ var/datum/mind/changeling = antag_pick(possible_changelings, /datum/role_preference/antagonist/changeling)
antag_candidates -= changeling
possible_changelings -= changeling
changeling.special_role = ROLE_CHANGELING
@@ -72,13 +72,16 @@
if(changelings.len >= changelingcap) //Caps number of latejoin antagonists
..()
return
+ var/datum/antagonist/aux_antag_datum = /datum/antagonist/changeling
if(changelings.len <= (changelingcap - 2) || prob(100 / (csc * 4)))
- if(ROLE_CHANGELING in character.client.prefs.be_special)
- if(!is_banned_from(character.ckey, list(ROLE_CHANGELING, ROLE_SYNDICATE)) && !QDELETED(character))
- if(age_check(character.client))
- if(!(character.job in restricted_jobs))
- character.mind.make_Changeling()
- changelings += character.mind
+ if(!QDELETED(character) && character.client.should_include_for_role(
+ banning_key = initial(aux_antag_datum.banning_key),
+ role_preference_key = /datum/role_preference/antagonist/changeling,
+ req_hours = initial(aux_antag_datum.required_living_playtime)
+ ))
+ if(!(character.job in restricted_jobs))
+ character.mind.make_Changeling()
+ changelings += character.mind
if(QDELETED(character))
return
..()
diff --git a/code/game/gamemodes/clock_cult/clockcult.dm b/code/game/gamemodes/clock_cult/clockcult.dm
index b31dd9e379c..af4f68b3bc8 100644
--- a/code/game/gamemodes/clock_cult/clockcult.dm
+++ b/code/game/gamemodes/clock_cult/clockcult.dm
@@ -32,8 +32,8 @@ GLOBAL_VAR(clockcult_eminence)
required_players = 24
required_enemies = 4
recommended_enemies = 4
- antag_flag = ROLE_SERVANT_OF_RATVAR
- enemy_minimum_age = 14
+ role_preference = /datum/role_preference/antagonist/clock_cultist
+ antag_datum = /datum/antagonist/servant_of_ratvar
title_icon = "clockcult"
announce_span = "danger"
@@ -58,7 +58,7 @@ GLOBAL_VAR(clockcult_eminence)
for(var/i in 1 to clock_cultists)
if(!antag_candidates.len)
break
- var/datum/mind/clockie = antag_pick(antag_candidates, ROLE_SERVANT_OF_RATVAR)
+ var/datum/mind/clockie = antag_pick(antag_candidates, /datum/role_preference/antagonist/clock_cultist)
//In case antag_pick breaks
if(!clockie)
continue
diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm
index 7b2498f9263..1280a629674 100644
--- a/code/game/gamemodes/cult/cult.dm
+++ b/code/game/gamemodes/cult/cult.dm
@@ -36,14 +36,14 @@
name = "cult"
config_tag = "cult"
report_type = "cult"
- antag_flag = ROLE_CULTIST
+ role_preference = /datum/role_preference/antagonist/blood_cultist
+ antag_datum = /datum/antagonist/cult
false_report_weight = 1
restricted_jobs = list(JOB_NAME_CHAPLAIN,JOB_NAME_AI, JOB_NAME_CYBORG, JOB_NAME_SECURITYOFFICER, JOB_NAME_WARDEN, JOB_NAME_DETECTIVE, JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN, JOB_NAME_HEADOFPERSONNEL)
protected_jobs = list()
required_players = 29
required_enemies = 4
recommended_enemies = 4
- enemy_minimum_age = 14
announce_span = "cult"
announce_text = "Some crew members are trying to start a cult to Nar'Sie!\n\
@@ -84,7 +84,7 @@
for(var/cultists_number = 1 to recommended_enemies)
if(!antag_candidates.len)
break
- var/datum/mind/cultist = antag_pick(antag_candidates, ROLE_CULTIST)
+ var/datum/mind/cultist = antag_pick(antag_candidates, /datum/role_preference/antagonist/blood_cultist)
antag_candidates -= cultist
if(!cultist)
cultists_number--
diff --git a/code/game/gamemodes/devil/devil_game_mode.dm b/code/game/gamemodes/devil/devil_game_mode.dm
index b7d0bbe7766..95b7ab5db67 100644
--- a/code/game/gamemodes/devil/devil_game_mode.dm
+++ b/code/game/gamemodes/devil/devil_game_mode.dm
@@ -2,14 +2,14 @@
name = "devil"
config_tag = "devil"
report_type = "devil"
- antag_flag = ROLE_DEVIL
+ role_preference = /datum/role_preference/antagonist/devil
+ antag_datum = /datum/antagonist/devil
false_report_weight = 1
protected_jobs = list(JOB_NAME_LAWYER, JOB_NAME_CURATOR, JOB_NAME_CHAPLAIN, JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN, JOB_NAME_AI, JOB_NAME_CYBORG, JOB_NAME_SECURITYOFFICER, JOB_NAME_WARDEN, JOB_NAME_DETECTIVE)
required_players = 0
required_enemies = 1
recommended_enemies = 4
reroll_friendly = 1
- enemy_minimum_age = 0
title_icon = "devil"
allowed_special = list(/datum/special_role/traitor)
@@ -42,7 +42,7 @@
for(var/j = 0, j < num_devils, j++)
if (!antag_candidates.len)
break
- var/datum/mind/devil = antag_pick(antag_candidates, ROLE_DEVIL)
+ var/datum/mind/devil = antag_pick(antag_candidates, /datum/role_preference/antagonist/devil)
devils += devil
devil.special_role = traitor_name
devil.restricted_roles = restricted_jobs
diff --git a/code/game/gamemodes/dynamic/dynamic.dm b/code/game/gamemodes/dynamic/dynamic.dm
index 8e07f35c244..de004e48a54 100644
--- a/code/game/gamemodes/dynamic/dynamic.dm
+++ b/code/game/gamemodes/dynamic/dynamic.dm
@@ -699,15 +699,6 @@ GLOBAL_VAR_INIT(dynamic_forced_threat_level, -1)
log_game("DYNAMIC: [src] passed lowpop_lowimpact requirement: ([living_antags_count] antags of [living_players_count] players - [antag_percent]%)")
return FALSE
-/// Checks if client age is age or older.
-/datum/game_mode/dynamic/proc/check_age(client/C, age)
- enemy_minimum_age = age
- if(get_remaining_days(C) == 0)
- enemy_minimum_age = initial(enemy_minimum_age)
- return TRUE // Available in 0 days = available right now = player is old enough to play.
- enemy_minimum_age = initial(enemy_minimum_age)
- return FALSE
-
/datum/game_mode/dynamic/make_antag_chance(mob/living/carbon/human/newPlayer)
if (GLOB.dynamic_forced_extended)
return
diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets.dm b/code/game/gamemodes/dynamic/dynamic_rulesets.dm
index 3179f32c974..54d038e1447 100644
--- a/code/game/gamemodes/dynamic/dynamic_rulesets.dm
+++ b/code/game/gamemodes/dynamic/dynamic_rulesets.dm
@@ -18,12 +18,10 @@
var/list/mob/candidates = list()
/// List of players that were selected for this rule
var/list/datum/mind/assigned = list()
- /// Preferences flag such as ROLE_WIZARD that need to be turned on for players to be antag
- var/antag_flag = null
+ /// The /datum/role_preference typepath used for this ruleset.
+ var/role_preference = null
/// The antagonist datum that is assigned to the mobs mind on ruleset execution.
var/datum/antagonist/antag_datum = null
- /// The required minimum account age for this ruleset.
- var/minimum_required_age = 7
/// If set, and config flag protect_roles_from_antagonist is false, then the rule will not pick players from these roles.
var/list/protected_roles = list()
/// If set, rule will deny candidates from those roles always.
@@ -55,8 +53,6 @@
var/list/requirements = list(40,30,20,10,10,10,10,10,10,10)
/// Reference to the mode, use this instead of SSticker.mode.
var/datum/game_mode/dynamic/mode = null
- /// If a role is to be considered another for the purpose of banning.
- var/antag_flag_override = null
/// If a ruleset type which is in this list has been executed, then the ruleset will not be executed.
var/list/blocking_rules = list()
/// The minimum amount of players required for the rule to be considered.
@@ -213,19 +209,19 @@
var/client/client = GET_CLIENT(P)
if (!client || !P.mind) // Are they connected?
candidates.Remove(P)
- else if(!mode.check_age(client, minimum_required_age))
+ continue
+
+ if(!client.should_include_for_role(
+ banning_key = initial(antag_datum.banning_key),
+ role_preference_key = role_preference,
+ req_hours = initial(antag_datum.required_living_playtime)
+ ))
candidates.Remove(P)
continue
+
if(P.mind.special_role) // We really don't want to give antag to an antag.
candidates.Remove(P)
- else if(antag_flag_override)
- if(!(antag_flag_override in client.prefs.be_special) || is_banned_from(P.ckey, list(antag_flag_override, ROLE_SYNDICATE)))
- candidates.Remove(P)
- continue
- else
- if(!(antag_flag in client.prefs.be_special) || is_banned_from(P.ckey, list(antag_flag, ROLE_SYNDICATE)))
- candidates.Remove(P)
- continue
+ continue
/// Do your checks if the ruleset is ready to be executed here.
/// Should ignore certain checks if forced is TRUE
diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm
index 375d1163e56..74cf8577ef0 100644
--- a/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm
+++ b/code/game/gamemodes/dynamic/dynamic_rulesets_latejoin.dm
@@ -9,21 +9,15 @@
if (!P.client || !P.mind || !P.mind.assigned_role) // Are they connected?
candidates.Remove(P)
continue
- if(!mode.check_age(P.client, minimum_required_age))
- candidates.Remove(P)
- continue
- if(antag_flag_override)
- if(!(antag_flag_override in P.client.prefs.be_special) || is_banned_from(P.ckey, list(antag_flag_override, ROLE_SYNDICATE)))
- candidates.Remove(P)
- continue
- else
- if(!(antag_flag in P.client.prefs.be_special) || is_banned_from(P.ckey, list(antag_flag, ROLE_SYNDICATE)))
- candidates.Remove(P)
- continue
if (P.mind.assigned_role in restricted_roles) // Does their job allow for it?
candidates.Remove(P)
- continue
- if ((exclusive_roles.len > 0) && !(P.mind.assigned_role in exclusive_roles)) // Is the rule exclusive to their job?
+ else if(length(exclusive_roles) && !(P.mind.assigned_role in exclusive_roles)) // Is the rule exclusive to their job?
+ candidates.Remove(P)
+ else if(!P.client.should_include_for_role(
+ banning_key = initial(antag_datum.banning_key),
+ role_preference_key = role_preference,
+ req_hours = initial(antag_datum.required_living_playtime)
+ ))
candidates.Remove(P)
continue
@@ -53,7 +47,7 @@
/datum/dynamic_ruleset/latejoin/execute()
var/mob/M = pick(candidates)
assigned += M.mind
- M.mind.special_role = antag_flag
+ M.mind.special_role = initial(antag_datum.banning_key)
M.mind.add_antag_datum(antag_datum)
return TRUE
@@ -66,7 +60,7 @@
/datum/dynamic_ruleset/latejoin/infiltrator
name = "Syndicate Infiltrator"
antag_datum = /datum/antagonist/traitor
- antag_flag = ROLE_TRAITOR
+ role_preference = /datum/role_preference/antagonist/traitor
protected_roles = list(JOB_NAME_SECURITYOFFICER, JOB_NAME_WARDEN, JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN, JOB_NAME_HEADOFPERSONNEL)
restricted_roles = list(JOB_NAME_AI,JOB_NAME_CYBORG)
required_candidates = 1
@@ -92,8 +86,7 @@
name = "Provocateur"
persistent = TRUE
antag_datum = /datum/antagonist/rev/head
- antag_flag = ROLE_REV_HEAD
- antag_flag_override = ROLE_REV
+ role_preference = /datum/role_preference/antagonist/revolutionary
restricted_roles = list(JOB_NAME_AI, JOB_NAME_CYBORG, JOB_NAME_SECURITYOFFICER, JOB_NAME_WARDEN, JOB_NAME_DETECTIVE, JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN, JOB_NAME_HEADOFPERSONNEL, JOB_NAME_CHIEFENGINEER, JOB_NAME_CHIEFMEDICALOFFICER, JOB_NAME_RESEARCHDIRECTOR, JOB_NAME_MASTERATARMS) //NSV13 - added MAA
enemy_roles = list(JOB_NAME_AI, JOB_NAME_CYBORG, JOB_NAME_SECURITYOFFICER,JOB_NAME_DETECTIVE,JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN, JOB_NAME_WARDEN)
required_enemies = list(2,2,1,1,1,1,1,0,0,0)
@@ -125,7 +118,7 @@
var/mob/M = pick(candidates) // This should contain a single player, but in case.
if(check_eligible(M.mind)) // Didnt die/run off z-level/get implanted since leaving shuttle.
assigned += M.mind
- M.mind.special_role = antag_flag
+ M.mind.special_role = ROLE_REV_HEAD
revolution = new()
var/datum/antagonist/rev/head/new_head = new()
new_head.give_flash = TRUE
@@ -168,7 +161,7 @@
/datum/dynamic_ruleset/latejoin/heretic_smuggler
name = "Heretic Smuggler"
antag_datum = /datum/antagonist/heretic
- antag_flag = ROLE_HERETIC
+ role_preference = /datum/role_preference/antagonist/heretic
protected_roles = list(JOB_NAME_SECURITYOFFICER, JOB_NAME_WARDEN, JOB_NAME_HEADOFPERSONNEL, JOB_NAME_DETECTIVE, JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN)
restricted_roles = list(JOB_NAME_AI,JOB_NAME_CYBORG)
required_candidates = 1
diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm
index 9aa65b5b481..0c6c3579dd2 100644
--- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm
+++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm
@@ -51,17 +51,14 @@
if (!M.client) // Are they connected?
trimmed_list.Remove(M)
continue
- if(!mode.check_age(M.client, minimum_required_age))
+ if(!M.client.should_include_for_role(
+ banning_key = initial(antag_datum.banning_key),
+ role_preference_key = role_preference,
+ poll_ignore_key = role_preference,
+ req_hours = initial(antag_datum.required_living_playtime)
+ ))
trimmed_list.Remove(M)
continue
- if(antag_flag_override)
- if(!(antag_flag_override in M.client.prefs.be_special) || is_banned_from(M.ckey, list(antag_flag_override, ROLE_SYNDICATE)))
- trimmed_list.Remove(M)
- continue
- else
- if(!(antag_flag in M.client.prefs.be_special) || is_banned_from(M.ckey, list(antag_flag, ROLE_SYNDICATE)))
- trimmed_list.Remove(M)
- continue
if (M.mind)
if (restrict_ghost_roles && (M.mind.assigned_role in GLOB.exp_specialmap[EXP_TYPE_SPECIAL])) // Are they playing a ghost role?
trimmed_list.Remove(M)
@@ -114,7 +111,7 @@
message_admins("Polling [possible_volunteers.len] players to apply for the [name] ruleset.")
log_game("DYNAMIC: Polling [possible_volunteers.len] players to apply for the [name] ruleset.")
- candidates = pollGhostCandidates("The mode is looking for volunteers to become [antag_flag] for [name]", antag_flag, SSticker.mode, antag_flag_override ? antag_flag_override : antag_flag, poll_time = 300)
+ candidates = pollGhostCandidates("The mode is looking for volunteers to become [initial(antag_datum.name)] for [name]", initial(antag_datum.banning_key), role_preference, poll_time = 300)
if(!length(candidates))
message_admins("The ruleset [name] received no applications.")
@@ -170,7 +167,7 @@
var/datum/antagonist/new_role = new antag_datum()
setup_role(new_role)
new_character.mind.add_antag_datum(new_role)
- new_character.mind.special_role = antag_flag
+ new_character.mind.special_role = new_role.banning_key
/datum/dynamic_ruleset/midround/from_ghosts/proc/setup_role(datum/antagonist/new_role)
return
@@ -185,7 +182,7 @@
name = "Syndicate Sleeper Agent"
midround_ruleset_style = MIDROUND_RULESET_STYLE_LIGHT
antag_datum = /datum/antagonist/traitor
- antag_flag = ROLE_TRAITOR
+ role_preference = /datum/role_preference/midround_living/traitor
protected_roles = list(JOB_NAME_SECURITYOFFICER, JOB_NAME_WARDEN, JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN)
restricted_roles = list(JOB_NAME_CYBORG, JOB_NAME_AI, "Positronic Brain")
required_candidates = 1
@@ -239,7 +236,7 @@
name = "Malfunctioning AI"
midround_ruleset_style = MIDROUND_RULESET_STYLE_HEAVY
antag_datum = /datum/antagonist/traitor
- antag_flag = ROLE_MALF
+ role_preference = /datum/role_preference/midround_living/malfunctioning_ai
enemy_roles = list(JOB_NAME_SECURITYOFFICER, JOB_NAME_WARDEN, JOB_NAME_DETECTIVE, JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN, JOB_NAME_SCIENTIST, JOB_NAME_CHEMIST, JOB_NAME_RESEARCHDIRECTOR, JOB_NAME_CHIEFENGINEER)
exclusive_roles = list(JOB_NAME_AI)
required_enemies = list(4,4,4,4,4,4,2,2,2,0)
@@ -274,7 +271,7 @@
var/mob/living/silicon/ai/M = pick_n_take(candidates)
assigned += M.mind
var/datum/antagonist/traitor/AI = new
- M.mind.special_role = antag_flag
+ M.mind.special_role = "Malf AI"
M.mind.add_antag_datum(AI)
if(prob(ion_announce))
priority_announce("Ion storm detected near the station. Please check all AI-controlled equipment for errors.", "Anomaly Alert", ANNOUNCER_IONSTORM)
@@ -294,7 +291,7 @@
name = "Wizard"
midround_ruleset_style = MIDROUND_RULESET_STYLE_HEAVY
antag_datum = /datum/antagonist/wizard
- antag_flag = ROLE_WIZARD
+ role_preference = /datum/role_preference/midround_ghost/wizard
enemy_roles = list(JOB_NAME_SECURITYOFFICER, JOB_NAME_DETECTIVE, JOB_NAME_WARDEN, JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN, JOB_NAME_RESEARCHDIRECTOR) //RD doesn't believe in magic
required_enemies = list(2,2,1,1,1,1,1,0,0,0)
required_candidates = 1
@@ -325,7 +322,7 @@
/datum/dynamic_ruleset/midround/from_ghosts/nuclear
name = "Nuclear Assault"
midround_ruleset_style = MIDROUND_RULESET_STYLE_HEAVY
- antag_flag = ROLE_OPERATIVE
+ role_preference = /datum/role_preference/midround_ghost/nuclear_operative
antag_datum = /datum/antagonist/nukeop
enemy_roles = list(JOB_NAME_AI, JOB_NAME_CYBORG, JOB_NAME_SECURITYOFFICER, JOB_NAME_WARDEN, JOB_NAME_DETECTIVE, JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN)
required_enemies = list(3,3,3,3,3,2,1,1,0,0)
@@ -351,8 +348,8 @@
return ..()
/datum/dynamic_ruleset/midround/from_ghosts/nuclear/finish_setup(mob/new_character, index)
- new_character.mind.special_role = "Nuclear Operative"
- new_character.mind.assigned_role = "Nuclear Operative"
+ new_character.mind.special_role = ROLE_OPERATIVE
+ new_character.mind.assigned_role = ROLE_OPERATIVE
if (index == 1) // Our first guy is the leader
var/datum/antagonist/nukeop/leader/new_role = new
nuke_team = new_role.nuke_team
@@ -370,7 +367,7 @@
name = "Blob"
midround_ruleset_style = MIDROUND_RULESET_STYLE_HEAVY
antag_datum = /datum/antagonist/blob
- antag_flag = ROLE_BLOB
+ role_preference = /datum/role_preference/midround_ghost/blob
enemy_roles = list(JOB_NAME_SECURITYOFFICER, JOB_NAME_DETECTIVE, JOB_NAME_WARDEN, JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN)
required_enemies = list(2,2,1,1,1,1,1,0,0,0)
required_candidates = 1
@@ -394,7 +391,7 @@
name = "Alien Infestation"
midround_ruleset_style = MIDROUND_RULESET_STYLE_HEAVY
antag_datum = /datum/antagonist/xeno
- antag_flag = ROLE_ALIEN
+ role_preference = /datum/role_preference/midround_ghost/xenomorph
enemy_roles = list(JOB_NAME_SECURITYOFFICER, JOB_NAME_DETECTIVE, JOB_NAME_WARDEN, JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN)
required_enemies = list(2,2,2,1,1,1,1,0,0,0)
required_candidates = 1
@@ -442,8 +439,7 @@
name = "Nightmare"
midround_ruleset_style = MIDROUND_RULESET_STYLE_LIGHT
antag_datum = /datum/antagonist/nightmare
- antag_flag = "Nightmare"
- antag_flag_override = ROLE_ALIEN
+ role_preference = /datum/role_preference/midround_ghost/space_dragon
enemy_roles = list(JOB_NAME_SECURITYOFFICER, JOB_NAME_DETECTIVE, JOB_NAME_WARDEN, JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN)
required_enemies = list(2,2,1,1,1,1,1,0,0,0)
required_candidates = 1
@@ -490,8 +486,7 @@
/datum/dynamic_ruleset/midround/from_ghosts/abductors
name = "Abductors"
midround_ruleset_style = MIDROUND_RULESET_STYLE_HEAVY
- antag_flag = "Abductor"
- antag_flag_override = ROLE_ABDUCTOR
+ role_preference = /datum/role_preference/midround_ghost/abductor
enemy_roles = list(JOB_NAME_SECURITYOFFICER, JOB_NAME_DETECTIVE, JOB_NAME_WARDEN, JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN)
required_enemies = list(2,2,1,1,1,1,1,0,0,0)
required_candidates = 2
@@ -529,8 +524,7 @@
name = "Revenant"
midround_ruleset_style = MIDROUND_RULESET_STYLE_LIGHT
antag_datum = /datum/antagonist/revenant
- antag_flag = "Revenant"
- antag_flag_override = ROLE_REVENANT
+ role_preference = /datum/role_preference/midround_ghost/revenant
enemy_roles = list(JOB_NAME_SECURITYOFFICER, JOB_NAME_DETECTIVE, JOB_NAME_WARDEN, JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN)
required_enemies = list(2,2,1,1,1,1,1,0,0,0)
required_candidates = 1
@@ -581,7 +575,7 @@
/datum/dynamic_ruleset/midround/pirates
name = "Space Pirates"
midround_ruleset_style = MIDROUND_RULESET_STYLE_HEAVY
- antag_flag = "Space Pirates"
+ role_preference = /datum/role_preference/midround_ghost/space_pirate
required_type = /mob/dead/observer
enemy_roles = list(JOB_NAME_SECURITYOFFICER, JOB_NAME_DETECTIVE, JOB_NAME_WARDEN, JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN)
required_enemies = list(2,2,1,1,1,1,1,0,0,0)
@@ -608,7 +602,7 @@
name = "Obsessed"
midround_ruleset_style = MIDROUND_RULESET_STYLE_LIGHT
antag_datum = /datum/antagonist/obsessed
- antag_flag = ROLE_OBSESSED
+ role_preference = /datum/role_preference/midround_living/obsessed
restricted_roles = list(JOB_NAME_AI, JOB_NAME_CYBORG, "Positronic Brain")
enemy_roles = list(JOB_NAME_SECURITYOFFICER, JOB_NAME_DETECTIVE, JOB_NAME_WARDEN, JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN)
required_enemies = list(2,2,1,1,1,1,1,0,0,0)
@@ -625,7 +619,6 @@
!candidate.getorgan(/obj/item/organ/brain) \
|| candidate.mind.has_antag_datum(/datum/antagonist/obsessed) \
|| candidate.stat == DEAD \
- || !(ROLE_OBSESSED in candidate.client?.prefs?.be_special) \
|| !SSjob.GetJob(candidate.mind.assigned_role) \
|| (candidate.mind.assigned_role in GLOB.nonhuman_positions) \
)
diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm
index 569319b8cf8..fe384067216 100644
--- a/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm
+++ b/code/game/gamemodes/dynamic/dynamic_rulesets_roundstart.dm
@@ -7,9 +7,8 @@
/datum/dynamic_ruleset/roundstart/traitor
name = "Traitors"
- antag_flag = ROLE_TRAITOR
+ role_preference = /datum/role_preference/antagonist/traitor
antag_datum = /datum/antagonist/traitor
- minimum_required_age = 0
protected_roles = list(JOB_NAME_SECURITYOFFICER, JOB_NAME_WARDEN, JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN)
restricted_roles = list(JOB_NAME_CYBORG)
required_candidates = 1
@@ -41,8 +40,8 @@
/datum/dynamic_ruleset/roundstart/traitorbro
name = "Blood Brothers"
- antag_flag = ROLE_BROTHER
- antag_datum = /datum/antagonist/brother/
+ role_preference = /datum/role_preference/antagonist/blood_brother
+ antag_datum = /datum/antagonist/brother
protected_roles = list(JOB_NAME_SECURITYOFFICER, JOB_NAME_WARDEN, JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN)
restricted_roles = list(JOB_NAME_AI, JOB_NAME_CYBORG)
required_candidates = 2
@@ -66,7 +65,7 @@
var/mob/bro = pick_n_take(candidates)
assigned += bro.mind
team.add_member(bro.mind)
- bro.mind.special_role = "brother"
+ bro.mind.special_role = ROLE_BROTHER
bro.mind.restricted_roles = restricted_roles
pre_brother_teams += team
return TRUE
@@ -89,7 +88,7 @@
/datum/dynamic_ruleset/roundstart/changeling
name = "Changelings"
- antag_flag = ROLE_CHANGELING
+ role_preference = /datum/role_preference/antagonist/changeling
antag_datum = /datum/antagonist/changeling
protected_roles = list(JOB_NAME_SECURITYOFFICER, JOB_NAME_WARDEN, JOB_NAME_DETECTIVE, JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN)
restricted_roles = list(JOB_NAME_AI, JOB_NAME_CYBORG)
@@ -126,7 +125,7 @@
/datum/dynamic_ruleset/roundstart/heretics
name = "Heretics"
- antag_flag = ROLE_HERETIC
+ role_preference = /datum/role_preference/antagonist/heretic
antag_datum = /datum/antagonist/heretic
protected_roles = list(JOB_NAME_SECURITYOFFICER, JOB_NAME_WARDEN, JOB_NAME_DETECTIVE, JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN)
restricted_roles = list(JOB_NAME_AI, JOB_NAME_CYBORG)
@@ -170,10 +169,9 @@
// Dynamic is a wonderful thing that adds wizards to every round and then adds even more wizards during the round.
/datum/dynamic_ruleset/roundstart/wizard
name = "Wizard"
- antag_flag = ROLE_WIZARD
+ role_preference = /datum/role_preference/antagonist/wizard
antag_datum = /datum/antagonist/wizard
flags = HIGH_IMPACT_RULESET | NO_OTHER_ROUNDSTARTS_RULESET
- minimum_required_age = 14
restricted_roles = list(JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN) // Just to be sure that a wizard getting picked won't ever imply a Captain or HoS not getting drafted
required_candidates = 1
weight = 2
@@ -214,9 +212,8 @@
/datum/dynamic_ruleset/roundstart/bloodcult
name = "Blood Cult"
- antag_flag = ROLE_CULTIST
+ role_preference = /datum/role_preference/antagonist/blood_cultist
antag_datum = /datum/antagonist/cult
- minimum_required_age = 14
restricted_roles = list(JOB_NAME_AI, JOB_NAME_CYBORG, JOB_NAME_SECURITYOFFICER, JOB_NAME_WARDEN, JOB_NAME_DETECTIVE, JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN, JOB_NAME_CHAPLAIN, JOB_NAME_HEADOFPERSONNEL)
required_candidates = 2
weight = 3
@@ -269,10 +266,9 @@
/datum/dynamic_ruleset/roundstart/nuclear
name = "Nuclear Emergency"
- antag_flag = ROLE_OPERATIVE
+ role_preference = /datum/role_preference/antagonist/nuclear_operative
antag_datum = /datum/antagonist/nukeop
var/datum/antagonist/antag_leader_datum = /datum/antagonist/nukeop/leader
- minimum_required_age = 14
restricted_roles = list(JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN) // Just to be sure that a nukie getting picked won't ever imply a Captain or HoS not getting drafted
required_candidates = 5
weight = 3
@@ -295,8 +291,8 @@
break
var/mob/M = pick_n_take(candidates)
assigned += M.mind
- M.mind.assigned_role = "Nuclear Operative"
- M.mind.special_role = "Nuclear Operative"
+ M.mind.assigned_role = ROLE_OPERATIVE
+ M.mind.special_role = ROLE_OPERATIVE
return TRUE
/datum/dynamic_ruleset/roundstart/nuclear/execute()
@@ -354,10 +350,8 @@
/datum/dynamic_ruleset/roundstart/revs
name = "Revolution"
persistent = TRUE
- antag_flag = ROLE_REV_HEAD
- antag_flag_override = ROLE_REV
+ role_preference = /datum/role_preference/antagonist/revolutionary
antag_datum = /datum/antagonist/rev/head
- minimum_required_age = 14
restricted_roles = list(JOB_NAME_AI, JOB_NAME_CYBORG, JOB_NAME_SECURITYOFFICER, JOB_NAME_WARDEN, JOB_NAME_DETECTIVE, JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN, JOB_NAME_HEADOFPERSONNEL, JOB_NAME_CHIEFENGINEER, JOB_NAME_CHIEFMEDICALOFFICER, JOB_NAME_RESEARCHDIRECTOR, JOB_NAME_MASTERATARMS) //NSV13 - added MAA
required_candidates = 3
weight = 3
@@ -383,7 +377,7 @@
var/mob/M = pick_n_take(candidates)
assigned += M.mind
M.mind.restricted_roles = restricted_roles
- M.mind.special_role = antag_flag
+ M.mind.special_role = ROLE_REV_HEAD
return TRUE
/datum/dynamic_ruleset/roundstart/revs/execute()
@@ -437,7 +431,6 @@
/datum/dynamic_ruleset/roundstart/extended
name = "Extended"
- antag_flag = null
antag_datum = null
restricted_roles = list()
required_candidates = 0
@@ -486,7 +479,7 @@
/datum/dynamic_ruleset/roundstart/devil
name = "Devil"
- antag_flag = ROLE_DEVIL
+ role_preference = /datum/role_preference/antagonist/devil
antag_datum = /datum/antagonist/devil
restricted_roles = list(JOB_NAME_LAWYER, JOB_NAME_CURATOR, JOB_NAME_CHAPLAIN, JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN, JOB_NAME_AI, JOB_NAME_CYBORG, JOB_NAME_SECURITYOFFICER, JOB_NAME_WARDEN, JOB_NAME_DETECTIVE)
required_candidates = 1
@@ -574,7 +567,7 @@
/datum/dynamic_ruleset/roundstart/clockcult
name = "Clockwork Cult"
- antag_flag = ROLE_SERVANT_OF_RATVAR
+ role_preference = /datum/role_preference/antagonist/clock_cultist
antag_datum = /datum/antagonist/servant_of_ratvar
restricted_roles = list(JOB_NAME_AI, JOB_NAME_CYBORG, JOB_NAME_SECURITYOFFICER, JOB_NAME_WARDEN, JOB_NAME_DETECTIVE,JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN, JOB_NAME_CHAPLAIN, JOB_NAME_HEADOFPERSONNEL)
required_candidates = 4
@@ -636,7 +629,7 @@
/datum/dynamic_ruleset/roundstart/incursion
name = "Incursion"
- antag_flag = ROLE_INCURSION
+ role_preference = /datum/role_preference/antagonist/incursionist
antag_datum = /datum/antagonist/incursion
protected_roles = list(JOB_NAME_SECURITYOFFICER, JOB_NAME_WARDEN, JOB_NAME_DETECTIVE,JOB_NAME_CAPTAIN, JOB_NAME_HEADOFPERSONNEL, JOB_NAME_HEADOFSECURITY, JOB_NAME_CHIEFENGINEER, JOB_NAME_RESEARCHDIRECTOR, JOB_NAME_CHIEFMEDICALOFFICER)
restricted_roles = list(JOB_NAME_AI, JOB_NAME_CYBORG)
@@ -688,7 +681,7 @@
/datum/dynamic_ruleset/roundstart/hivemind
name = "Assimilation"
- antag_flag = ROLE_HIVE
+ role_preference = /datum/role_preference/antagonist/hivemind_host
antag_datum = /datum/antagonist/hivemind
protected_roles = list(JOB_NAME_SECURITYOFFICER, JOB_NAME_WARDEN, JOB_NAME_DETECTIVE,JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN)
restricted_roles = list(JOB_NAME_AI, JOB_NAME_CYBORG)
diff --git a/code/game/gamemodes/dynamic/dynamic_simulations.dm b/code/game/gamemodes/dynamic/dynamic_simulations.dm
index 4b48955ce75..acba5d1cc42 100644
--- a/code/game/gamemodes/dynamic/dynamic_simulations.dm
+++ b/code/game/gamemodes/dynamic/dynamic_simulations.dm
@@ -29,11 +29,6 @@
var/datum/client_interface/mock_client = new
var/datum/preferences/prefs = new
- var/list/be_special = list()
- for (var/special_role in GLOB.special_roles)
- be_special += special_role
-
- prefs.be_special = be_special
mock_client.prefs = prefs
mock_new_player.mock_client = mock_client
diff --git a/code/game/gamemodes/dynamic/readme.md b/code/game/gamemodes/dynamic/readme.md
index 7faa5c2d870..9af317301d8 100644
--- a/code/game/gamemodes/dynamic/readme.md
+++ b/code/game/gamemodes/dynamic/readme.md
@@ -144,7 +144,6 @@ Rulesets have the following variables notable to developers and those interested
- Traitor: `antag_cap = list("denominator" = 24)`. This means that for every 24 players, 1 traitor will be added (assuming no scaling).
- Nuclear Emergency: `antag_cap = list("denominator" = 18, "offset" = 1)`. For every 18 players, 1 nuke op will be added. Starts at 1, meaning at 30 players, 3 nuke ops will be created, rather than 2.
- Revolution: `antag_cap = 3`. There will always be 3 rev-heads, no matter what.
-- `minimum_required_age` - The minimum age in order to apply for the ruleset.
- `weight` - How likely this ruleset is to be picked. A higher weight results in a higher chance of drafting.
- `cost` - The initial cost of the ruleset. This cost is taken from either the roundstart or midround budget, depending on the ruleset.
- `scaling_cost` - Cost for every *additional* application of this ruleset.
diff --git a/code/game/gamemodes/eldritch_cult/eldritch_cult.dm b/code/game/gamemodes/eldritch_cult/eldritch_cult.dm
index 307b1be0893..c169e11ae73 100644
--- a/code/game/gamemodes/eldritch_cult/eldritch_cult.dm
+++ b/code/game/gamemodes/eldritch_cult/eldritch_cult.dm
@@ -2,7 +2,8 @@
name = "heresy"
config_tag = "heresy"
report_type = "heresy"
- antag_flag = ROLE_HERETIC
+ role_preference = /datum/role_preference/antagonist/heretic
+ antag_datum = /datum/antagonist/heretic
false_report_weight = 5
protected_jobs = list(JOB_NAME_SECURITYOFFICER, JOB_NAME_WARDEN, JOB_NAME_DETECTIVE, JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN)
restricted_jobs = list(JOB_NAME_AI, JOB_NAME_CYBORG)
@@ -10,7 +11,6 @@
required_enemies = 1
recommended_enemies = 4
reroll_friendly = 1
- enemy_minimum_age = 0
allowed_special = list(/datum/special_role/traitor/higher_chance)
@@ -44,7 +44,7 @@
for(var/i in 1 to num_ecult)
if(!antag_candidates.len)
break
- var/datum/mind/cultie = antag_pick(antag_candidates, ROLE_HERETIC)
+ var/datum/mind/cultie = antag_pick(antag_candidates, /datum/role_preference/antagonist/heretic)
antag_candidates -= cultie
cultie.special_role = ROLE_HERETIC
cultie.restricted_roles = restricted_jobs
diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm
index 03300874083..80576b5813e 100644
--- a/code/game/gamemodes/game_mode.dm
+++ b/code/game/gamemodes/game_mode.dm
@@ -28,13 +28,15 @@
var/maximum_players = -1 // -1 is no maximum, positive numbers limit the selection of a mode on overstaffed stations
var/required_enemies = 0
var/recommended_enemies = 0
- var/antag_flag = null //preferences flag such as BE_WIZARD that need to be turned on for players to be antag
+ /// The role preference used to poll players.
+ var/role_preference
+ /// The antag datum typepath primarily spawned by this gamemode. Used for checking the banning key and required playtime.
+ var/datum/antagonist/antag_datum
var/mob/living/living_antag_player = null
var/datum/game_mode/replacementmode = null
var/round_converted = 0 //0: round not converted, 1: round going to convert, 2: round converted
var/reroll_friendly //During mode conversion only these are in the running
var/continuous_sanity_checked //Catches some cases where config options could be used to suggest that modes without antagonists should end when all antagonists die
- var/enemy_minimum_age = 7 //How many days must players have been playing before they can play this antagonist
var/list/allowed_special = list() //Special roles that can spawn (Add things like /datum/antagonist/special/undercover for them to be able to spawn during this gamemode)
var/list/active_specials = list() //Special roles that have spawned, and can now spawn late
@@ -87,7 +89,7 @@
return 1
/datum/game_mode/proc/setup_antag_candidates()
- antag_candidates = get_players_for_role(antag_flag)
+ antag_candidates = get_players_for_role(antag_datum, role_preference)
///Attempts to select players for special roles the mode might have.
/datum/game_mode/proc/pre_setup()
@@ -121,11 +123,11 @@
if(candidates.len == 0)
return //No more candidates, end the selection process, and active specials at this time will be handled by latejoins or not included
var/mob/person
- if(special.special_role_flag)
- person = antag_pick(candidates, special.special_role_flag)
+ if(special.use_antag_rep)
+ person = antag_pick(candidates, special.preference_type)
else
person = pick_n_take(candidates)
- if(is_banned_from(person.ckey, special.preference_type))
+ if(is_banned_from(person.ckey, special.banning_key))
continue
if(!person)
continue
@@ -205,7 +207,7 @@
continue
if(!is_special_type(M, subantag.attached_antag_datum))
continue
- if(is_banned_from(M.ckey, list(subantag.preference_type)))
+ if(is_banned_from(M.ckey, subantag.banning_key))
continue
count++
if(count >= subantag.max_amount)
@@ -256,7 +258,7 @@
var/list/antag_candidates = list()
for(var/mob/living/carbon/human/H in living_crew)
- if(H.client && (H.client.prefs.toggles & PREFTOGGLE_MIDROUND_ANTAG) && !is_centcom_level(H.z))
+ if(H.client && !is_centcom_level(H.z))
antag_candidates += H
if(!antag_candidates)
@@ -429,7 +431,9 @@
// The odds become:
// Player A: 150 / 250 = 0.6 = 60%
// Player B: 100 / 250 = 0.4 = 40%
-/datum/game_mode/proc/antag_pick(list/datum/candidates, role)
+/// The role_preference argument is optional, but candidates will not use their PERSONAL antag rep if the preference is disabled, rather only using the "base" antag rep.
+/// This is mainly used in the situation where someone is drafted for a ruleset despite having the preference disabled (a feature of gamemodes) - we don't want to spend their rep.
+/datum/game_mode/proc/antag_pick(list/datum/candidates, role_preference = null)
if(!CONFIG_GET(flag/use_antag_rep)) // || candidates.len <= 1)
return pick(candidates)
@@ -452,7 +456,10 @@
if(!player)
candidates -= mind
continue
- total_tickets += min(((role in player.client.prefs.be_special) ? SSpersistence.antag_rep[p_ckey] : 0) + DEFAULT_ANTAG_TICKETS, MAX_TICKETS_PER_ROLL)
+ var/role_enabled = TRUE
+ if(role_preference && player.client)
+ role_enabled = player.client.role_preference_enabled(role_preference)
+ total_tickets += min((role_enabled ? SSpersistence.antag_rep[p_ckey] : 0) + DEFAULT_ANTAG_TICKETS, MAX_TICKETS_PER_ROLL)
var/antag_select = rand(1,total_tickets)
var/current = 1
@@ -461,9 +468,11 @@
p_ckey = ckey(mind.key)
var/mob/dead/new_player/player = get_mob_by_ckey(p_ckey)
p_rep = SSpersistence.antag_rep[p_ckey]
-
+ var/role_enabled = TRUE
+ if(role_preference && player.client)
+ role_enabled = player.client.role_preference_enabled(role_preference)
var/previous = current
- var/spend = min(((role in player.client.prefs.be_special) ? p_rep : 0) + DEFAULT_ANTAG_TICKETS, MAX_TICKETS_PER_ROLL)
+ var/spend = min((role_enabled ? p_rep : 0) + DEFAULT_ANTAG_TICKETS, MAX_TICKETS_PER_ROLL)
current += spend
if(antag_select >= previous && antag_select <= (current-1))
@@ -474,7 +483,9 @@
WARNING("Something has gone terribly wrong. /datum/game_mode/proc/antag_pick failed to select a candidate. Falling back to pick()")
return pick(candidates)
-/datum/game_mode/proc/get_players_for_role(role)
+/datum/game_mode/proc/get_players_for_role(datum/antagonist/antag_datum, role_preference = null)
+ var/banning_key = ispath(antag_datum, /datum/antagonist) ? initial(antag_datum.banning_key) : null
+ var/req_hours = ispath(antag_datum, /datum/antagonist) ? initial(antag_datum.required_living_playtime) : 0
var/list/players = list()
var/list/candidates = list()
var/list/drafted = list()
@@ -490,11 +501,13 @@
players = shuffle(players)
for(var/mob/dead/new_player/player in players)
- if(player.client && player.ready == PLAYER_READY_TO_PLAY)
- if(role in player.client.prefs.be_special)
- if(!is_banned_from(player.ckey, list(role, ROLE_SYNDICATE)) && !QDELETED(player))
- if(age_check(player.client)) //Must be older than the minimum age
- candidates += player.mind // Get a list of all the people who want to be the antagonist for this round
+ if(!QDELETED(player) && player.client && player.ready == PLAYER_READY_TO_PLAY)
+ if(player.client.should_include_for_role(
+ banning_key = banning_key,
+ role_preference_key = role_preference,
+ req_hours = req_hours
+ ))
+ candidates += player.mind // Get a list of all the people who want to be the antagonist for this round
if(restricted_jobs)
for(var/datum/mind/player in candidates)
@@ -504,10 +517,14 @@
if(candidates.len < recommended_enemies)
for(var/mob/dead/new_player/player in players)
- if(player.client && player.ready == PLAYER_READY_TO_PLAY)
- if(!(role in player.client.prefs.be_special)) // We don't have enough people who want to be antagonist, make a separate list of people who don't want to be one
- if(!is_banned_from(player.ckey, list(role, ROLE_SYNDICATE)) && !QDELETED(player))
- drafted += player.mind
+ if(!QDELETED(player) && player.client && player.ready == PLAYER_READY_TO_PLAY)
+ // We don't have enough people who want to be antagonist, make a separate list of people who don't want to be one but are otherwise eligible
+ if(player.client.should_include_for_role(
+ banning_key = banning_key,
+ role_preference_key = null,
+ req_hours = req_hours
+ ) && !player.client.role_preference_enabled(role_preference))
+ drafted += player.mind
if(restricted_jobs)
for(var/datum/mind/player in drafted) // Remove people who can't be an antagonist
@@ -550,15 +567,15 @@
// Less if there are not enough valid players in the game entirely to make recommended_enemies.
-/datum/game_mode/proc/get_alive_non_antagonsist_players_for_role(role, list/restricted_roles)
+/datum/game_mode/proc/get_alive_non_antagonsist_players_for_role(datum/antagonist/antag_datum, role_preference, list/restricted_roles)
+ var/banning_key = ispath(antag_datum, /datum/antagonist) ? initial(antag_datum.banning_key) : null
+ var/req_hours = ispath(antag_datum, /datum/antagonist) ? initial(antag_datum.required_living_playtime) : 0
var/list/candidates = list()
for(var/mob/living/carbon/human/player in GLOB.player_list)
- if(player.client && is_station_level(player.z))
- if(role in player.client.prefs.be_special)
- if(!is_banned_from(player.ckey, list(role, ROLE_SYNDICATE)) && !QDELETED(player))
- if(age_check(player.client) && !player.mind.special_role) //Must be older than the minimum age
- candidates += player.mind // Get a list of all the people who want to be the antagonist for this round
+ if(!QDELETED(player) && player.client && is_station_level(player.z) && !player.mind.special_role)
+ if(player.client.should_include_for_role(banning_key = banning_key, role_preference_key = role_preference, req_hours = req_hours))
+ candidates += player.mind // Get a list of all the people who want to be the antagonist for this round // Get a list of all the people who want to be the antagonist for this round
var/restricted_list = length(restricted_roles) ? restricted_roles : restricted_jobs
if(restricted_list)
@@ -728,25 +745,6 @@
for (var/C in GLOB.admins)
to_chat(C, msg.Join())
-//If the configuration option is set to require players to be logged as old enough to play certain jobs, then this proc checks that they are, otherwise it just returns 1
-/datum/game_mode/proc/age_check(client/C)
- if(get_remaining_days(C) == 0)
- return 1 //Available in 0 days = available right now = player is old enough to play.
- return 0
-
-
-/datum/game_mode/proc/get_remaining_days(client/C)
- if(!C)
- return 0
- if(!CONFIG_GET(flag/use_age_restriction_for_jobs))
- return 0
- if(!isnum_safe(C.player_age))
- return 0 //This is only a number if the db connection is established, otherwise it is text: "Requires database", meaning these restrictions cannot be enforced
- if(!isnum_safe(enemy_minimum_age))
- return 0
-
- return max(0, enemy_minimum_age - C.player_age)
-
/datum/game_mode/proc/remove_antag_for_borging(datum/mind/newborgie)
SSticker.mode.remove_cultist(newborgie, 0, 0)
remove_servant_of_ratvar(newborgie)
diff --git a/code/game/gamemodes/gangs/gangs.dm b/code/game/gamemodes/gangs/gangs.dm
index 7d1187ef1d9..f0e9536cdae 100644
--- a/code/game/gamemodes/gangs/gangs.dm
+++ b/code/game/gamemodes/gangs/gangs.dm
@@ -5,12 +5,12 @@ GLOBAL_LIST_EMPTY(gangs)
/datum/game_mode/gang
name = "gang war"
config_tag = "gang"
- antag_flag = ROLE_GANG
+ role_preference = /datum/role_preference/antagonist/gangster
+ antag_datum = /datum/antagonist/gang
restricted_jobs = list(JOB_NAME_SECURITYOFFICER, JOB_NAME_WARDEN, JOB_NAME_DETECTIVE, JOB_NAME_AI, JOB_NAME_CYBORG,JOB_NAME_CAPTAIN, JOB_NAME_HEADOFPERSONNEL, JOB_NAME_HEADOFSECURITY)
required_players = 15 //NSV13 - down from 30
required_enemies = 1 //NSV13 - down from 2
recommended_enemies = 2 //NSV13 - down from 3
- enemy_minimum_age = 14
announce_span = "danger"
announce_text = "A violent turf war has erupted on the station!\n\
diff --git a/code/game/gamemodes/hivemind/hivemind.dm b/code/game/gamemodes/hivemind/hivemind.dm
index 4fa0b6095c0..90bf74f93cc 100644
--- a/code/game/gamemodes/hivemind/hivemind.dm
+++ b/code/game/gamemodes/hivemind/hivemind.dm
@@ -4,7 +4,8 @@ GLOBAL_LIST_EMPTY(hivehosts)
name = "assimilation"
config_tag = "hivemind"
report_type = "hivemind"
- antag_flag = ROLE_HIVE
+ role_preference = /datum/role_preference/antagonist/hivemind_host
+ antag_datum = /datum/antagonist/hivemind
false_report_weight = 5
protected_jobs = list(JOB_NAME_SECURITYOFFICER, JOB_NAME_WARDEN, JOB_NAME_DETECTIVE, JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN)
restricted_jobs = list(JOB_NAME_AI, JOB_NAME_CYBORG)
@@ -12,7 +13,6 @@ GLOBAL_LIST_EMPTY(hivehosts)
required_enemies = 3
recommended_enemies = 3
reroll_friendly = 1
- enemy_minimum_age = 0
announce_span = "danger"
announce_text = "The hosts of several psionic hiveminds have infiltrated the station and are looking to assimilate the crew!\n\
@@ -62,7 +62,7 @@ GLOBAL_LIST_EMPTY(hivehosts)
for(var/j = 0, j < num_hosts, j++)
if (!antag_candidates.len)
break
- var/datum/mind/host = antag_pick(antag_candidates, ROLE_HIVE)
+ var/datum/mind/host = antag_pick(antag_candidates, /datum/role_preference/antagonist/hivemind_host)
hosts += host
host.special_role = ROLE_HIVE
host.restricted_roles = restricted_jobs
diff --git a/code/game/gamemodes/incursion/incursion.dm b/code/game/gamemodes/incursion/incursion.dm
index adf8979f516..c5324e52111 100644
--- a/code/game/gamemodes/incursion/incursion.dm
+++ b/code/game/gamemodes/incursion/incursion.dm
@@ -7,9 +7,9 @@
config_tag = "incursion"
restricted_jobs = list(JOB_NAME_AI, JOB_NAME_CYBORG)
protected_jobs = list(JOB_NAME_SECURITYOFFICER, JOB_NAME_WARDEN, JOB_NAME_DETECTIVE,JOB_NAME_CAPTAIN, JOB_NAME_HEADOFPERSONNEL, JOB_NAME_HEADOFSECURITY, JOB_NAME_CHIEFENGINEER, JOB_NAME_RESEARCHDIRECTOR, JOB_NAME_CHIEFMEDICALOFFICER, JOB_NAME_MASTERATARMS) //NSV13 - added MAA
- antag_flag = ROLE_INCURSION
+ role_preference = /datum/role_preference/antagonist/incursionist
+ antag_datum = /datum/antagonist/incursion
false_report_weight = 10
- enemy_minimum_age = 0
announce_span = "danger"
announce_text = "A large force of syndicate operatives have infiltrated the ranks of the station and wish to take it by force!\n\
@@ -30,8 +30,6 @@
if(CONFIG_GET(flag/protect_assistant_from_antagonist))
restricted_jobs += JOB_NAME_ASSISTANT
- var/list/datum/mind/possible_traitors = get_players_for_role(ROLE_INCURSION)
-
var/datum/team/incursion/team = new
var/cost_base = CONFIG_GET(number/incursion_cost_base)
var/cost_increment = CONFIG_GET(number/incursion_cost_increment)
@@ -41,11 +39,10 @@
team_size = CLAMP(team_size, CONFIG_GET(number/incursion_count_min), CONFIG_GET(number/incursion_count_max))
for(var/k = 1 to team_size)
- var/datum/mind/incursion = antag_pick(possible_traitors, ROLE_INCURSION)
+ var/datum/mind/incursion = antag_pick(antag_candidates, /datum/role_preference/antagonist/incursionist)
if(!incursion)
message_admins("Ran out of people to put in an incursion team, wanted [team_size] but only got [k-1]")
break
- possible_traitors -= incursion
antag_candidates -= incursion
team.add_member(incursion)
incursion.special_role = ROLE_INCURSION
diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm
index 281f3507fe3..9d2880be163 100644
--- a/code/game/gamemodes/nuclear/nuclear.dm
+++ b/code/game/gamemodes/nuclear/nuclear.dm
@@ -8,8 +8,8 @@
required_players = 30 // 30 players - 3 players to be the nuke ops = 27 players remaining
required_enemies = 2
recommended_enemies = 5
- antag_flag = ROLE_OPERATIVE
- enemy_minimum_age = 14
+ role_preference = /datum/role_preference/antagonist/nuclear_operative
+ antag_datum = /datum/antagonist/nukeop
announce_span = "danger"
announce_text = "Syndicate forces are approaching the station in an attempt to destroy it!\n\
@@ -31,7 +31,7 @@
var/n_agents = min(round(num_players() / 10), antag_candidates.len, agents_possible)
if(n_agents >= required_enemies)
for(var/i = 0, i < n_agents, ++i)
- var/datum/mind/new_op = antag_pick(antag_candidates, ROLE_OPERATIVE)
+ var/datum/mind/new_op = antag_pick(antag_candidates, /datum/role_preference/antagonist/nuclear_operative)
pre_nukeops += new_op
new_op.assigned_role = "Nuclear Operative"
new_op.special_role = "Nuclear Operative"
@@ -160,7 +160,7 @@
E.implant(H)
var/obj/item/implant/weapons_auth/W = new/obj/item/implant/weapons_auth(H)
W.implant(H)
- H.faction |= ROLE_SYNDICATE
+ H.faction |= FACTION_SYNDICATE
H.update_icons()
/datum/outfit/syndicate/full
diff --git a/code/game/gamemodes/overthrow/overthrow.dm b/code/game/gamemodes/overthrow/overthrow.dm
index 0783c862f5e..9fd0cd3863e 100644
--- a/code/game/gamemodes/overthrow/overthrow.dm
+++ b/code/game/gamemodes/overthrow/overthrow.dm
@@ -3,7 +3,8 @@
name = "overthrow"
config_tag = "overthrow"
report_type = "overthrow"
- antag_flag = ROLE_OVERTHROW
+ role_preference = /datum/role_preference/antagonist/traitor // use traitor role pref
+ antag_datum = /datum/antagonist/overthrow
restricted_jobs = list(JOB_NAME_SECURITYOFFICER, JOB_NAME_WARDEN, JOB_NAME_DETECTIVE, JOB_NAME_AI, JOB_NAME_CYBORG,JOB_NAME_CAPTAIN, JOB_NAME_HEADOFPERSONNEL, JOB_NAME_HEADOFSECURITY, JOB_NAME_CHIEFENGINEER, JOB_NAME_RESEARCHDIRECTOR, JOB_NAME_CHIEFMEDICALOFFICER, JOB_NAME_MASTERATARMS) //NSV13 - added MAA
required_players = 20 // the core idea is of a swift, bloodless coup, so it shouldn't be as chaotic as revs.
required_enemies = 2 // minimum two teams, otherwise it's just nerfed revs.
@@ -28,7 +29,7 @@
for (var/i in 1 to sleeping_agents)
if (!antag_candidates.len)
break
- var/datum/mind/sleeping_agent = antag_pick(antag_candidates, ROLE_OVERTHROW)
+ var/datum/mind/sleeping_agent = antag_pick(antag_candidates, /datum/role_preference/antagonist/traitor)
antag_candidates -= sleeping_agent
initial_agents += sleeping_agent
sleeping_agent.restricted_roles = restricted_jobs
diff --git a/code/game/gamemodes/revolution/revolution.dm b/code/game/gamemodes/revolution/revolution.dm
index 0ff58d3c82b..a635784064a 100644
--- a/code/game/gamemodes/revolution/revolution.dm
+++ b/code/game/gamemodes/revolution/revolution.dm
@@ -11,14 +11,14 @@
name = "revolution"
config_tag = "revolution"
report_type = "revolution"
- antag_flag = ROLE_REV
+ role_preference = /datum/role_preference/antagonist/revolutionary
+ antag_datum = /datum/antagonist/rev/head
false_report_weight = 10
restricted_jobs = list(JOB_NAME_SECURITYOFFICER, JOB_NAME_WARDEN, JOB_NAME_DETECTIVE, JOB_NAME_AI, JOB_NAME_CYBORG,JOB_NAME_CAPTAIN, JOB_NAME_HEADOFPERSONNEL, JOB_NAME_HEADOFSECURITY, JOB_NAME_CHIEFENGINEER, JOB_NAME_RESEARCHDIRECTOR, JOB_NAME_CHIEFMEDICALOFFICER, JOB_NAME_MASTERATARMS) //NSV13 - added MAA
required_jobs = list(list(JOB_NAME_CAPTAIN=1),list(JOB_NAME_HEADOFPERSONNEL=1),list(JOB_NAME_HEADOFSECURITY=1),list(JOB_NAME_CHIEFENGINEER=1),list(JOB_NAME_RESEARCHDIRECTOR=1),list(JOB_NAME_CHIEFMEDICALOFFICER=1),list(JOB_NAME_MASTERATARMS=1)) //Any head present //NSV13 - added MAA
required_players = 30
required_enemies = 2
recommended_enemies = 3
- enemy_minimum_age = 14
title_icon = "revolution"
announce_span = "danger"
@@ -55,7 +55,7 @@
for (var/i=1 to max_headrevs)
if (antag_candidates.len==0)
break
- var/datum/mind/lenin = antag_pick(antag_candidates, ROLE_REV_HEAD)
+ var/datum/mind/lenin = antag_pick(antag_candidates, /datum/role_preference/antagonist/revolutionary)
antag_candidates -= lenin
headrev_candidates += lenin
lenin.restricted_roles = restricted_jobs
diff --git a/code/game/gamemodes/traitor/double_agents.dm b/code/game/gamemodes/traitor/double_agents.dm
index 7e3db6e86c4..b5b6f9bbecc 100644
--- a/code/game/gamemodes/traitor/double_agents.dm
+++ b/code/game/gamemodes/traitor/double_agents.dm
@@ -12,11 +12,11 @@
recommended_enemies = 8
reroll_friendly = 0
traitor_name = "Nanotrasen Internal Affairs Agent"
- antag_flag = ROLE_INTERNAL_AFFAIRS
+ antag_datum = /datum/antagonist/traitor/internal_affairs
+ role_preference = /datum/role_preference/antagonist/internal_affairs
traitors_possible = 10 //hard limit on traitors if scaling is turned off
num_modifier = 4 // Four additional traitors
- antag_datum = /datum/antagonist/traitor/internal_affairs
announce_text = "There are Nanotrasen Internal Affairs Agents trying to kill each other!\n\
IAA: Eliminate your targets and protect yourself!\n\
diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm
index b87f81f8570..30a6cea5124 100644
--- a/code/game/gamemodes/traitor/traitor.dm
+++ b/code/game/gamemodes/traitor/traitor.dm
@@ -9,7 +9,8 @@
name = "traitor"
config_tag = "traitor"
report_type = "traitor"
- antag_flag = ROLE_TRAITOR
+ role_preference = /datum/role_preference/antagonist/traitor
+ antag_datum = /datum/antagonist/traitor
false_report_weight = 20 //Reports of traitors are pretty common.
restricted_jobs = list(JOB_NAME_CYBORG)//They are part of the AI if he is traitor so are they, they use to get double chances
protected_jobs = list(JOB_NAME_SECURITYOFFICER, JOB_NAME_WARDEN, JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN, JOB_NAME_PILOT, JOB_NAME_MASTERATARMS) //NSV13 added pilots and master at arms
@@ -17,7 +18,6 @@
required_enemies = 1
recommended_enemies = 4
reroll_friendly = 1
- enemy_minimum_age = 0
announce_span = "danger"
announce_text = "There are Syndicate agents on the station!\n\
@@ -29,7 +29,6 @@
var/list/datum/mind/pre_traitors = list()
var/traitors_possible = 4 //hard limit on traitors if scaling is turned off
var/num_modifier = 0 // Used for gamemodes, that are a child of traitor, that need more than the usual.
- var/antag_datum = /datum/antagonist/traitor //what type of antag to create
var/traitors_required = TRUE //Will allow no traitors
@@ -55,7 +54,7 @@
for(var/j = 0, j < num_traitors, j++)
if (!antag_candidates.len)
break
- var/datum/mind/traitor = antag_pick(antag_candidates, ROLE_TRAITOR)
+ var/datum/mind/traitor = antag_pick(antag_candidates, /datum/role_preference/antagonist/traitor)
pre_traitors += traitor
traitor.special_role = traitor_name
traitor.restricted_roles = restricted_jobs
@@ -90,11 +89,13 @@
if((SSticker.mode.traitors.len + pre_traitors.len) >= traitorcap) //Upper cap for number of latejoin antagonists
return
if((SSticker.mode.traitors.len + pre_traitors.len) <= (traitorcap - 2) || prob(100 / (tsc * 2)))
- if(antag_flag in character.client.prefs.be_special)
- if(!is_banned_from(character.ckey, list(ROLE_TRAITOR, ROLE_SYNDICATE)) && !QDELETED(character))
- if(age_check(character.client))
- if(!(character.job in restricted_jobs))
- add_latejoin_traitor(character.mind)
+ if(!QDELETED(character) && character.client?.should_include_for_role(
+ banning_key = initial(antag_datum.banning_key),
+ role_preference_key = role_preference,
+ req_hours = initial(antag_datum.required_living_playtime),
+ ))
+ if(!(character.job in restricted_jobs))
+ add_latejoin_traitor(character.mind)
/datum/game_mode/traitor/proc/add_latejoin_traitor(datum/mind/character)
var/datum/antagonist/traitor/new_antag = new antag_datum()
diff --git a/code/game/gamemodes/wizard/wizard.dm b/code/game/gamemodes/wizard/wizard.dm
index f72b5041322..f58b8b6c09d 100644
--- a/code/game/gamemodes/wizard/wizard.dm
+++ b/code/game/gamemodes/wizard/wizard.dm
@@ -6,12 +6,12 @@
name = "wizard"
config_tag = "wizard"
report_type = "wizard"
- antag_flag = ROLE_WIZARD
+ role_preference = /datum/role_preference/antagonist/wizard
+ antag_datum = /datum/antagonist/wizard
false_report_weight = 10
required_players = 20
required_enemies = 1
recommended_enemies = 1
- enemy_minimum_age = 14
round_ends_with_antag_death = 1
announce_span = "danger"
announce_text = "There is a space wizard attacking the station!\n\
@@ -22,7 +22,7 @@
title_icon = "wizard"
/datum/game_mode/wizard/pre_setup()
- var/datum/mind/wizard = antag_pick(antag_candidates, ROLE_WIZARD)
+ var/datum/mind/wizard = antag_pick(antag_candidates, /datum/role_preference/antagonist/wizard)
wizards += wizard
wizard.assigned_role = ROLE_WIZARD
wizard.special_role = ROLE_WIZARD
diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm
index f3e600f570d..f3b490f4993 100644
--- a/code/game/machinery/cloning.dm
+++ b/code/game/machinery/cloning.dm
@@ -297,7 +297,7 @@
/obj/machinery/clonepod/proc/offer_to_ghost(mob/living/carbon/H)
set waitfor = FALSE
- var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [H.real_name]'s experimental clone?", ROLE_EXPERIMENTAL_CLONE, null, null, 300, H, POLL_IGNORE_EXPERIMENTAL_CLONE)
+ var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [H.real_name]'s experimental clone?", ROLE_EXPERIMENTAL_CLONE, null, 30 SECONDS, H)
if(length(candidates))
var/mob/dead/observer/C = pick(candidates)
H.key = C.key
diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm
index 9830d6e5454..e60327d47be 100644
--- a/code/game/machinery/porta_turret/portable_turret.dm
+++ b/code/game/machinery/porta_turret/portable_turret.dm
@@ -424,7 +424,7 @@
if(iscyborg(sillycone))
var/mob/living/silicon/robot/sillyconerobot = A
- if((ROLE_SYNDICATE in faction) && sillyconerobot.emagged == TRUE)
+ if((FACTION_SYNDICATE in faction) && sillyconerobot.emagged == TRUE)
continue
else if(iscarbon(A))
@@ -686,7 +686,7 @@
stun_projectile_sound = 'sound/weapons/gunshot.ogg'
icon_state = "syndie_off"
base_icon_state = "syndie"
- faction = list(ROLE_SYNDICATE)
+ faction = list(FACTION_SYNDICATE)
desc = "A ballistic machine gun auto-turret."
/obj/machinery/porta_turret/syndicate/ComponentInitialize()
diff --git a/code/game/objects/effects/anomalies.dm b/code/game/objects/effects/anomalies.dm
index 68dcf131774..0a932d2a8b0 100644
--- a/code/game/objects/effects/anomalies.dm
+++ b/code/game/objects/effects/anomalies.dm
@@ -329,7 +329,7 @@
S.amount_grown = SLIME_EVOLUTION_THRESHOLD
S.Evolve()
S.flavor_text = FLAVOR_TEXT_EVIL
- S.set_playable()
+ S.set_playable(ROLE_PYRO_SLIME)
/////////////////////
diff --git a/code/game/objects/items/holy_weapons.dm b/code/game/objects/items/holy_weapons.dm
index 36845c8446d..3779a8f4450 100644
--- a/code/game/objects/items/holy_weapons.dm
+++ b/code/game/objects/items/holy_weapons.dm
@@ -518,7 +518,7 @@
possessed = TRUE
- var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you want to play as the spirit of [user.real_name]'s blade?", ROLE_PAI, null, FALSE, 100, POLL_IGNORE_POSSESSED_BLADE)
+ var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you want to play as the spirit of [user.real_name]'s blade?", ROLE_SPECTRAL_BLADE, null, 10 SECONDS, ignore_category = POLL_IGNORE_SPECTRAL_BLADE)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
diff --git a/code/game/objects/structures/ghost_role_spawners.dm b/code/game/objects/structures/ghost_role_spawners.dm
index d3156ca1370..244549a5f29 100644
--- a/code/game/objects/structures/ghost_role_spawners.dm
+++ b/code/game/objects/structures/ghost_role_spawners.dm
@@ -18,6 +18,7 @@
Estimated time of last contact: Deployment, 5000 millennia ago."
assignedrole = "Lifebringer"
use_cooldown = TRUE
+ banType = ROLE_LIFEBRINGER
/obj/effect/mob_spawn/human/seed_vault/special(mob/living/new_spawn)
var/plant_name = pick("Tomato", "Potato", "Broccoli", "Carrot", "Ambrosia", "Pumpkin", "Ivy", "Kudzu", "Banana", "Moss", "Flower", "Bloom", "Root", "Bark", "Glowshroom", "Petal", "Leaf", \
@@ -54,6 +55,7 @@
assignedrole = "Ash Walker"
var/datum/team/ashwalkers/team
use_cooldown = TRUE
+ banType = ROLE_ASHWALKER
/obj/effect/mob_spawn/human/ash_walker/special(mob/living/new_spawn)
to_chat(new_spawn, "Drag the corpses of men and beasts to your nest. It will absorb them to create more of your kind. Don't leave your nest undefended, protect it with your life. Glory to the Necropolis!")
@@ -78,40 +80,6 @@
head = /obj/item/clothing/head/helmet/gladiator
uniform = /obj/item/clothing/under/costume/gladiator/ash_walker
-
-//Timeless prisons: Spawns in Wish Granter prisons in lavaland. Ghosts become age-old users of the Wish Granter and are advised to seek repentance for their past.
-/obj/effect/mob_spawn/human/exile
- name = "timeless prison"
- desc = "Although this stasis pod looks medicinal, it seems as though it's meant to preserve something for a very long time."
- mob_name = "a penitent exile"
- icon = 'icons/obj/machines/sleeper.dmi'
- icon_state = "sleeper"
- roundstart = FALSE
- death = FALSE
- mob_species = /datum/species/shadow
- short_desc = "You are cursed."
- flavour_text = "Years ago, you sacrificed the lives of your trusted friends and the humanity of yourself to reach the Wish Granter. Though you \
- did so, it has come at a cost: your very body rejects the light, dooming you to wander endlessly in this horrible wasteland."
- assignedrole = "Exile"
- use_cooldown = TRUE
-
-/obj/effect/mob_spawn/human/exile/Destroy()
- new/obj/structure/fluff/empty_sleeper(get_turf(src))
- return ..()
-
-/obj/effect/mob_spawn/human/exile/special(mob/living/new_spawn)
- new_spawn.fully_replace_character_name(null,"Wish Granter's Victim ([rand(1,999)])")
- var/wish = rand(1,4)
- switch(wish)
- if(1)
- to_chat(new_spawn, "You wished to kill, and kill you did. You've lost track of how many, but the spark of excitement that murder once held has winked out. You feel only regret.")
- if(2)
- to_chat(new_spawn, "You wished for unending wealth, but no amount of money was worth this existence. Maybe charity might redeem your soul?")
- if(3)
- to_chat(new_spawn, "You wished for power. Little good it did you, cast out of the light. You are the [gender == MALE ? "king" : "queen"] of a hell that holds no subjects. You feel only remorse.")
- if(4)
- to_chat(new_spawn, "You wished for immortality, even as your friends lay dying behind you. No matter how many times you cast yourself into the lava, you awaken in this room again within a few days. There is no escape.")
-
//Golem shells: Spawns in Free Golem ships in lavaland. Ghosts become mineral golems and are advised to spread personal freedom.
/obj/effect/mob_spawn/human/golem
name = "inert free golem shell"
@@ -132,6 +100,7 @@
flavour_text = "In his infinite and divine wisdom, he set your clan free to \
travel the stars with a single declaration: \"Yeah go do whatever.\" Though you are bound to the one who created you, it is customary in your society to repeat those same words to newborn \
golems, so that no golem may ever be forced to serve again."
+ banType = ROLE_FREE_GOLEM
/obj/effect/mob_spawn/human/golem/Initialize(mapload, datum/species/golem/species = null, mob/creator = null)
if(species) //spawners list uses object name to register so this goes before ..()
@@ -206,6 +175,7 @@
can_transfer = FALSE
mob_species = /datum/species/golem/adamantine
use_cooldown = TRUE //Only the roundstart free golems are
+ banType = ROLE_FREE_GOLEM
//Malfunctioning cryostasis sleepers: Spawns in makeshift shelters in lavaland. Ghosts become hermits with knowledge of how they got to where they are now.
/obj/effect/mob_spawn/human/hermit
@@ -224,6 +194,7 @@
the fresh air of Earth. These thoughts are dispelled by yet another recollection of how you got here... "
assignedrole = "Hermit"
use_cooldown = TRUE
+ banType = ROLE_HERMIT
/obj/effect/mob_spawn/human/hermit/Initialize(mapload)
. = ..()
@@ -266,6 +237,7 @@
all you did was apply bruise packs. Why is this place full of advanced medical equipment? And what are those screams you hear? The world outside is desolate - tormented with fire and brimstone. But you took an oath. \
You have to save these people! You might not have a fancy cloning machine like a real hospital, but surely there must be some way to save these people with the tools you have. Right?"
assignedrole = "Translocated Vet"
+ banType = ROLE_TRANSLOCATED_VET
/obj/effect/mob_spawn/human/doctor/alive/lavaland/Destroy()
var/obj/structure/fluff/empty_sleeper/S = new(drop_location())
@@ -287,6 +259,7 @@
flavour_text = "Good. It seems as though your ship crashed. You remember that you were convicted of "
assignedrole = "Escaped Prisoner"
use_cooldown = TRUE
+ banType = ROLE_LAVALAND_ESCAPED_PRISONER
/obj/effect/mob_spawn/human/prisoner_transport/special(mob/living/L)
L.fully_replace_character_name(null,"NTP #LL-0[rand(111,999)]") //Nanotrasen Prisoner #Lavaland-(numbers)
@@ -327,6 +300,7 @@
important_info = "DON'T leave the hotel"
assignedrole = "Hotel Staff"
use_cooldown = TRUE
+ banType = ROLE_HOTEL_STAFF
/datum/outfit/hotelstaff
name = "Hotel Staff"
@@ -374,6 +348,7 @@
var/obj/effect/proc_holder/spell/targeted/summon_friend/spell
var/datum/mind/owner
assignedrole = "SuperFriend"
+ banType = ROLE_DEMONIC_FRIEND
/obj/effect/mob_spawn/human/demonic_friend/Initialize(mapload, datum/mind/owner_mind, obj/effect/proc_holder/spell/targeted/summon_friend/summoning_spell)
. = ..()
@@ -414,77 +389,6 @@
implants = list(/obj/item/implant/mindshield) //No revolutionaries, he's MY friend.
id = /obj/item/card/id
-/obj/effect/mob_spawn/human/syndicate
- name = "Syndicate Operative"
- roundstart = FALSE
- death = FALSE
- icon = 'icons/obj/machines/sleeper.dmi'
- icon_state = "sleeper_s"
- outfit = /datum/outfit/syndicate_empty
- assignedrole = "Space Syndicate" //I know this is really dumb, but Syndicate operative is nuke ops
-
-/datum/outfit/syndicate_empty
- name = "Syndicate Operative Empty"
- uniform = /obj/item/clothing/under/syndicate
- shoes = /obj/item/clothing/shoes/combat
- gloves = /obj/item/clothing/gloves/combat
- ears = /obj/item/radio/headset/syndicate/alt
- back = /obj/item/storage/backpack
- implants = list(/obj/item/implant/weapons_auth)
- id = /obj/item/card/id/syndicate
-
-/datum/outfit/syndicate_empty/post_equip(mob/living/carbon/human/H)
- H.faction |= ROLE_SYNDICATE
-
-/obj/effect/mob_spawn/human/syndicate/battlecruiser
- name = "Syndicate Battlecruiser Ship Operative"
- short_desc = "You are a crewmember aboard the syndicate flagship: the SBC Starfury."
- flavour_text = "Your job is to follow your captain's orders, maintain the ship, and keep the engine running. If you are not familiar with how the supermatter engine functions: do not attempt to start it."
- important_info = "The armory is not a candy store, and your role is not to assault the station directly, leave that work to the assault operatives."
- outfit = /datum/outfit/syndicate_empty/SBC
-
-/datum/outfit/syndicate_empty/SBC
- name = "Syndicate Battlecruiser Ship Operative"
- l_pocket = /obj/item/gun/ballistic/automatic/pistol
- r_pocket = /obj/item/kitchen/knife/combat/survival
- belt = /obj/item/storage/belt/military/assault
-
-/obj/effect/mob_spawn/human/syndicate/battlecruiser/assault
- name = "Syndicate Battlecruiser Assault Operative"
- short_desc = "You are an assault operative aboard the syndicate flagship: the SBC Starfury."
- flavour_text = "Your job is to follow your captain's orders, keep intruders out of the ship, and assault Space Station 13. There is an armory, multiple assault ships, and beam cannons to attack the station with."
- important_info = "Work as a team with your fellow operatives and work out a plan of attack. If you are overwhelmed, escape back to your ship!"
- outfit = /datum/outfit/syndicate_empty/SBC/assault
-
-/datum/outfit/syndicate_empty/SBC/assault
- name = "Syndicate Battlecruiser Assault Operative"
- uniform = /obj/item/clothing/under/syndicate/combat
- l_pocket = /obj/item/ammo_box/magazine/m10mm
- r_pocket = /obj/item/kitchen/knife/combat/survival
- belt = /obj/item/storage/belt/military
- suit = /obj/item/clothing/suit/armor/vest
- suit_store = /obj/item/gun/ballistic/automatic/pistol
- back = /obj/item/storage/backpack/security
- mask = /obj/item/clothing/mask/gas/syndicate
-
-/obj/effect/mob_spawn/human/syndicate/battlecruiser/captain
- name = "Syndicate Battlecruiser Captain"
- short_desc = "You are the captain aboard the syndicate flagship: the SBC Starfury."
- flavour_text = "Your job is to oversee your crew, defend the ship, and destroy Space Station 13. The ship has an armory, multiple ships, beam cannons, and multiple crewmembers to accomplish this goal."
- important_info = "As the captain, this whole operation falls on your shoulders. You do not need to nuke the station, causing sufficient damage and preventing your ship from being destroyed will be enough."
- outfit = /datum/outfit/syndicate_empty/SBC/assault/captain
- id_access_list = list(150,151)
-
-/datum/outfit/syndicate_empty/SBC/assault/captain
- name = "Syndicate Battlecruiser Captain"
- l_pocket = /obj/item/melee/transforming/energy/sword/saber/red
- r_pocket = /obj/item/melee/classic_baton/police/telescopic
- suit = /obj/item/clothing/suit/armor/vest/capcarapace/syndicate
- suit_store = /obj/item/gun/ballistic/revolver/mateba
- back = /obj/item/storage/backpack/satchel/leather
- head = /obj/item/clothing/head/HoS/syndicate
- mask = /obj/item/clothing/mask/cigarette/cigar/havana
- glasses = /obj/item/clothing/glasses/thermal/eyepatch
//Ancient cryogenic sleepers. Players become NT crewmen from a hundred year old space station, now on the verge of collapse.
/obj/effect/mob_spawn/human/oldsec
@@ -509,6 +413,7 @@
l_pocket = /obj/item/assembly/flash/handheld
assignedrole = "Ancient Crew"
use_cooldown = TRUE
+ banType = ROLE_ANCIENT_CREW
/obj/effect/mob_spawn/human/oldsec/Destroy()
new/obj/structure/showcase/machinery/oldpod/used(drop_location())
@@ -536,6 +441,7 @@
l_pocket = /obj/item/tank/internals/emergency_oxygen
assignedrole = "Ancient Crew"
use_cooldown = TRUE
+ banType = ROLE_ANCIENT_CREW
/obj/effect/mob_spawn/human/oldeng/Destroy()
new/obj/structure/showcase/machinery/oldpod/used(drop_location())
@@ -562,6 +468,7 @@
l_pocket = /obj/item/stack/medical/bruise_pack
assignedrole = "Ancient Crew"
use_cooldown = TRUE
+ banType = ROLE_ANCIENT_CREW
/obj/effect/mob_spawn/human/oldsci/Destroy()
new/obj/structure/showcase/machinery/oldpod/used(drop_location())
@@ -584,6 +491,7 @@
short_desc = "You are a space pirate."
flavour_text = "The station refused to pay for your protection, protect the ship, siphon the credits from the station and raid it for even more loot."
assignedrole = "Space Pirate"
+ is_antagonist = TRUE
var/rank = "Mate"
/obj/effect/mob_spawn/human/pirate/special(mob/living/new_spawn)
diff --git a/code/game/objects/structures/spawner.dm b/code/game/objects/structures/spawner.dm
index 0b41fcf8d49..8f7870e7b30 100644
--- a/code/game/objects/structures/spawner.dm
+++ b/code/game/objects/structures/spawner.dm
@@ -31,7 +31,7 @@
icon_state = "syndbeacon"
spawn_text = "warps in from"
mob_types = list(/mob/living/simple_animal/hostile/syndicate/ranged)
- faction = list(ROLE_SYNDICATE)
+ faction = list(FACTION_SYNDICATE)
/obj/structure/spawner/skeleton
name = "bone pit"
diff --git a/code/modules/admin/antag_panel.dm b/code/modules/admin/antag_panel.dm
index 3dc29f2d1cf..5b4f5087d99 100644
--- a/code/modules/admin/antag_panel.dm
+++ b/code/modules/admin/antag_panel.dm
@@ -165,11 +165,19 @@ GLOBAL_VAR(antag_prototypes)
continue
pref_source = prototype
break
- if(pref_source.job_rank)
- if(!is_banned_from(src.key, pref_source.job_rank))
- antag_header_parts += pref_source.enabled_in_preferences(src) ? "Enabled in Prefs" : "Disabled in Prefs"
- else
+ if(pref_source.banning_key)
+ if(is_banned_from(src.key, pref_source.banning_key))
antag_header_parts += "\[BANNED\]"
+ else if(current.client)
+ var/list/related_preferences = list()
+ for(var/datum/role_preference/role_pref_type as anything in GLOB.role_preference_entries)
+ if(initial(role_pref_type.antag_datum) == pref_source.type)
+ related_preferences += role_pref_type
+ if(length(related_preferences) == 1)
+ antag_header_parts += current.client.role_preference_enabled(related_preferences[1]) ? "Enabled in Prefs" : "Disabled in Prefs"
+ else if(length(related_preferences) >= 1)
+ for(var/datum/role_preference/preftype as anything in related_preferences)
+ antag_header_parts += "[initial(preftype.name)]: [current.client.role_preference_enabled(preftype) ? "Enabled Pref" : "Disabled Pref"]"
//Traitor : None | Traitor | IAA
// Command1 | Command2 | Command3
diff --git a/code/modules/admin/fun_balloon.dm b/code/modules/admin/fun_balloon.dm
index ca395efabda..33308c17d44 100644
--- a/code/modules/admin/fun_balloon.dm
+++ b/code/modules/admin/fun_balloon.dm
@@ -53,7 +53,7 @@
bodies += M
var/question = "Would you like to be [group_name]?"
- var/list/candidates = pollCandidatesForMobs(question, ROLE_PAI, null, FALSE, 100, bodies)
+ var/list/candidates = pollCandidatesForMobs(question, ROLE_SENTIENCE, null, 10 SECONDS, bodies)
while(LAZYLEN(candidates) && LAZYLEN(bodies))
var/mob/dead/observer/C = pick_n_take(candidates)
var/mob/living/body = pick_n_take(bodies)
diff --git a/code/modules/admin/secrets.dm b/code/modules/admin/secrets.dm
index 56759be507a..f05165e3a7a 100644
--- a/code/modules/admin/secrets.dm
+++ b/code/modules/admin/secrets.dm
@@ -690,7 +690,7 @@ GLOBAL_DATUM_INIT(admin_secrets, /datum/admin_secrets, new)
continue
if((L in GLOB.player_list) || L.mind || (L.flags_1 & HOLOGRAM_1))
continue
- L.set_playable()
+ L.set_playable(ROLE_SENTIENT_ANIMAL)
if("flipmovement")
if(!check_rights(R_FUN))
@@ -789,7 +789,7 @@ GLOBAL_DATUM_INIT(admin_secrets, /datum/admin_secrets, new)
var/list/candidates = list()
if (prefs["offerghosts"]["value"] == "Yes")
- candidates = pollGhostCandidates(replacetext(prefs["ghostpoll"]["value"], "%TYPE%", initial(pathToSpawn.name)), ROLE_TRAITOR)
+ candidates = pollGhostCandidates(replacetext(prefs["ghostpoll"]["value"], "%TYPE%", initial(pathToSpawn.name)), BAN_ROLE_ALL_ANTAGONISTS, ignore_category = FALSE)
if (prefs["playersonly"]["value"] == "Yes" && length(candidates) < prefs["minplayers"]["value"])
message_admins("Not enough players signed up to create a portal storm, the minimum was [prefs["minplayers"]["value"]] and the number of signups [length(candidates)]")
diff --git a/code/modules/admin/sql_ban_system.dm b/code/modules/admin/sql_ban_system.dm
index 9b0efda4aec..255360d94de 100644
--- a/code/modules/admin/sql_ban_system.dm
+++ b/code/modules/admin/sql_ban_system.dm
@@ -1,20 +1,36 @@
#define MAX_ADMINBANS_PER_ADMIN 1
#define MAX_ADMINBANS_PER_HEADMIN 3
+/// Process global ban types
+/proc/check_role_ban(ban_cache, role)
+ if(role in GLOB.antagonist_bannable_roles)
+ if((BAN_ROLE_ALL_ANTAGONISTS in ban_cache) || ("Syndicate" in ban_cache)) // Legacy "Syndicate" ban
+ return TRUE
+ if(role in GLOB.forced_bannable_roles)
+ if(BAN_ROLE_FORCED_ANTAGONISTS in ban_cache)
+ return TRUE
+ if(role in GLOB.ghost_role_bannable_roles)
+ if((BAN_ROLE_ALL_GHOST in ban_cache) || ("Lavaland" in ban_cache)) // Legacy "Lavaland" ban
+ return TRUE
+ return role in ban_cache
+
//checks client ban cache or DB ban table if ckey is banned from one or more roles
//doesn't return any details, use only for if statements
/proc/is_banned_from(player_ckey, list/roles)
- if(!player_ckey)
+ if(!player_ckey || isnull(roles) || (islist(roles) && !length(roles)))
return
+ player_ckey = ckey(player_ckey)
var/client/C = GLOB.directory[player_ckey]
if(C)
if(!C.ban_cache)
build_ban_cache(C)
if(islist(roles))
for(var/R in roles)
- if(R in C.ban_cache)
+ if(!R)
+ continue
+ if(check_role_ban(C.ban_cache, R))
return TRUE //they're banned from at least one role, no need to keep checking
- else if(roles in C.ban_cache)
+ else if(check_role_ban(C.ban_cache, roles))
return TRUE
else
var/values = list(
@@ -325,16 +341,14 @@
"}
break_counter++
output += ""
- var/list/long_job_lists = list(("Civilian" = GLOB.civilian_positions | JOB_NAME_GIMMICK),
- "Ghost and Other Roles" = list(ROLE_BRAINWASHED, ROLE_DEATHSQUAD, ROLE_DRONE, ROLE_LAVALAND, ROLE_MIND_TRANSFER, ROLE_POSIBRAIN, ROLE_SENTIENCE),
- "Antagonist Positions" = list(ROLE_ABDUCTOR, ROLE_ALIEN, ROLE_BLOB,
- ROLE_BROTHER, ROLE_CHANGELING, ROLE_CULTIST, ROLE_HERETIC,
- ROLE_DEVIL, ROLE_INTERNAL_AFFAIRS, ROLE_MALF,
- ROLE_NINJA, ROLE_OPERATIVE,
- ROLE_SERVANT_OF_RATVAR,
- ROLE_OVERTHROW, ROLE_REV, ROLE_REVENANT,
- ROLE_REV_HEAD, ROLE_SYNDICATE,
- ROLE_TRAITOR, ROLE_WIZARD, ROLE_HIVE, ROLE_GANG, ROLE_TERATOMA)) //ROLE_REV_HEAD is excluded from this because rev jobbans are handled by ROLE_REV
+ var/list/long_job_lists = list(
+ "Civilian" = GLOB.civilian_positions | JOB_NAME_GIMMICK,
+ "Antagonist Positions" = list(BAN_ROLE_ALL_ANTAGONISTS) + GLOB.antagonist_bannable_roles,
+ "Forced Antagonist Positions" = list(BAN_ROLE_FORCED_ANTAGONISTS) + GLOB.forced_bannable_roles,
+ "Ghost Roles" = list(BAN_ROLE_ALL_GHOST) + GLOB.ghost_role_bannable_roles,
+ "Other" = GLOB.other_bannable_roles,
+ )
+
for(var/department in long_job_lists)
output += "
"
break_counter = 0
diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm
index bcf50f3238b..b91367cca0b 100644
--- a/code/modules/admin/verbs/one_click_antag.dm
+++ b/code/modules/admin/verbs/one_click_antag.dm
@@ -27,10 +27,10 @@
popup.set_content(dat)
popup.open()
-/datum/admins/proc/isReadytoRumble(mob/living/carbon/human/applicant, targetrole, onstation = TRUE, conscious = TRUE)
+/datum/admins/proc/isReadytoRumble(mob/living/carbon/human/applicant, targetrole, preference, onstation = TRUE, conscious = TRUE)
if(applicant.mind.special_role)
return FALSE
- if(!(targetrole in applicant.client.prefs.be_special))
+ if(!applicant.client?.should_include_for_role(targetrole, preference))
return FALSE
if(onstation)
var/turf/T = get_turf(applicant)
@@ -40,7 +40,7 @@
return FALSE
if(!considered_alive(applicant.mind) || considered_afk(applicant.mind)) //makes sure the player isn't a zombie, brain, or just afk all together
return FALSE
- return !is_banned_from(applicant.ckey, list(targetrole, ROLE_SYNDICATE))
+ return TRUE
/datum/admins/proc/makeTraitors(maxCount = 3)
@@ -59,10 +59,9 @@
var/mob/living/carbon/human/H = null
for(var/mob/living/carbon/human/applicant in GLOB.player_list)
- if(isReadytoRumble(applicant, ROLE_TRAITOR))
- if(temp.age_check(applicant.client))
- if(!(applicant.job in temp.restricted_jobs))
- candidates += applicant
+ if(isReadytoRumble(applicant, ROLE_TRAITOR, /datum/role_preference/midround_living/traitor))
+ if(!(applicant.job in temp.restricted_jobs))
+ candidates += applicant
if(candidates.len)
var/numTraitors = min(candidates.len, maxCount)
@@ -94,10 +93,9 @@
var/mob/living/carbon/human/H = null
for(var/mob/living/carbon/human/applicant in GLOB.player_list)
- if(isReadytoRumble(applicant, ROLE_CHANGELING))
- if(temp.age_check(applicant.client))
- if(!(applicant.job in temp.restricted_jobs))
- candidates += applicant
+ if(isReadytoRumble(applicant, ROLE_CHANGELING, /datum/role_preference/antagonist/changeling))
+ if(!(applicant.job in temp.restricted_jobs))
+ candidates += applicant
if(candidates.len)
var/numChangelings = min(candidates.len, maxCount)
@@ -124,10 +122,9 @@
var/mob/living/carbon/human/H = null
for(var/mob/living/carbon/human/applicant in GLOB.player_list)
- if(isReadytoRumble(applicant, ROLE_REV))
- if(temp.age_check(applicant.client))
- if(!(applicant.job in temp.restricted_jobs))
- candidates += applicant
+ if(isReadytoRumble(applicant, ROLE_REV_HEAD, /datum/role_preference/antagonist/revolutionary))
+ if(!(applicant.job in temp.restricted_jobs))
+ candidates += applicant
if(candidates.len)
var/numRevs = min(candidates.len, maxCount)
@@ -142,7 +139,7 @@
/datum/admins/proc/makeWizard()
- var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you wish to be considered for the position of a Wizard Federation 'diplomat'?", ROLE_WIZARD, null)
+ var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you wish to be considered for the position of a Wizard Federation 'diplomat'?", ROLE_WIZARD, /datum/role_preference/midround_ghost/wizard, ignore_category = POLL_IGNORE_WIZARD_HELPER)
var/mob/dead/observer/selected = pick_n_take(candidates)
@@ -166,10 +163,9 @@
var/mob/living/carbon/human/H = null
for(var/mob/living/carbon/human/applicant in GLOB.player_list)
- if(isReadytoRumble(applicant, ROLE_CULTIST))
- if(temp.age_check(applicant.client))
- if(!(applicant.job in temp.restricted_jobs))
- candidates += applicant
+ if(isReadytoRumble(applicant, ROLE_CULTIST, /datum/role_preference/antagonist/blood_cultist))
+ if(!(applicant.job in temp.restricted_jobs))
+ candidates += applicant
if(candidates.len)
var/numCultists = min(candidates.len, maxCount)
@@ -186,8 +182,7 @@
/datum/admins/proc/makeNukeTeam(maxCount = 5)
- var/datum/game_mode/nuclear/temp = new
- var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you wish to be considered for a nuke team being sent in?", ROLE_OPERATIVE, temp)
+ var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you wish to be considered for a nuke team being sent in?", ROLE_OPERATIVE, /datum/role_preference/midround_ghost/nuclear_operative)
var/list/mob/dead/observer/chosen = list()
var/mob/dead/observer/theghost = null
@@ -351,7 +346,7 @@
ertemplate.enforce_human = prefs["enforce_human"]["value"] == "Yes" ? TRUE : FALSE
ertemplate.opendoors = prefs["open_armory"]["value"] == "Yes" ? TRUE : FALSE
- var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you wish to be considered for [ertemplate.polldesc] ?", "deathsquad", null, req_hours = 50)
+ var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you wish to be considered for [ertemplate.polldesc] ?", ROLE_ERT, req_hours = 50)
var/teamSpawned = FALSE
if(candidates.len > 0)
diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm
index b3fae2315a9..55bb88f5bed 100644
--- a/code/modules/admin/verbs/randomverbs.dm
+++ b/code/modules/admin/verbs/randomverbs.dm
@@ -300,7 +300,7 @@
for(var/mob/M in GLOB.player_list)
if(M.stat != DEAD)
continue //we are not dead!
- if(!(ROLE_ALIEN in M.client.prefs.be_special))
+ if(!M.client?.should_include_for_role(ROLE_ALIEN, /datum/role_preference/midround_ghost/xenomorph))
continue //we don't want to be an alium
if(M.client.is_afk())
continue //we are afk
@@ -474,7 +474,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
new_character.forceMove(pick(GLOB.wizardstart))
var/datum/antagonist/wizard/A = new_character.mind.has_antag_datum(/datum/antagonist/wizard,TRUE)
A.equip_wizard()
- if(ROLE_SYNDICATE)
+ if(ROLE_OPERATIVE)
new_character.forceMove(pick(GLOB.nukeop_start))
var/datum/antagonist/nukeop/N = new_character.mind.has_antag_datum(/datum/antagonist/nukeop,TRUE)
N.equip_op()
diff --git a/code/modules/antagonists/_common/antag_datum.dm b/code/modules/antagonists/_common/antag_datum.dm
index a7cc7e8c0d6..4da2f23239f 100644
--- a/code/modules/antagonists/_common/antag_datum.dm
+++ b/code/modules/antagonists/_common/antag_datum.dm
@@ -12,7 +12,10 @@ GLOBAL_LIST(admin_antag_list)
var/can_coexist_with_others = TRUE //Whether or not the person will be able to have more than one datum
var/list/typecache_datum_blacklist = list() //List of datums this type can't coexist with
var/delete_on_mind_deletion = TRUE
- var/job_rank
+ /// The ROLE_X key used for this antagonist.
+ var/banning_key
+ /// Required living playtime to be included in the rolling for this antagonist
+ var/required_living_playtime = 0
var/give_objectives = TRUE //Should the default objectives be generated?
var/replace_banned = TRUE //Should replace jobbanned player with ghosts if granted.
var/list/objectives = list()
@@ -114,12 +117,12 @@ GLOBAL_LIST(admin_antag_list)
/datum/antagonist/proc/is_banned(mob/M)
if(!M)
return FALSE
- . = (is_banned_from(M.ckey, list(ROLE_SYNDICATE, job_rank)) || QDELETED(M))
+ . = (is_banned_from(M.ckey, banning_key) || QDELETED(M))
/datum/antagonist/proc/replace_banned_player()
set waitfor = FALSE
- var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [name]?", job_rank, null, job_rank, 50, owner.current)
+ var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [name]?", banning_key, null, 7.5 SECONDS, owner.current, ignore_category = FALSE)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
to_chat(owner, "Your mob has been taken over by a ghost! Appeal your job ban if you want to avoid this in the future!")
@@ -127,6 +130,7 @@ GLOBAL_LIST(admin_antag_list)
owner.current.ghostize(FALSE)
owner.current.key = C.key
else
+ owner.current.playable_bantype = banning_key
owner.current.ghostize(FALSE,SENTIENCE_FORCE)
///Called by the remove_antag_datum() and remove_all_antag_datums() mind procs for the antag datum to handle its own removal and deletion.
@@ -221,14 +225,6 @@ GLOBAL_LIST(admin_antag_list)
/datum/antagonist/proc/antag_panel_data()
return ""
-/datum/antagonist/proc/enabled_in_preferences(datum/mind/M)
- if(job_rank)
- if(M.current && M.current.client && (job_rank in M.current.client.prefs.be_special))
- return TRUE
- else
- return FALSE
- return TRUE
-
// List if ["Command"] = CALLBACK(), user will be appeneded to callback arguments on execution
/datum/antagonist/proc/get_admin_commands()
. = list()
diff --git a/code/modules/antagonists/_common/antag_spawner.dm b/code/modules/antagonists/_common/antag_spawner.dm
index d17f6c8e2e9..eff42e0d677 100644
--- a/code/modules/antagonists/_common/antag_spawner.dm
+++ b/code/modules/antagonists/_common/antag_spawner.dm
@@ -58,7 +58,7 @@
if(used)
to_chat(H, "You already used this contract!")
return
- var/list/candidates = pollCandidatesForMob("Do you want to play as a wizard's [href_list["school"]] apprentice?", ROLE_WIZARD, null, ROLE_WIZARD, 150, src)
+ var/list/candidates = pollGhostCandidates("Do you want to play as a wizard's [href_list["school"]] apprentice?", ROLE_WIZARD, /datum/role_preference/midround_ghost/wizard, 15 SECONDS, ignore_category = POLL_IGNORE_WIZARD_HELPER)
if(LAZYLEN(candidates))
if(QDELETED(src))
return
@@ -123,7 +123,7 @@
return
to_chat(user, "You activate [src] and wait for confirmation.")
- var/list/nuke_candidates = pollGhostCandidates("Do you want to play as a syndicate [borg_to_spawn ? "[lowertext(borg_to_spawn)] cyborg":"operative"]?", ROLE_OPERATIVE, null, ROLE_OPERATIVE, 150, POLL_IGNORE_SYNDICATE)
+ var/list/nuke_candidates = pollGhostCandidates("Do you want to play as a syndicate [borg_to_spawn ? "[lowertext(borg_to_spawn)] cyborg":"operative"]?", ROLE_OPERATIVE, /datum/role_preference/midround_ghost/nuclear_operative, 15 SECONDS)
if(LAZYLEN(nuke_candidates))
if(QDELETED(src) || !check_usability(user))
return
@@ -243,7 +243,7 @@
return
if(used)
return
- var/list/candidates = pollCandidatesForMob("Do you want to play as a [initial(demon_type.name)]?", ROLE_ALIEN, null, ROLE_ALIEN, 50, src)
+ var/list/candidates = pollGhostCandidates("Do you want to play as a [initial(demon_type.name)]?", ROLE_SLAUGHTER_DEMON, null, 10 SECONDS, ignore_category = FALSE)
if(LAZYLEN(candidates))
if(used || QDELETED(src))
return
@@ -295,7 +295,7 @@
return
to_chat(user, "You activate [src] and wait for confirmation.")
- var/list/candidates = pollGhostCandidates("Do you want to play as a gangster reinforcements?", ROLE_GANG, null, ROLE_GANG, 150)
+ var/list/candidates = pollGhostCandidates("Do you want to play as a gangster reinforcements?", ROLE_GANG, /datum/role_preference/antagonist/gangster, 15 SECONDS)
if(LAZYLEN(candidates))
if(QDELETED(src) || !check_usability(user))
return
diff --git a/code/modules/antagonists/abductor/abductor.dm b/code/modules/antagonists/abductor/abductor.dm
index 4973e420256..054c9d137bf 100644
--- a/code/modules/antagonists/abductor/abductor.dm
+++ b/code/modules/antagonists/abductor/abductor.dm
@@ -4,7 +4,7 @@
name = "Abductor"
roundend_category = "abductors"
antagpanel_category = "Abductor"
- job_rank = ROLE_ABDUCTOR
+ banning_key = ROLE_ABDUCTOR
show_in_antagpanel = FALSE //should only show subtypes
show_to_ghosts = TRUE
var/datum/team/abductor_team/team
@@ -179,6 +179,7 @@
name = "Abductee"
roundend_category = "abductees"
antagpanel_category = "Abductee"
+ banning_key = UNBANNABLE_ANTAGONIST
/datum/antagonist/abductee/on_gain()
give_objective()
diff --git a/code/modules/antagonists/ashwalker/ashwalker.dm b/code/modules/antagonists/ashwalker/ashwalker.dm
index f7a35eb0a31..5f767a84800 100644
--- a/code/modules/antagonists/ashwalker/ashwalker.dm
+++ b/code/modules/antagonists/ashwalker/ashwalker.dm
@@ -4,7 +4,7 @@
/datum/antagonist/ashwalker
name = "Ash Walker"
- job_rank = ROLE_LAVALAND
+ banning_key = ROLE_ASHWALKER
show_in_antagpanel = FALSE
show_to_ghosts = TRUE
prevent_roundtype_conversion = FALSE
diff --git a/code/modules/antagonists/blob/blob.dm b/code/modules/antagonists/blob/blob.dm
index 9c58e95630b..802b38735b6 100644
--- a/code/modules/antagonists/blob/blob.dm
+++ b/code/modules/antagonists/blob/blob.dm
@@ -3,7 +3,7 @@
roundend_category = "blobs"
antagpanel_category = "Blob"
show_to_ghosts = TRUE
- job_rank = ROLE_BLOB
+ banning_key = ROLE_BLOB
var/datum/action/innate/blobpop/pop_action
var/starting_points_human_blob = 60
diff --git a/code/modules/antagonists/blob/blob_mobs.dm b/code/modules/antagonists/blob/blob_mobs.dm
index 33bc9acd69a..f67e4d2aeca 100644
--- a/code/modules/antagonists/blob/blob_mobs.dm
+++ b/code/modules/antagonists/blob/blob_mobs.dm
@@ -7,7 +7,7 @@
/mob/living/simple_animal/hostile/blob
icon = 'icons/mob/blob.dmi'
pass_flags = PASSBLOB
- faction = list(ROLE_BLOB)
+ faction = list(FACTION_BLOB)
bubble_icon = "blob"
speak_emote = null //so we use verb_yell/verb_say/etc
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
@@ -166,7 +166,7 @@
update_icons()
visible_message("The corpse of [H.name] suddenly rises!")
if(!key)
- set_playable()
+ set_playable(ROLE_BLOB)
/mob/living/simple_animal/hostile/blob/blobspore/death(gibbed)
// On death, create a small smoke of harmful gas (s-Acid)
diff --git a/code/modules/antagonists/blob/blobstrains/explosive_lattice.dm b/code/modules/antagonists/blob/blobstrains/explosive_lattice.dm
index 82528d95828..7714ab6944c 100644
--- a/code/modules/antagonists/blob/blobstrains/explosive_lattice.dm
+++ b/code/modules/antagonists/blob/blobstrains/explosive_lattice.dm
@@ -31,7 +31,7 @@
var/obj/effect/temp_visual/explosion/fast/E = new /obj/effect/temp_visual/explosion/fast(get_turf(M))
E.alpha = 150
for(var/mob/living/L in ohearers(1, get_turf(M)))
- if(ROLE_BLOB in L.faction) //no friendly fire
+ if(FACTION_BLOB in L.faction) //no friendly fire
continue
var/aoe_volume = ..(L, TOUCH, initial_volume, 0, L.get_permeability_protection(), O)
L.apply_damage(0.4*aoe_volume, BRUTE)
diff --git a/code/modules/antagonists/blob/overmind.dm b/code/modules/antagonists/blob/overmind.dm
index 2c57a7da6dd..b2139d3cbac 100644
--- a/code/modules/antagonists/blob/overmind.dm
+++ b/code/modules/antagonists/blob/overmind.dm
@@ -18,7 +18,7 @@ GLOBAL_LIST_EMPTY(blob_nodes)
layer = FLY_LAYER
pass_flags = PASSBLOB
- faction = list(ROLE_BLOB)
+ faction = list(FACTION_BLOB)
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
hud_type = /datum/hud/blob_overmind
var/obj/structure/blob/core/blob_core = null // The blob overmind's core
@@ -145,7 +145,7 @@ GLOBAL_LIST_EMPTY(blob_nodes)
if(!(Ablob.area_flags & BLOBS_ALLOWED))
continue
- if(!(ROLE_BLOB in L.faction))
+ if(!(FACTION_BLOB in L.faction))
playsound(L, 'sound/effects/splat.ogg', 50, 1)
L.death()
new/mob/living/simple_animal/hostile/blob/blobspore(T)
diff --git a/code/modules/antagonists/blob/powers.dm b/code/modules/antagonists/blob/powers.dm
index 706abeef12a..1040673e8b8 100644
--- a/code/modules/antagonists/blob/powers.dm
+++ b/code/modules/antagonists/blob/powers.dm
@@ -16,13 +16,13 @@
if(!placement_override)
if(!pop_override)
for(var/mob/living/M in range(7, src))
- if(ROLE_BLOB in M.faction)
+ if(FACTION_BLOB in M.faction)
continue
if(M.client)
to_chat(src, "There is someone too close to place your blob core!")
return 0
for(var/mob/living/M in hearers(13, src))
- if(ROLE_BLOB in M.faction)
+ if(FACTION_BLOB in M.faction)
continue
if(M.client)
to_chat(src, "Someone could see your blob core from here!")
@@ -172,7 +172,7 @@
B.naut = TRUE //temporary placeholder to prevent creation of more than one per factory.
to_chat(src, "You attempt to produce a blobbernaut.")
- var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you want to play as a [blobstrain.name] blobbernaut?", ROLE_BLOB, null, ROLE_BLOB, 50) //players must answer rapidly
+ var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you want to play as a [blobstrain.name] blobbernaut?", ROLE_BLOB, /datum/role_preference/midround_ghost/blob, 7.5 SECONDS, ignore_category = POLL_IGNORE_BLOB_HELPER) //players must answer rapidly
if(LAZYLEN(candidates)) //if we got at least one candidate, they're a blobbernaut now.
B.max_integrity = initial(B.max_integrity) * 0.25 //factories that produced a blobbernaut have much lower health
B.obj_integrity = min(B.obj_integrity, B.max_integrity)
@@ -268,7 +268,7 @@
if(can_buy(BLOB_SPREAD_COST))
var/attacksuccess = FALSE
for(var/mob/living/L in T)
- if(ROLE_BLOB in L.faction) //no friendly/dead fire
+ if(FACTION_BLOB in L.faction) //no friendly/dead fire
continue
if(L.stat != DEAD)
attacksuccess = TRUE
diff --git a/code/modules/antagonists/blob/structures/_blob.dm b/code/modules/antagonists/blob/structures/_blob.dm
index dad188eaaaf..20dfcbb3aef 100644
--- a/code/modules/antagonists/blob/structures/_blob.dm
+++ b/code/modules/antagonists/blob/structures/_blob.dm
@@ -253,7 +253,7 @@
/obj/structure/blob/attack_animal(mob/living/simple_animal/M)
- if(ROLE_BLOB in M.faction) //sorry, but you can't kill the blob as a blobbernaut
+ if(FACTION_BLOB in M.faction) //sorry, but you can't kill the blob as a blobbernaut
return
..()
diff --git a/code/modules/antagonists/blood_contract/blood_contract.dm b/code/modules/antagonists/blood_contract/blood_contract.dm
index f2faecdd458..c1b79bc13b1 100644
--- a/code/modules/antagonists/blood_contract/blood_contract.dm
+++ b/code/modules/antagonists/blood_contract/blood_contract.dm
@@ -4,6 +4,7 @@
show_in_antagpanel = FALSE
show_name_in_check_antagonists = TRUE
var/duration = 2 MINUTES
+ banning_key = UNBANNABLE_ANTAGONIST
/datum/antagonist/blood_contract/on_gain()
. = ..()
@@ -37,6 +38,7 @@
for(var/mob/living/carbon/human/P in GLOB.player_list)
if(P == H)
continue
+ log_game("[key_name(P)] was selected to kill [key_name(H)] by blood contract") // holy shit why is there no antag datum. I'm doing a huge refactor so I don't have time for one but I had to add this log here
to_chat(P, "You have an overwhelming desire to kill [H]. [H.p_theyve(TRUE)] been marked red! Whoever [H.p_they()] [H.p_were()], friend or foe, go kill [H.p_them()]!")
var/obj/item/I = new /obj/item/kitchen/knife/butcher(get_turf(P))
diff --git a/code/modules/antagonists/brainwashing/brainwashing.dm b/code/modules/antagonists/brainwashing/brainwashing.dm
index 57d082ec819..269e40ee32b 100644
--- a/code/modules/antagonists/brainwashing/brainwashing.dm
+++ b/code/modules/antagonists/brainwashing/brainwashing.dm
@@ -28,7 +28,7 @@
/datum/antagonist/brainwashed
name = "Brainwashed Victim"
- job_rank = ROLE_BRAINWASHED
+ banning_key = ROLE_BRAINWASHED
roundend_category = "brainwashed victims"
show_in_antagpanel = TRUE
antagpanel_category = "Other"
diff --git a/code/modules/antagonists/brother/brother.dm b/code/modules/antagonists/brother/brother.dm
index efdea659704..b48cf60aa7f 100644
--- a/code/modules/antagonists/brother/brother.dm
+++ b/code/modules/antagonists/brother/brother.dm
@@ -1,8 +1,8 @@
/datum/antagonist/brother
name = "Brother"
antagpanel_category = "Brother"
- job_rank = ROLE_BROTHER
- var/special_role = ROLE_BROTHER
+ banning_key = ROLE_BROTHER
+ required_living_playtime = 4
hijack_speed = 0.5
var/datum/team/brother_team/team
antag_moodlet = /datum/mood_event/focused
@@ -22,14 +22,14 @@
objectives += team.objectives
for(var/datum/objective/O in team.objectives)
log_objective(owner, O.explanation_text)
- owner.special_role = special_role
+ owner.special_role = ROLE_BROTHER
finalize_brother()
return ..()
/datum/antagonist/brother/on_removal()
SSticker.mode.brothers -= owner
if(owner.current)
- to_chat(owner.current,"You are no longer the [special_role]!")
+ to_chat(owner.current,"You are no longer the Blood Brother!")
owner.special_role = null
return ..()
@@ -56,7 +56,7 @@
/datum/antagonist/brother/greet()
var/brother_text = get_brother_names()
- to_chat(owner.current, "You are the [owner.special_role] of [brother_text].")
+ to_chat(owner.current, "You are the Blood Brother of [brother_text].")
to_chat(owner.current, "The Syndicate only accepts those that have proven themselves. Prove yourself and prove your [team.member_name]s by completing your objectives together! You and your team are outfitted with communication implants allowing for direct, encrypted communication.")
owner.announce_objectives()
give_meeting_area()
diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm
index 957db20573c..53c3a42b637 100644
--- a/code/modules/antagonists/changeling/changeling.dm
+++ b/code/modules/antagonists/changeling/changeling.dm
@@ -6,7 +6,8 @@
name = "Changeling"
roundend_category = "changelings"
antagpanel_category = "Changeling"
- job_rank = ROLE_CHANGELING
+ banning_key = ROLE_CHANGELING
+ required_living_playtime = 4
antag_moodlet = /datum/mood_event/focused
hijack_speed = 0.5
var/you_are_greet = TRUE
diff --git a/code/modules/antagonists/changeling/powers/teratoma.dm b/code/modules/antagonists/changeling/powers/teratoma.dm
index 482ac09834b..f0a89f41d6f 100644
--- a/code/modules/antagonists/changeling/powers/teratoma.dm
+++ b/code/modules/antagonists/changeling/powers/teratoma.dm
@@ -23,7 +23,7 @@
var/datum/antagonist/changeling/c = user.mind.has_antag_datum(/datum/antagonist/changeling)
c.chem_charges -= chemical_cost //I'm taking your chemicals hostage!
var/turf/A = get_turf(user)
- var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you want to play as a living teratoma?", ROLE_TERATOMA, null, ROLE_TERATOMA, 5 SECONDS) //players must answer rapidly
+ var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you want to play as a living teratoma?", ROLE_TERATOMA, null, 7.5 SECONDS) //players must answer rapidly
if(!LAZYLEN(candidates)) //if we got at least one candidate, they're teratoma now
to_chat(usr, "You fail at creating a tumor. Perhaps you should try again later?")
c.chem_charges += chemical_cost //If it fails we want to refund the chemicals
diff --git a/code/modules/antagonists/changeling/teratoma.dm b/code/modules/antagonists/changeling/teratoma.dm
index e304ae4383c..3e5a4c51aaf 100644
--- a/code/modules/antagonists/changeling/teratoma.dm
+++ b/code/modules/antagonists/changeling/teratoma.dm
@@ -2,7 +2,7 @@
name = "Teratoma"
roundend_category = "other"
antagpanel_category = "Changeling"
- job_rank = ROLE_TERATOMA
+ banning_key = ROLE_TERATOMA
/datum/antagonist/teratoma/on_gain()
owner.special_role = "Teratoma"
@@ -45,7 +45,6 @@
name = "Maintenance Teratoma"
roundend_category = "other"
antagpanel_category = "Changeling"
- job_rank = ROLE_TERATOMA
/datum/antagonist/teratoma/hugbox/greet()
..()
diff --git a/code/modules/antagonists/clock_cult/mobs/cogscarab.dm b/code/modules/antagonists/clock_cult/mobs/cogscarab.dm
index 8d233a2d20d..d1be9760a77 100644
--- a/code/modules/antagonists/clock_cult/mobs/cogscarab.dm
+++ b/code/modules/antagonists/clock_cult/mobs/cogscarab.dm
@@ -65,11 +65,6 @@ GLOBAL_LIST_INIT(cogscarabs, list())
/obj/effect/mob_spawn/drone/cogscarab/attack_ghost(mob/user)
if(is_banned_from(user.ckey, ROLE_SERVANT_OF_RATVAR) || QDELETED(src) || QDELETED(user))
return
- if(CONFIG_GET(flag/use_age_restriction_for_jobs))
- if(!isnum(user.client.player_age)) //apparently what happens when there's no DB connected. just don't let anybody be a drone without admin intervention
- if(user.client.player_age < 14)
- to_chat(user, "You're too new to play as a drone! Please try again in [14 - user.client.player_age] days.")
- return
if(!SSticker.mode)
to_chat(user, "Can't become a cogscarab before the game has started.")
return
diff --git a/code/modules/antagonists/clock_cult/scriptures/sigil_of_vitality.dm b/code/modules/antagonists/clock_cult/scriptures/sigil_of_vitality.dm
index e4ce19d5f04..0d80bd2aa47 100644
--- a/code/modules/antagonists/clock_cult/scriptures/sigil_of_vitality.dm
+++ b/code/modules/antagonists/clock_cult/scriptures/sigil_of_vitality.dm
@@ -53,7 +53,7 @@
if(M.mind)
M.mind.grab_ghost(TRUE)
else
- var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [M.name], an inactive clock cultist?", ROLE_SERVANT_OF_RATVAR, null, ROLE_SERVANT_OF_RATVAR, 50, M)
+ var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [M.name], an inactive clock cultist?", ROLE_SERVANT_OF_RATVAR, /datum/role_preference/antagonist/clock_cultist, 7.5 SECONDS, M)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(M)]) to replace an AFK player.")
diff --git a/code/modules/antagonists/clock_cult/scriptures/summon_marauder.dm b/code/modules/antagonists/clock_cult/scriptures/summon_marauder.dm
index ef41ed2bb61..d665cbeaee7 100644
--- a/code/modules/antagonists/clock_cult/scriptures/summon_marauder.dm
+++ b/code/modules/antagonists/clock_cult/scriptures/summon_marauder.dm
@@ -17,7 +17,7 @@
var/mob/dead/observer/selected
/datum/clockcult/scripture/marauder/invoke()
- candidates = pollGhostCandidates("Would you like to play as a clockwork marauder?", ROLE_SERVANT_OF_RATVAR, null, null, 100, POLL_IGNORE_CLOCKWORK)
+ candidates = pollGhostCandidates("Would you like to play as a clockwork marauder?", ROLE_SERVANT_OF_RATVAR, /datum/role_preference/antagonist/clock_cultist, 10 SECONDS, POLL_IGNORE_CLOCKWORK_HELPER)
if(LAZYLEN(candidates))
selected = pick(candidates)
if(!selected)
diff --git a/code/modules/antagonists/clock_cult/servant_of_ratvar.dm b/code/modules/antagonists/clock_cult/servant_of_ratvar.dm
index 470215b2696..d904a53fe91 100644
--- a/code/modules/antagonists/clock_cult/servant_of_ratvar.dm
+++ b/code/modules/antagonists/clock_cult/servant_of_ratvar.dm
@@ -7,7 +7,8 @@
roundend_category = "clock cultists"
antagpanel_category = "Clockcult"
antag_moodlet = /datum/mood_event/cult
- job_rank = ROLE_SERVANT_OF_RATVAR
+ banning_key = ROLE_SERVANT_OF_RATVAR
+ required_living_playtime = 4
//The class of the servant
var/datum/action/innate/clockcult/transmit/transmit_spell
diff --git a/code/modules/antagonists/clock_cult/structure/eminence_beacon.dm b/code/modules/antagonists/clock_cult/structure/eminence_beacon.dm
index 666acf43f25..0a04a5f1316 100644
--- a/code/modules/antagonists/clock_cult/structure/eminence_beacon.dm
+++ b/code/modules/antagonists/clock_cult/structure/eminence_beacon.dm
@@ -35,7 +35,7 @@
vote_active = FALSE
used = TRUE
if(!eminence)
- var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you want to play as the eminence?", ROLE_SERVANT_OF_RATVAR, null, null, 100, POLL_IGNORE_PYROSLIME)
+ var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you want to play as the eminence?", ROLE_SERVANT_OF_RATVAR, /datum/role_preference/antagonist/clock_cultist, 10 SECONDS)
if(LAZYLEN(candidates))
eminence = pick(candidates)
else
diff --git a/code/modules/antagonists/creep/creep.dm b/code/modules/antagonists/creep/creep.dm
index 6537250de14..63b43371dad 100644
--- a/code/modules/antagonists/creep/creep.dm
+++ b/code/modules/antagonists/creep/creep.dm
@@ -2,7 +2,7 @@
name = "Obsessed"
show_in_antagpanel = TRUE
antagpanel_category = "Other"
- job_rank = ROLE_OBSESSED
+ banning_key = ROLE_OBSESSED
show_name_in_check_antagonists = TRUE
roundend_category = "obsessed"
count_against_dynamic_roll_chance = FALSE
diff --git a/code/modules/antagonists/cult/cult.dm b/code/modules/antagonists/cult/cult.dm
index 75ff9fe6815..0f8cf5cefed 100644
--- a/code/modules/antagonists/cult/cult.dm
+++ b/code/modules/antagonists/cult/cult.dm
@@ -8,7 +8,8 @@
var/datum/action/innate/cult/comm/communion = new
var/datum/action/innate/cult/mastervote/vote = new
var/datum/action/innate/cult/blood_magic/magic = new
- job_rank = ROLE_CULTIST
+ banning_key = ROLE_CULTIST
+ required_living_playtime = 4
var/ignore_implant = FALSE
var/give_equipment = FALSE
var/datum/team/cult/cult_team
diff --git a/code/modules/antagonists/cult/cult_comms.dm b/code/modules/antagonists/cult/cult_comms.dm
index adb892f2e73..e28c1220f3a 100644
--- a/code/modules/antagonists/cult/cult_comms.dm
+++ b/code/modules/antagonists/cult/cult_comms.dm
@@ -108,7 +108,7 @@
if(B.current && B.current != Nominee && !B.current.incapacitated())
SEND_SOUND(B.current, 'sound/magic/exit_blood.ogg')
asked_cultists += B.current
- var/list/yes_voters = pollCandidates("[Nominee] seeks to lead your cult, do you support [Nominee.p_them()]?", poll_time = 300, group = asked_cultists)
+ var/list/yes_voters = pollCandidates("[Nominee] seeks to lead your cult, do you support [Nominee.p_them()]?", poll_time = 30 SECONDS, group = asked_cultists)
if(QDELETED(Nominee) || Nominee.incapacitated())
team.cult_vote_called = FALSE
for(var/datum/mind/B in team.members)
diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm
index fef483b3a3e..4f5d58cf7c7 100644
--- a/code/modules/antagonists/cult/runes.dm
+++ b/code/modules/antagonists/cult/runes.dm
@@ -603,7 +603,7 @@ structure_check() searches for nearby cultist structures required for the invoca
mob_to_revive.grab_ghost()
if(!mob_to_revive.client || mob_to_revive.client.is_afk())
set waitfor = FALSE
- var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [mob_to_revive.name], an inactive blood cultist?", ROLE_CULTIST, null, ROLE_CULTIST, 50, mob_to_revive)
+ var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [mob_to_revive.name], an inactive blood cultist?", ROLE_CULTIST, /datum/role_preference/antagonist/blood_cultist, 7.5 SECONDS, mob_to_revive)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
to_chat(mob_to_revive.mind, "Your physical form has been taken over by another soul due to your inactivity! Ahelp if you wish to regain your form.")
diff --git a/code/modules/antagonists/devil/devil.dm b/code/modules/antagonists/devil/devil.dm
index 15bc64418e0..8b548791769 100644
--- a/code/modules/antagonists/devil/devil.dm
+++ b/code/modules/antagonists/devil/devil.dm
@@ -88,7 +88,7 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
name = "Devil"
roundend_category = "devils"
antagpanel_category = "Devil"
- job_rank = ROLE_DEVIL
+ banning_key = ROLE_DEVIL
//Don't delete upon mind destruction, otherwise soul re-selling will break.
delete_on_mind_deletion = FALSE
show_to_ghosts = TRUE
diff --git a/code/modules/antagonists/devil/imp/imp.dm b/code/modules/antagonists/devil/imp/imp.dm
index bbe9b3978c7..0b8f25b0a25 100644
--- a/code/modules/antagonists/devil/imp/imp.dm
+++ b/code/modules/antagonists/devil/imp/imp.dm
@@ -64,6 +64,7 @@
name = "Imp"
antagpanel_category = "Devil"
show_in_roundend = FALSE
+ banning_key = ROLE_DEVIL
/datum/antagonist/imp/on_gain()
. = ..()
diff --git a/code/modules/antagonists/devil/sintouched/sintouched.dm b/code/modules/antagonists/devil/sintouched/sintouched.dm
index 29c3c77fd6d..014fdfcba30 100644
--- a/code/modules/antagonists/devil/sintouched/sintouched.dm
+++ b/code/modules/antagonists/devil/sintouched/sintouched.dm
@@ -10,6 +10,7 @@
name = "sintouched"
roundend_category = "sintouched"
antagpanel_category = "Devil"
+ banning_key = UNBANNABLE_ANTAGONIST
var/sin
var/static/list/sins = list(SIN_ACEDIA,SIN_GLUTTONY,SIN_GREED,SIN_SLOTH,SIN_WRATH,SIN_ENVY,SIN_PRIDE)
diff --git a/code/modules/antagonists/eldritch_cult/eldritch_antag.dm b/code/modules/antagonists/eldritch_cult/eldritch_antag.dm
index bd98f6e4d07..b752da58ec1 100644
--- a/code/modules/antagonists/eldritch_cult/eldritch_antag.dm
+++ b/code/modules/antagonists/eldritch_cult/eldritch_antag.dm
@@ -3,7 +3,8 @@
roundend_category = "Heretics"
antagpanel_category = "Heretic"
antag_moodlet = /datum/mood_event/heretics
- job_rank = ROLE_HERETIC
+ banning_key = ROLE_HERETIC
+ required_living_playtime = 4
var/antag_hud_type = ANTAG_HUD_HERETIC // someone make all the other antags conform to this too lol
var/antag_hud_name = "heretic"
hijack_speed = 0.5
diff --git a/code/modules/antagonists/eldritch_cult/eldritch_monster_antag.dm b/code/modules/antagonists/eldritch_cult/eldritch_monster_antag.dm
index 7ecba7e1df1..4a48677f763 100644
--- a/code/modules/antagonists/eldritch_cult/eldritch_monster_antag.dm
+++ b/code/modules/antagonists/eldritch_cult/eldritch_monster_antag.dm
@@ -4,7 +4,7 @@
roundend_category = "Heretics"
antagpanel_category = "Heretic Beast"
antag_moodlet = /datum/mood_event/heretics
- job_rank = ROLE_HERETIC
+ banning_key = ROLE_HERETIC
var/antag_hud_type = ANTAG_HUD_HERETIC
var/antag_hud_name = "heretic_beast"
var/datum/antagonist/heretic/master
diff --git a/code/modules/antagonists/ert/ert.dm b/code/modules/antagonists/ert/ert.dm
index 458280d6e0e..65f0e45db0d 100644
--- a/code/modules/antagonists/ert/ert.dm
+++ b/code/modules/antagonists/ert/ert.dm
@@ -22,6 +22,7 @@
show_to_ghosts = TRUE
antag_moodlet = /datum/mood_event/focused
count_against_dynamic_roll_chance = FALSE
+ banning_key = ROLE_ERT
/datum/antagonist/ert/on_gain()
if(random_names)
diff --git a/code/modules/antagonists/gang/gang.dm b/code/modules/antagonists/gang/gang.dm
index 37377021b71..479ffb27b90 100644
--- a/code/modules/antagonists/gang/gang.dm
+++ b/code/modules/antagonists/gang/gang.dm
@@ -2,7 +2,7 @@
name = "Gangster"
roundend_category = "gangsters"
can_coexist_with_others = FALSE
- job_rank = ROLE_GANG
+ banning_key = ROLE_GANG
antagpanel_category = "Gang"
var/hud_type = "gangster"
var/message_name = "Gangster"
diff --git a/code/modules/antagonists/greentext/greentext.dm b/code/modules/antagonists/greentext/greentext.dm
index a40ab260538..3409e710410 100644
--- a/code/modules/antagonists/greentext/greentext.dm
+++ b/code/modules/antagonists/greentext/greentext.dm
@@ -3,6 +3,7 @@
show_in_antagpanel = FALSE
show_name_in_check_antagonists = TRUE //Not that it will be there for long
count_against_dynamic_roll_chance = FALSE
+ banning_key = UNBANNABLE_ANTAGONIST
/datum/antagonist/greentext/proc/forge_objectives()
var/datum/objective/O = new /datum/objective("Succeed")
diff --git a/code/modules/antagonists/guardian/guardian.dm b/code/modules/antagonists/guardian/guardian.dm
index 192f8675362..3d46c14c325 100644
--- a/code/modules/antagonists/guardian/guardian.dm
+++ b/code/modules/antagonists/guardian/guardian.dm
@@ -5,6 +5,7 @@
show_in_antagpanel = FALSE
var/datum/guardian_stats/stats
var/datum/mind/summoner
+ banning_key = ROLE_HOLOPARASITE
/datum/antagonist/guardian/roundend_report()
var/list/parts = list()
diff --git a/code/modules/antagonists/highlander/highlander.dm b/code/modules/antagonists/highlander/highlander.dm
index c79a4845af6..5892dec8abf 100644
--- a/code/modules/antagonists/highlander/highlander.dm
+++ b/code/modules/antagonists/highlander/highlander.dm
@@ -5,6 +5,7 @@
show_name_in_check_antagonists = TRUE
can_elimination_hijack = ELIMINATION_ENABLED
count_against_dynamic_roll_chance = FALSE
+ banning_key = BAN_ROLE_ALL_ANTAGONISTS
/datum/antagonist/highlander/apply_innate_effects(mob/living/mob_override)
var/mob/living/L = owner.current || mob_override
diff --git a/code/modules/antagonists/hivemind/hivemind.dm b/code/modules/antagonists/hivemind/hivemind.dm
index 0fceed869ef..fa4d0033ee2 100644
--- a/code/modules/antagonists/hivemind/hivemind.dm
+++ b/code/modules/antagonists/hivemind/hivemind.dm
@@ -2,7 +2,8 @@
name = "Hivemind Host"
roundend_category = "hiveminds"
antagpanel_category = "Hivemind Host"
- job_rank = ROLE_HIVE
+ banning_key = ROLE_HIVE
+ required_living_playtime = 4
antag_moodlet = /datum/mood_event/hivehost
var/special_role = ROLE_HIVE
var/list/hivemembers = list()
@@ -156,7 +157,7 @@
/datum/antagonist/hivemind/on_gain()
- owner.special_role = special_role
+ owner.special_role = ROLE_HIVE
GLOB.hivehosts += src
generate_flavour()
create_actions()
diff --git a/code/modules/antagonists/hivemind/vessel.dm b/code/modules/antagonists/hivemind/vessel.dm
index 2fad52867b8..393417f79d7 100644
--- a/code/modules/antagonists/hivemind/vessel.dm
+++ b/code/modules/antagonists/hivemind/vessel.dm
@@ -2,7 +2,7 @@
/datum/antagonist/hivevessel
name = "Awoken Vessel"
- job_rank = ROLE_BRAINWASHED
+ banning_key = ROLE_HIVE_VESSEL
roundend_category = "awoken vessels"
antagpanel_category = "Other"
show_name_in_check_antagonists = TRUE
@@ -36,7 +36,7 @@
mind.remove_antag_datum(/datum/antagonist/brainwashed)
/datum/antagonist/hivevessel/on_gain()
- owner.special_role = special_role
+ owner.special_role = ROLE_HIVE_VESSEL
owner.AddSpell(fist)
..()
diff --git a/code/modules/antagonists/incursion/incursion.dm b/code/modules/antagonists/incursion/incursion.dm
index d9ccbb95d0e..5358e20ac0e 100644
--- a/code/modules/antagonists/incursion/incursion.dm
+++ b/code/modules/antagonists/incursion/incursion.dm
@@ -1,8 +1,8 @@
/datum/antagonist/incursion
name = "Syndicate Incursion Member"
antagpanel_category = "Incursion"
- job_rank = ROLE_INCURSION
- var/special_role = ROLE_INCURSION
+ banning_key = ROLE_INCURSION
+ required_living_playtime = 4
var/datum/team/incursion/team
antag_moodlet = /datum/mood_event/focused
hijack_speed = 0.5
@@ -22,7 +22,7 @@
for(var/datum/objective/O in team.objectives)
objectives += O
log_objective(owner, O.explanation_text)
- owner.special_role = special_role
+ owner.special_role = ROLE_INCURSION
finalize_incursion()
return ..()
@@ -198,15 +198,15 @@
/datum/team/incursion/proc/generate_traitor_kill_objective(list/restricted_jobs)
//Spawn someone as a traitor
- var/list/datum/mind/people = SSticker.mode.get_alive_non_antagonsist_players_for_role(ROLE_EXCOMM, restricted_jobs)
+ var/list/datum/mind/people = SSticker.mode.get_alive_non_antagonsist_players_for_role(/datum/antagonist/traitor, /datum/role_preference/antagonist/excommunicate, restricted_jobs)
if(!LAZYLEN(people))
log_game("Not enough players for incursion role. [LAZYLEN(people)]")
return
- var/datum/mind/target = SSticker.mode.antag_pick(people, ROLE_EXCOMM)
+ var/datum/mind/target = SSticker.mode.antag_pick(people, /datum/role_preference/antagonist/excommunicate)
if(!target)
log_game("No mind selected.")
return
- target.make_Traitor()
+ target.add_antag_datum(/datum/antagonist/traitor/excommunicate)
to_chat(target, "You have been declared an ex-communicate of the syndicate and are being hunted down.")
to_chat(target, "You have stolen syndicate objective documents, complete the objectives to throw off the syndicate and sabotage their efforts.")
target.store_memory("You have been declared an ex-communicate of the syndicate and are being hunted down by a group of traitors. Be careful!")
diff --git a/code/modules/antagonists/magic_servant/servant.dm b/code/modules/antagonists/magic_servant/servant.dm
index 3277991446c..9717e869475 100644
--- a/code/modules/antagonists/magic_servant/servant.dm
+++ b/code/modules/antagonists/magic_servant/servant.dm
@@ -3,6 +3,7 @@
show_in_roundend = FALSE
show_in_antagpanel = FALSE
show_name_in_check_antagonists = TRUE
+ banning_key = ROLE_WIZARD
/datum/antagonist/magic_servant/proc/setup_master(mob/M)
var/datum/objective/O = new("Serve [M.real_name].")
diff --git a/code/modules/antagonists/morph/morph.dm b/code/modules/antagonists/morph/morph.dm
index 7aa8db699f0..e88a891f1b1 100644
--- a/code/modules/antagonists/morph/morph.dm
+++ b/code/modules/antagonists/morph/morph.dm
@@ -276,7 +276,7 @@
role_name = "morphling"
/datum/round_event/ghost_role/morph/spawn_role()
- var/list/candidates = get_candidates(ROLE_ALIEN, null, ROLE_ALIEN)
+ var/list/candidates = get_candidates(ROLE_MORPH, /datum/role_preference/midround_ghost/morph)
if(!candidates.len)
return NOT_ENOUGH_PLAYERS
diff --git a/code/modules/antagonists/morph/morph_antag.dm b/code/modules/antagonists/morph/morph_antag.dm
index 7b0491e5de5..c648a24fdea 100644
--- a/code/modules/antagonists/morph/morph_antag.dm
+++ b/code/modules/antagonists/morph/morph_antag.dm
@@ -2,5 +2,6 @@
name = "Morph"
show_name_in_check_antagonists = TRUE
show_in_antagpanel = FALSE
+ banning_key = ROLE_MORPH
//It does nothing! (Besides tracking)
diff --git a/code/modules/antagonists/ninja/ninja.dm b/code/modules/antagonists/ninja/ninja.dm
index 03b0f9042c8..b697e6684bd 100644
--- a/code/modules/antagonists/ninja/ninja.dm
+++ b/code/modules/antagonists/ninja/ninja.dm
@@ -1,7 +1,7 @@
/datum/antagonist/ninja
name = "Ninja"
antagpanel_category = "Ninja"
- job_rank = ROLE_NINJA
+ banning_key = ROLE_NINJA
show_name_in_check_antagonists = TRUE
show_to_ghosts = TRUE
antag_moodlet = /datum/mood_event/focused
diff --git a/code/modules/antagonists/nukeop/nukeop.dm b/code/modules/antagonists/nukeop/nukeop.dm
index 52accf3923d..8126e12ff1c 100644
--- a/code/modules/antagonists/nukeop/nukeop.dm
+++ b/code/modules/antagonists/nukeop/nukeop.dm
@@ -2,7 +2,8 @@
name = "Nuclear Operative"
roundend_category = "syndicate operatives" //just in case
antagpanel_category = "NukeOp"
- job_rank = ROLE_OPERATIVE
+ banning_key = ROLE_OPERATIVE
+ required_living_playtime = 8
antag_moodlet = /datum/mood_event/focused
show_to_ghosts = TRUE
hijack_speed = 2 //If you can't take out the station, take the shuttle instead.
@@ -144,7 +145,7 @@
nuke_team = new_team
/datum/antagonist/nukeop/admin_add(datum/mind/new_owner,mob/admin)
- new_owner.assigned_role = ROLE_SYNDICATE
+ new_owner.assigned_role = ROLE_OPERATIVE
new_owner.add_antag_datum(src)
message_admins("[key_name_admin(admin)] has nuke op'ed [key_name_admin(new_owner)].")
log_admin("[key_name(admin)] has nuke op'ed [key_name(new_owner)].")
diff --git a/code/modules/antagonists/official/official.dm b/code/modules/antagonists/official/official.dm
index a35ef429734..d1d73bc79b7 100644
--- a/code/modules/antagonists/official/official.dm
+++ b/code/modules/antagonists/official/official.dm
@@ -6,6 +6,7 @@
var/datum/objective/mission
var/datum/team/ert/ert_team
show_to_ghosts = TRUE
+ banning_key = ROLE_ERT
/datum/antagonist/official/greet()
to_chat(owner, "You are a CentCom Official.")
diff --git a/code/modules/antagonists/overthrow/overthrow.dm b/code/modules/antagonists/overthrow/overthrow.dm
index eeb25929891..da118ce87b4 100644
--- a/code/modules/antagonists/overthrow/overthrow.dm
+++ b/code/modules/antagonists/overthrow/overthrow.dm
@@ -9,7 +9,7 @@
name = "Syndicate mutineer"
roundend_category = "syndicate mutineers"
antagpanel_category = "Syndicate Mutineers"
- job_rank = ROLE_TRAITOR // simply use the traitor preference & jobban settings
+ banning_key = ROLE_OVERTHROW
var/datum/team/overthrow/team
var/static/list/possible_useful_items
diff --git a/code/modules/antagonists/pirate/pirate.dm b/code/modules/antagonists/pirate/pirate.dm
index b8fbd18c70e..5804e64f448 100644
--- a/code/modules/antagonists/pirate/pirate.dm
+++ b/code/modules/antagonists/pirate/pirate.dm
@@ -1,6 +1,6 @@
/datum/antagonist/pirate
name = "Space Pirate"
- job_rank = ROLE_TRAITOR
+ banning_key = ROLE_SPACE_PIRATE
roundend_category = "space pirates"
antagpanel_category = "Pirate"
show_to_ghosts = TRUE
diff --git a/code/modules/antagonists/revenant/revenant.dm b/code/modules/antagonists/revenant/revenant.dm
index 803d8fd916c..02370743481 100644
--- a/code/modules/antagonists/revenant/revenant.dm
+++ b/code/modules/antagonists/revenant/revenant.dm
@@ -438,7 +438,7 @@
break
if(!key_of_revenant)
message_admins("The new revenant's old client either could not be found or is in a new, living mob - grabbing a random candidate instead...")
- var/list/candidates = pollCandidatesForMob("Do you want to be [revenant.name] (reforming)?", ROLE_REVENANT, null, ROLE_REVENANT, 50, revenant)
+ var/list/candidates = pollCandidatesForMob("Do you want to be [revenant.name] (reforming)?", ROLE_REVENANT, /datum/role_preference/midround_ghost/revenant, 7.5 SECONDS, revenant)
if(!LAZYLEN(candidates))
qdel(revenant)
message_admins("No candidates were found for the new revenant. Oh well!")
diff --git a/code/modules/antagonists/revenant/revenant_antag.dm b/code/modules/antagonists/revenant/revenant_antag.dm
index 169d23d25c0..2c9aa4d8a87 100644
--- a/code/modules/antagonists/revenant/revenant_antag.dm
+++ b/code/modules/antagonists/revenant/revenant_antag.dm
@@ -3,6 +3,7 @@
show_in_antagpanel = FALSE
show_name_in_check_antagonists = TRUE
show_to_ghosts = TRUE
+ banning_key = ROLE_REVENANT
/datum/antagonist/revenant/greet()
owner.announce_objectives()
diff --git a/code/modules/antagonists/revenant/revenant_spawn_event.dm b/code/modules/antagonists/revenant/revenant_spawn_event.dm
index 10ee621a9b8..54368fd8721 100644
--- a/code/modules/antagonists/revenant/revenant_spawn_event.dm
+++ b/code/modules/antagonists/revenant/revenant_spawn_event.dm
@@ -26,7 +26,7 @@
message_admins("Event attempted to spawn a revenant, but there were only [deadMobs]/[REVENANT_SPAWN_THRESHOLD] dead mobs.")
return WAITING_FOR_SOMETHING
- var/list/candidates = get_candidates(ROLE_REVENANT, null, ROLE_REVENANT)
+ var/list/candidates = get_candidates(ROLE_REVENANT, /datum/role_preference/midround_ghost/revenant)
if(!candidates.len)
return NOT_ENOUGH_PLAYERS
diff --git a/code/modules/antagonists/revolution/revolution.dm b/code/modules/antagonists/revolution/revolution.dm
index d5dce9e21ef..17591952189 100644
--- a/code/modules/antagonists/revolution/revolution.dm
+++ b/code/modules/antagonists/revolution/revolution.dm
@@ -7,7 +7,7 @@
name = "Revolutionary"
roundend_category = "revolutionaries" // if by some miracle revolutionaries without revolution happen
antagpanel_category = "Revolution"
- job_rank = ROLE_REV
+ banning_key = ROLE_REV
antag_moodlet = /datum/mood_event/revolution
var/hud_type = "rev"
var/datum/team/revolution/rev_team
@@ -159,6 +159,8 @@
/datum/antagonist/rev/head
name = "Head Revolutionary"
hud_type = "rev_head"
+ banning_key = ROLE_REV_HEAD
+ required_living_playtime = 4
var/remove_clumsy = FALSE
var/give_flash = FALSE
var/give_hud = TRUE
@@ -289,6 +291,7 @@
/datum/antagonist/revolution_enemy
name = "Enemy of the Revolution"
show_in_antagpanel = FALSE
+ banning_key = UNBANNABLE_ANTAGONIST
/datum/antagonist/revolution_enemy/on_gain()
owner.special_role = "revolution enemy"
@@ -342,7 +345,7 @@
var/list/datum/mind/nonhuman_promotable = list()
for(var/datum/mind/khrushchev in non_heads)
if(khrushchev.current && !khrushchev.current.incapacitated() && !khrushchev.current.restrained() && khrushchev.current.client && khrushchev.current.stat != DEAD)
- if(ROLE_REV in khrushchev.current.client.prefs.be_special)
+ if(khrushchev.current.client.should_include_for_role(ROLE_REV_HEAD, /datum/role_preference/antagonist/revolutionary))
if(ishuman(khrushchev.current))
promotable += khrushchev
else
diff --git a/code/modules/antagonists/role_preference/_role_preference.dm b/code/modules/antagonists/role_preference/_role_preference.dm
new file mode 100644
index 00000000000..710ce5d2430
--- /dev/null
+++ b/code/modules/antagonists/role_preference/_role_preference.dm
@@ -0,0 +1,27 @@
+/datum/role_preference
+ var/name
+ /// What heading to display this entry under in the preferences menu. Use ROLE_PREFERENCE_CATEGORY defines.
+ var/category
+ /// The Antagonist datum typepath for this entry, if there is one. Used to get data about the role for display (bans etc)
+ var/datum/antagonist/antag_datum
+ /// The base abstract path for this subtype.
+ var/abstract_type = /datum/role_preference
+ /// If this preference can vary between characters.
+ var/per_character = FALSE
+
+/// Includes latejoin and roundstart antagonists
+/datum/role_preference/antagonist
+ category = ROLE_PREFERENCE_CATEGORY_ANAGONIST
+ abstract_type = /datum/role_preference/antagonist
+ per_character = TRUE
+
+/// Includes autotraitor and gamemode midround assignments - being forced into an antagonist during a round (does not apply to conversion antags).
+/datum/role_preference/midround_living
+ category = ROLE_PREFERENCE_CATEGORY_MIDROUND_LIVING
+ abstract_type = /datum/role_preference/midround_living
+ per_character = TRUE
+
+/// Includes anything polled from ghosts that does antagonist stuff
+/datum/role_preference/midround_ghost
+ category = ROLE_PREFERENCE_CATEGORY_MIDROUND_GHOST
+ abstract_type = /datum/role_preference/midround_ghost
diff --git a/code/modules/antagonists/role_preference/role_antagonists.dm b/code/modules/antagonists/role_preference/role_antagonists.dm
new file mode 100644
index 00000000000..b952e5ad233
--- /dev/null
+++ b/code/modules/antagonists/role_preference/role_antagonists.dm
@@ -0,0 +1,43 @@
+/datum/role_preference/antagonist/blood_brother
+ name = "Blood Brother"
+ antag_datum = /datum/antagonist/brother
+
+/datum/role_preference/antagonist/blood_cultist
+ name = "Blood Cultist"
+ antag_datum = /datum/antagonist/cult
+
+/datum/role_preference/antagonist/clock_cultist
+ name = "Clock Cultist"
+ antag_datum = /datum/antagonist/servant_of_ratvar
+
+/datum/role_preference/antagonist/devil
+ name = "Devil"
+ antag_datum = /datum/antagonist/devil
+
+/datum/role_preference/antagonist/revolutionary
+ name = "Head Revolutionary"
+ antag_datum = /datum/antagonist/rev/head
+
+/datum/role_preference/antagonist/heretic
+ name = "Heretic"
+ antag_datum = /datum/antagonist/heretic
+
+/datum/role_preference/antagonist/hivemind_host
+ name = "Hivemind Host"
+ antag_datum = /datum/antagonist/hivemind
+
+/datum/role_preference/antagonist/incursionist
+ name = "Incursionist"
+ antag_datum = /datum/antagonist/incursion
+
+/datum/role_preference/antagonist/excommunicate
+ name = "Excommunicated Syndicate Agent"
+ antag_datum = /datum/antagonist/traitor/excommunicate
+
+/datum/role_preference/antagonist/gangster
+ name = "Gangster"
+ antag_datum = /datum/antagonist/gang
+
+/datum/role_preference/antagonist/internal_affairs
+ name = "Internal Affairs Agent"
+ antag_datum = /datum/antagonist/traitor/internal_affairs
diff --git a/code/modules/antagonists/role_preference/role_changeling.dm b/code/modules/antagonists/role_preference/role_changeling.dm
new file mode 100644
index 00000000000..cf0399b0bcf
--- /dev/null
+++ b/code/modules/antagonists/role_preference/role_changeling.dm
@@ -0,0 +1,3 @@
+/datum/role_preference/antagonist/changeling
+ name = "Changeling"
+ antag_datum = /datum/antagonist/changeling
diff --git a/code/modules/antagonists/role_preference/role_midrounds.dm b/code/modules/antagonists/role_preference/role_midrounds.dm
new file mode 100644
index 00000000000..77a4c08d798
--- /dev/null
+++ b/code/modules/antagonists/role_preference/role_midrounds.dm
@@ -0,0 +1,69 @@
+/datum/role_preference/midround_ghost/blob
+ name = "Blob"
+ antag_datum = /datum/antagonist/blob
+
+/datum/role_preference/midround_ghost/xenomorph
+ name = "Xenomorph"
+ antag_datum = /datum/antagonist/xeno
+
+/datum/role_preference/midround_ghost/nightmare
+ name = "Nightmare"
+ antag_datum = /datum/antagonist/nightmare
+
+/datum/role_preference/midround_ghost/space_dragon
+ name = "Space Dragon"
+ antag_datum = /datum/antagonist/space_dragon
+
+/datum/role_preference/midround_ghost/abductor
+ name = "Abductor"
+ antag_datum = /datum/antagonist/abductor
+
+/datum/role_preference/midround_ghost/space_pirate
+ name = "Space Pirate"
+ antag_datum = /datum/antagonist/pirate
+
+/datum/role_preference/midround_ghost/revenant
+ name = "Revenant"
+ antag_datum = /datum/antagonist/revenant
+
+/* NSV13 - Disabled because we don't have this ported yet.
+/datum/role_preference/midround_ghost/spider
+ name = "Spider"
+ antag_datum = /datum/antagonist/spider
+
+/datum/role_preference/midround_ghost/swarmer
+ name = "Swarmer"
+ antag_datum = /datum/antagonist/swarmer
+*/
+
+/datum/role_preference/midround_ghost/morph
+ name = "Morph"
+ antag_datum = /datum/antagonist/morph
+
+/datum/role_preference/midround_ghost/fugitive
+ name = "Fugitive"
+ antag_datum = /datum/antagonist/fugitive
+
+/datum/role_preference/midround_ghost/fugitive_hunter
+ name = "Fugitive Hunter"
+ antag_datum = /datum/antagonist/fugitive_hunter
+
+/datum/role_preference/midround_ghost/slaughter_demon
+ name = "Slaughter Demon"
+ antag_datum = /datum/antagonist/slaughter
+
+/datum/role_preference/midround_ghost/devil
+ name = "Devil (Midround)"
+ antag_datum = /datum/antagonist/devil
+
+/datum/role_preference/midround_ghost/ninja
+ name = "Ninja"
+ antag_datum = /datum/antagonist/ninja
+
+/datum/role_preference/midround_living/malfunctioning_ai
+ name = "Malfunctioning AI"
+ antag_datum = /datum/antagonist/traitor
+
+/datum/role_preference/midround_living/obsessed
+ name = "Obsessed"
+ antag_datum = /datum/antagonist/obsessed
diff --git a/code/modules/antagonists/role_preference/role_operative.dm b/code/modules/antagonists/role_preference/role_operative.dm
new file mode 100644
index 00000000000..6a4fe7a5b9e
--- /dev/null
+++ b/code/modules/antagonists/role_preference/role_operative.dm
@@ -0,0 +1,7 @@
+/datum/role_preference/antagonist/nuclear_operative
+ name = "Nuclear Operative"
+ antag_datum = /datum/antagonist/nukeop
+
+/datum/role_preference/midround_ghost/nuclear_operative
+ name = "Nuclear Operative (Midround)"
+ antag_datum = /datum/antagonist/nukeop
diff --git a/code/modules/antagonists/role_preference/role_traitor.dm b/code/modules/antagonists/role_preference/role_traitor.dm
new file mode 100644
index 00000000000..46d11945a14
--- /dev/null
+++ b/code/modules/antagonists/role_preference/role_traitor.dm
@@ -0,0 +1,7 @@
+/datum/role_preference/antagonist/traitor
+ name = "Traitor"
+ antag_datum = /datum/antagonist/traitor
+
+/datum/role_preference/midround_living/traitor
+ name = "Traitor (Sleeper Agent)"
+ antag_datum = /datum/antagonist/traitor
diff --git a/code/modules/antagonists/role_preference/role_wizard.dm b/code/modules/antagonists/role_preference/role_wizard.dm
new file mode 100644
index 00000000000..31681493a58
--- /dev/null
+++ b/code/modules/antagonists/role_preference/role_wizard.dm
@@ -0,0 +1,7 @@
+/datum/role_preference/antagonist/wizard
+ name = "Wizard"
+ antag_datum = /datum/antagonist/wizard
+
+/datum/role_preference/midround_ghost/wizard
+ name = "Wizard (Midround)"
+ antag_datum = /datum/antagonist/wizard
diff --git a/code/modules/antagonists/roundstart_special/special_antagonist.dm b/code/modules/antagonists/roundstart_special/special_antagonist.dm
index 7d39652e9bf..603623e4830 100644
--- a/code/modules/antagonists/roundstart_special/special_antagonist.dm
+++ b/code/modules/antagonists/roundstart_special/special_antagonist.dm
@@ -24,8 +24,10 @@
var/max_occurrences = 1
var/holidayID = ""
//Preferences
- var/preference_type = ROLE_TRAITOR
- var/special_role_flag = null //Will use antag rep if enabled
+ var/preference_type = null
+ /// If we should use antag rep. Do note that having a preference_type enables checking during gamemode execution.
+ var/use_antag_rep = TRUE
+ var/banning_key = ROLE_TRAITOR
/datum/special_role/proc/setup()
if(CONFIG_GET(flag/protect_roles_from_antagonist))
@@ -46,6 +48,7 @@
E.antagonist_datum = attached_antag_datum
E.antag_name = role_name
E.preference_type = preference_type
+ E.banning_key = banning_key
E.protected_jobs = restricted_jobs
E.typepath = /datum/round_event/create_special_antag
E.weight = weight
@@ -72,8 +75,8 @@
//The datum associated with the role
/datum/antagonist/special
- name = "Role that should not be accessable in game."
- job_rank = ROLE_SYNDICATE
+ name = "Role that should not be accessible in game."
+ banning_key = BAN_ROLE_ALL_ANTAGONISTS
show_in_antagpanel = FALSE
show_name_in_check_antagonists = FALSE
prevent_roundtype_conversion = FALSE
diff --git a/code/modules/antagonists/santa/santa.dm b/code/modules/antagonists/santa/santa.dm
index fb1d304f8bb..563e89059cb 100644
--- a/code/modules/antagonists/santa/santa.dm
+++ b/code/modules/antagonists/santa/santa.dm
@@ -3,6 +3,7 @@
show_in_antagpanel = FALSE
show_name_in_check_antagonists = TRUE
show_to_ghosts = TRUE
+ banning_key = UNBANNABLE_ANTAGONIST
/datum/antagonist/santa/on_gain()
. = ..()
diff --git a/code/modules/antagonists/separatist/separatist.dm b/code/modules/antagonists/separatist/separatist.dm
index 20a6d84bdec..cc9a84836e6 100644
--- a/code/modules/antagonists/separatist/separatist.dm
+++ b/code/modules/antagonists/separatist/separatist.dm
@@ -6,6 +6,7 @@
show_in_antagpanel = FALSE
show_name_in_check_antagonists = TRUE
var/datum/team/nation/nation
+ banning_key = BAN_ROLE_ALL_ANTAGONISTS
/datum/antagonist/separatist/create_team(datum/team/nation/new_team)
if(!new_team)
diff --git a/code/modules/antagonists/slaughter/slaughter_antag.dm b/code/modules/antagonists/slaughter/slaughter_antag.dm
index 9f80462f578..557b2ec5c49 100644
--- a/code/modules/antagonists/slaughter/slaughter_antag.dm
+++ b/code/modules/antagonists/slaughter/slaughter_antag.dm
@@ -3,7 +3,7 @@
show_name_in_check_antagonists = TRUE
var/objective_verb = "Kill"
var/datum/mind/summoner
- job_rank = ROLE_ALIEN
+ banning_key = ROLE_SLAUGHTER_DEMON
show_in_antagpanel = FALSE
show_to_ghosts = TRUE
diff --git a/code/modules/antagonists/slaughter/slaughterevent.dm b/code/modules/antagonists/slaughter/slaughterevent.dm
index 8ad463763ce..9c2fdaf3d13 100644
--- a/code/modules/antagonists/slaughter/slaughterevent.dm
+++ b/code/modules/antagonists/slaughter/slaughterevent.dm
@@ -14,7 +14,7 @@
role_name = "slaughter demon"
/datum/round_event/ghost_role/slaughter/spawn_role()
- var/list/candidates = get_candidates(ROLE_ALIEN, null, ROLE_ALIEN)
+ var/list/candidates = get_candidates(ROLE_SLAUGHTER_DEMON, null)
if(!candidates.len)
return NOT_ENOUGH_PLAYERS
diff --git a/code/modules/antagonists/survivalist/survivalist.dm b/code/modules/antagonists/survivalist/survivalist.dm
index 4c36b4e1354..819d8c07fd0 100644
--- a/code/modules/antagonists/survivalist/survivalist.dm
+++ b/code/modules/antagonists/survivalist/survivalist.dm
@@ -2,6 +2,7 @@
name = "Survivalist"
show_in_antagpanel = FALSE
show_name_in_check_antagonists = TRUE
+ banning_key = ROLE_SURVIVALIST
var/greet_message = ""
/datum/antagonist/survivalist/proc/forge_objectives()
diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm
index 506f2695465..02396b7388b 100644
--- a/code/modules/antagonists/traitor/datum_traitor.dm
+++ b/code/modules/antagonists/traitor/datum_traitor.dm
@@ -5,7 +5,8 @@
name = "Traitor"
roundend_category = "traitors"
antagpanel_category = "Traitor"
- job_rank = ROLE_TRAITOR
+ banning_key = ROLE_TRAITOR
+ required_living_playtime = 4
antag_moodlet = /datum/mood_event/focused
hijack_speed = 0.5 //10 seconds per hijack stage by default
var/special_role = ROLE_TRAITOR
@@ -435,3 +436,8 @@
/datum/antagonist/traitor/is_gamemode_hero()
return SSticker.mode.name == "traitor"
+
+/datum/antagonist/traitor/excommunicate
+ name = "Excommunicate Traitor"
+ banning_key = ROLE_EXCOMM
+ special_role = ROLE_EXCOMM
diff --git a/code/modules/antagonists/traitor/equipment/contractor.dm b/code/modules/antagonists/traitor/equipment/contractor.dm
index 7827bf9f394..b97d5ad70c9 100644
--- a/code/modules/antagonists/traitor/equipment/contractor.dm
+++ b/code/modules/antagonists/traitor/equipment/contractor.dm
@@ -165,7 +165,7 @@
if (.)
to_chat(user, "The uplink vibrates quietly, connecting to nearby agents...")
- var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you want to play as the Contractor Support Unit for [user.real_name]?", ROLE_PAI, null, FALSE, 100, POLL_IGNORE_CONTRACTOR_SUPPORT)
+ var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you want to play as the Contractor Support Unit for [user.real_name]?", ROLE_CONTRACTOR_SUPPORT_UNIT, null, 10 SECONDS)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
diff --git a/code/modules/antagonists/traitor/traitor_spawner.dm b/code/modules/antagonists/traitor/traitor_spawner.dm
index 7d42fa8fc4f..f3c31485d74 100644
--- a/code/modules/antagonists/traitor/traitor_spawner.dm
+++ b/code/modules/antagonists/traitor/traitor_spawner.dm
@@ -13,9 +13,9 @@
allowAntagTargets = TRUE
latejoin_allowed = TRUE
protected_jobs = list(JOB_NAME_SECURITYOFFICER, JOB_NAME_WARDEN, JOB_NAME_DETECTIVE, JOB_NAME_HEADOFSECURITY, JOB_NAME_CAPTAIN)
-
- special_role_flag = ROLE_TRAITOR
- role_name = ROLE_TRAITOR
+ role_name = "Traitor"
+ preference_type = /datum/role_preference/antagonist/traitor
+ use_antag_rep = TRUE
var/traitors_possible = 4 //hard limit on traitors if scaling is turned off
diff --git a/code/modules/antagonists/valentines/heartbreaker.dm b/code/modules/antagonists/valentines/heartbreaker.dm
index 39ffdfa1496..51e80761140 100644
--- a/code/modules/antagonists/valentines/heartbreaker.dm
+++ b/code/modules/antagonists/valentines/heartbreaker.dm
@@ -3,6 +3,7 @@
roundend_category = "valentines"
show_in_antagpanel = FALSE
show_name_in_check_antagonists = TRUE
+ banning_key = BAN_ROLE_ALL_ANTAGONISTS
/datum/antagonist/heartbreaker/proc/forge_objectives()
diff --git a/code/modules/antagonists/valentines/valentine.dm b/code/modules/antagonists/valentines/valentine.dm
index df695fadce5..cc1f81ed1bf 100644
--- a/code/modules/antagonists/valentines/valentine.dm
+++ b/code/modules/antagonists/valentines/valentine.dm
@@ -5,6 +5,7 @@
prevent_roundtype_conversion = FALSE
var/datum/mind/date
count_against_dynamic_roll_chance = FALSE
+ banning_key = UNBANNABLE_ANTAGONIST
/datum/antagonist/valentine/proc/forge_objectives()
var/datum/objective/protect/protect_objective = new /datum/objective/protect
diff --git a/code/modules/antagonists/wishgranter/wishgranter.dm b/code/modules/antagonists/wishgranter/wishgranter.dm
index 497bf49b00d..960d49bdc46 100644
--- a/code/modules/antagonists/wishgranter/wishgranter.dm
+++ b/code/modules/antagonists/wishgranter/wishgranter.dm
@@ -3,6 +3,7 @@
show_in_antagpanel = FALSE
show_name_in_check_antagonists = TRUE
can_elimination_hijack = ELIMINATION_ENABLED
+ banning_key = BAN_ROLE_ALL_ANTAGONISTS
/datum/antagonist/wishgranter/proc/forge_objectives()
var/datum/objective/elimination/highlander/elimination_objective = new
diff --git a/code/modules/antagonists/wizard/equipment/soulstone.dm b/code/modules/antagonists/wizard/equipment/soulstone.dm
index af5087b5c84..6909768dca2 100644
--- a/code/modules/antagonists/wizard/equipment/soulstone.dm
+++ b/code/modules/antagonists/wizard/equipment/soulstone.dm
@@ -338,7 +338,7 @@
break
if(!chosen_ghost) //Failing that, we grab a ghost
- var/list/consenting_candidates = pollGhostCandidates("Would you like to play as a Shade?", "Cultist", null, ROLE_CULTIST, 50, POLL_IGNORE_SHADE)
+ var/list/consenting_candidates = pollGhostCandidates("Would you like to play as a Shade?", ROLE_CULTIST, null, 5 SECONDS, ignore_category = POLL_IGNORE_CULT_SHADE)
if(consenting_candidates.len)
chosen_ghost = pick(consenting_candidates)
if(!T)
diff --git a/code/modules/antagonists/wizard/wizard.dm b/code/modules/antagonists/wizard/wizard.dm
index b08b67b13c7..46cbfb3c857 100644
--- a/code/modules/antagonists/wizard/wizard.dm
+++ b/code/modules/antagonists/wizard/wizard.dm
@@ -2,7 +2,8 @@
name = "Space Wizard"
roundend_category = "wizards/witches"
antagpanel_category = "Wizard"
- job_rank = ROLE_WIZARD
+ banning_key = ROLE_WIZARD
+ required_living_playtime = 8
antag_moodlet = /datum/mood_event/focused
hijack_speed = 0.5
var/strip = TRUE //strip before equipping
@@ -182,12 +183,12 @@
/datum/antagonist/wizard/apply_innate_effects(mob/living/mob_override)
var/mob/living/M = mob_override || owner.current
update_wiz_icons_added(M, wiz_team ? TRUE : FALSE) //Don't bother showing the icon if you're solo wizard
- M.faction |= ROLE_WIZARD
+ M.faction |= FACTION_WIZARD
/datum/antagonist/wizard/remove_innate_effects(mob/living/mob_override)
var/mob/living/M = mob_override || owner.current
update_wiz_icons_removed(M)
- M.faction -= ROLE_WIZARD
+ M.faction -= FACTION_WIZARD
/datum/antagonist/wizard/get_admin_commands()
diff --git a/code/modules/antagonists/xeno/xeno.dm b/code/modules/antagonists/xeno/xeno.dm
index 7845ec7d225..dfabb8366e4 100644
--- a/code/modules/antagonists/xeno/xeno.dm
+++ b/code/modules/antagonists/xeno/xeno.dm
@@ -11,7 +11,7 @@
/datum/antagonist/xeno
name = "Xenomorph"
- job_rank = ROLE_ALIEN
+ banning_key = ROLE_ALIEN
show_in_antagpanel = FALSE
prevent_roundtype_conversion = FALSE
show_to_ghosts = TRUE
diff --git a/code/modules/awaymissions/corpse.dm b/code/modules/awaymissions/corpse.dm
index 45d5cc86506..281f873cc73 100644
--- a/code/modules/awaymissions/corpse.dm
+++ b/code/modules/awaymissions/corpse.dm
@@ -28,9 +28,11 @@
var/mob_color //Change the mob's color
var/assignedrole
var/show_flavour = TRUE
- var/banType = ROLE_LAVALAND
+ var/banType
var/ghost_usable = TRUE
var/use_cooldown = FALSE
+ /// If this should ignore admins disabling ghost roles (like lavaland roles), since it's actually an antagonist.
+ var/is_antagonist = FALSE
//ATTACK GHOST IGNORING PARENT RETURN VALUE
/obj/effect/mob_spawn/attack_ghost(mob/user)
@@ -42,6 +44,10 @@
if(!uses)
to_chat(user, "This spawner is out of charges!")
return
+ if(!SSticker.HasRoundStarted())
+ return
+ if(!user?.client?.can_take_ghost_spawner(banType, use_cooldown, is_ghost_role = !is_antagonist, is_admin_spawned = flags_1 & ADMIN_SPAWNED_1))
+ return
if(is_banned_from(user.key, banType))
to_chat(user, "You are jobanned!")
return
@@ -402,6 +408,17 @@
id_job = JOB_NAME_BARTENDER
use_cooldown = TRUE
+/obj/effect/mob_spawn/human/bartender/alive/beach
+ assignedrole = "Beach Bartender"
+ banType = ROLE_BEACH_BUM
+ outfit = /datum/outfit/spacebartender/beach
+
+/datum/outfit/spacebartender/beach/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
+ ..()
+ if(visualsOnly)
+ return
+ H.dna.add_mutation(STONER)
+
/datum/outfit/spacebartender
name = "Space Bartender"
uniform = /obj/item/clothing/under/rank/civilian/bartender
@@ -434,6 +451,7 @@
flavour_text = "Ch'yea. You came here, like, on spring break, hopin' to pick up some bangin' hot chicks, y'knaw?"
assignedrole = "Beach Bum"
use_cooldown = TRUE
+ banType = ROLE_BEACH_BUM
/obj/effect/mob_spawn/human/beach/alive/lifeguard
short_desc = "You're a spunky lifeguard!"
@@ -512,29 +530,6 @@
back = /obj/item/storage/backpack/security
id = /obj/item/card/id/job/security_officer
-
-/obj/effect/mob_spawn/human/commander/alive
- death = FALSE
- roundstart = FALSE
- mob_name = "\improper Nanotrasen Commander"
- name = "sleeper"
- icon = 'icons/obj/machines/sleeper.dmi'
- icon_state = "sleeper"
- short_desc = "You are a Nanotrasen Commander!"
- use_cooldown = TRUE
-
-/obj/effect/mob_spawn/human/nanotrasensoldier/alive
- death = FALSE
- roundstart = FALSE
- mob_name = "Private Security Officer"
- name = "sleeper"
- icon = 'icons/obj/machines/sleeper.dmi'
- icon_state = "sleeper"
- faction = "nanotrasenprivate"
- short_desc = "You are a Nanotrasen Private Security Officer!"
- use_cooldown = TRUE
-
-
/////////////////Spooky Undead//////////////////////
/obj/effect/mob_spawn/human/skeleton
@@ -549,30 +544,16 @@
icon = 'icons/effects/blood.dmi'
icon_state = "remains"
short_desc = "By unknown powers, your skeletal remains have been reanimated!"
- flavour_text = "Walk this mortal plain and terrorize all living adventurers who dare cross your path."
+ flavour_text = "Walk this mortal plane and terrorize all living adventurers who dare cross your path."
assignedrole = "Skeleton"
use_cooldown = TRUE
+ banType = ROLE_SKELETAL_REMAINS
/obj/effect/mob_spawn/human/skeleton/alive/equip(mob/living/carbon/human/H)
var/obj/item/implant/exile/implant = new/obj/item/implant/exile(H)
implant.implant(H)
H.set_species(/datum/species/skeleton)
-/obj/effect/mob_spawn/human/zombie
- name = "rotting corpse"
- mob_name = "zombie"
- mob_species = /datum/species/zombie
- assignedrole = "Zombie"
-
-/obj/effect/mob_spawn/human/zombie/alive
- death = FALSE
- roundstart = FALSE
- icon = 'icons/effects/blood.dmi'
- icon_state = "remains"
- short_desc = "By unknown powers, your rotting remains have been resurrected!"
- flavour_text = "Walk this mortal plain and terrorize all living adventurers who dare cross your path."
- use_cooldown = TRUE
-
/obj/effect/mob_spawn/human/abductor
name = "abductor"
mob_name = "alien"
@@ -584,25 +565,6 @@
uniform = /obj/item/clothing/under/color/grey
shoes = /obj/item/clothing/shoes/combat
-
-//For ghost bar.
-/obj/effect/mob_spawn/human/alive/space_bar_patron
- name = "Bar cryogenics"
- mob_name = "Bar patron"
- random = TRUE
- permanent = TRUE
- uses = -1
- outfit = /datum/outfit/spacebartender
- assignedrole = "Space Bar Patron"
-
-//ATTACK HAND IGNORING PARENT RETURN VALUE
-/obj/effect/mob_spawn/human/alive/space_bar_patron/attack_hand(mob/user)
- var/despawn = alert("Return to cryosleep? (Warning, Your mob will be deleted!)",,"Yes","No")
- if(despawn != "Yes" || !loc || !Adjacent(user))
- return
- user.visible_message("[user.name] climbs back into cryosleep...")
- qdel(user)
-
/datum/outfit/cryobartender
name = "Cryogenic Bartender"
uniform = /obj/item/clothing/under/rank/civilian/bartender
diff --git a/code/modules/awaymissions/mission_code/Academy.dm b/code/modules/awaymissions/mission_code/Academy.dm
index 724aa39b410..f62053e356d 100644
--- a/code/modules/awaymissions/mission_code/Academy.dm
+++ b/code/modules/awaymissions/mission_code/Academy.dm
@@ -90,7 +90,7 @@
var/mob/living/current_wizard = null
var/next_check = 0
var/cooldown = 600
- var/faction = ROLE_WIZARD
+ var/faction = FACTION_WIZARD
var/braindead_check = 0
/obj/structure/academy_wizard_spawner/New()
@@ -125,7 +125,7 @@
if(!current_wizard)
return
- var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as Wizard Academy Defender?", ROLE_WIZARD, null, ROLE_WIZARD, 50, current_wizard)
+ var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as Wizard Academy Defender?", ROLE_WIZARD, /datum/role_preference/midround_ghost/wizard, 10 SECONDS, current_wizard)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
@@ -133,6 +133,7 @@
current_wizard.ghostize(FALSE) // on the off chance braindead defender gets back in
current_wizard.key = C.key
else
+ current_wizard.playable_bantype = ROLE_WIZARD
current_wizard.ghostize(FALSE,SENTIENCE_FORCE)
/obj/structure/academy_wizard_spawner/proc/summon_wizard()
@@ -313,7 +314,7 @@
A.setup_master(user)
servant_mind.transfer_to(H)
- var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [user.real_name] Servant?", ROLE_WIZARD, null, ROLE_WIZARD, 50, H)
+ var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [user.real_name] Servant?", ROLE_WIZARD, /datum/role_preference/midround_ghost/wizard, 10 SECONDS, H)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
message_admins("[ADMIN_LOOKUPFLW(C)] was spawned as Dice Servant")
diff --git a/code/modules/awaymissions/mission_code/snowdin.dm b/code/modules/awaymissions/mission_code/snowdin.dm
index 12c18edec71..1eabeb89289 100644
--- a/code/modules/awaymissions/mission_code/snowdin.dm
+++ b/code/modules/awaymissions/mission_code/snowdin.dm
@@ -577,7 +577,7 @@
icon_state = "sleeper"
roundstart = FALSE
death = FALSE
- faction = ROLE_SYNDICATE
+ faction = FACTION_SYNDICATE
outfit = /datum/outfit/snowsyndie
short_desc = "You are a syndicate operative recently awoken from cryostasis in an underground outpost."
flavour_text = "You are a syndicate operative recently awoken from cryostasis in an underground outpost. Monitor Nanotrasen communications and record information. All intruders should be \
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 401e4131f8b..1acd467413c 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -24,10 +24,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/tip_delay = 500 //tip delay in milliseconds
//Antag preferences
- var/list/be_special = list() //Special role selection
- var/tmp/old_be_special = 0 //Bitflag version of be_special, used to update old savefiles and nothing more
- //If it's 0, that's good, if it's anything but 0, the owner of this prefs file's antag choices were,
- //autocorrected this round, not that you'd need to check that.
+ var/list/role_preferences = list() //Special role selection
var/UI_style = null
var/outline_color = COLOR_BLUE_GRAY
@@ -135,11 +132,12 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/list/dat = list("
"
+ if(ban_antagonists)
+ dat += "You are banned from all antagonist roles. \
+ Show Info "
+ if(ban_forced_antagonists)
+ dat += "You are banned from all forced antagonist roles (such as brainwashing). \
+ Show Info "
+ if(ban_ghost)
+ dat += "You are banned from all non-antagonist ghost roles. \
+ Show Info "
+ // --------------------------------------------
+ // Antagonist roles
+ dat += "