diff --git a/code/datums/browser.dm b/code/datums/browser.dm index bfdd8cc9c82..49226c8ae97 100644 --- a/code/datums/browser.dm +++ b/code/datums/browser.dm @@ -390,7 +390,7 @@ if ("color") settings["mainsettings"][setting]["value"] = input(user, "Enter new value for [settings["mainsettings"][setting]["desc"]]", "Enter new value for [settings["mainsettings"][setting]["desc"]]", settings["mainsettings"][setting]["value"]) as color if ("boolean") - settings["mainsettings"][setting]["value"] = input(user, "[settings["mainsettings"][setting]["desc"]]?") in list("Yes","No") + settings["mainsettings"][setting]["value"] = (settings["mainsettings"][setting]["value"] == "Yes") ? "No" : "Yes" if ("ckey") settings["mainsettings"][setting]["value"] = input(user, "[settings["mainsettings"][setting]["desc"]]?") in list("none") + GLOB.directory if (settings["mainsettings"][setting]["callback"]) diff --git a/code/datums/ert.dm b/code/datums/ert.dm index d2d2bbbf06e..f0f783aebf0 100644 --- a/code/datums/ert.dm +++ b/code/datums/ert.dm @@ -10,6 +10,12 @@ var/mission = "Assist the station." var/teamsize = 5 var/polldesc + /// If TRUE, gives the team members "[role] [random last name]" style names + var/random_names = TRUE + /// If TRUE, the admin who created the response team will be spawned in the briefing room in their preferred briefing outfit (assuming they're a ghost) + var/spawn_admin = FALSE + /// If TRUE, we try and pick one of the most experienced players who volunteered to fill the leader slot + var/leader_experience = TRUE /datum/ert/New() if (!polldesc) @@ -39,10 +45,12 @@ code = "Green" teamsize = 1 opendoors = FALSE - leader_role = /datum/antagonist/official - roles = list(/datum/antagonist/official) + leader_role = /datum/antagonist/ert/official + roles = list(/datum/antagonist/ert/official) rename_team = "CentCom Officials" polldesc = "a CentCom Official" + random_names = FALSE + leader_experience = FALSE /datum/ert/centcom_official/New() mission = "Conduct a routine performance review of [station_name()] and its Captain." @@ -71,6 +79,12 @@ rename_team = "Horde of Interns" mission = "Assist in conflict resolution." polldesc = "an unpaid internship opportunity with Nanotrasen" + random_names = FALSE + +/datum/ert/intern/unarmed + roles = list(/datum/antagonist/ert/intern/unarmed) + leader_role = /datum/antagonist/ert/intern/leader/unarmed + rename_team = "Unarmed Horde of Interns" /datum/ert/erp roles = list(/datum/antagonist/ert/security/party, /datum/antagonist/ert/clown/party, /datum/antagonist/ert/engineer/party, /datum/antagonist/ert/janitor/party) diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm index fefba6ef918..a45475b0c22 100644 --- a/code/modules/admin/verbs/one_click_antag.dm +++ b/code/modules/admin/verbs/one_click_antag.dm @@ -1,3 +1,6 @@ +/// If we spawn an ERT with the "choose experienced leader" option, select the leader from the top X playtimes +#define ERT_EXPERIENCED_LEADER_CHOOSE_TOP 3 + /client/proc/one_click_antag() set name = "Create Antagonist" set desc = "Auto-create an antagonist of your choice" @@ -251,6 +254,9 @@ .["mainsettings"]["mission"]["value"] = newtemplate.mission .["mainsettings"]["polldesc"]["value"] = newtemplate.polldesc .["mainsettings"]["open_armory"]["value"] = newtemplate.opendoors ? "Yes" : "No" + .["mainsettings"]["leader_experience"]["value"] = newtemplate.leader_experience ? "Yes" : "No" + .["mainsettings"]["random_names"]["value"] = newtemplate.random_names ? "Yes" : "No" + .["mainsettings"]["spawn_admin"]["value"] = newtemplate.spawn_admin ? "Yes" : "No" /datum/admins/proc/equipAntagOnDummy(mob/living/carbon/human/dummy/mannequin, datum/antagonist/antag) @@ -259,8 +265,6 @@ if (ispath(antag, /datum/antagonist/ert)) var/datum/antagonist/ert/ert = antag mannequin.equipOutfit(initial(ert.outfit), TRUE) - else if (ispath(antag, /datum/antagonist/official)) - mannequin.equipOutfit(/datum/outfit/centcom/centcom_official, TRUE) /datum/admins/proc/makeERTPreviewIcon(list/settings) // Set up the dummy for its photoshoot @@ -318,6 +322,9 @@ "polldesc" = list("desc" = "Ghost poll description", "type" = "string", "value" = ertemplate.polldesc), "enforce_human" = list("desc" = "Enforce human authority", "type" = "boolean", "value" = "[(CONFIG_GET(flag/enforce_human_authority) ? "Yes" : "No")]"), "open_armory" = list("desc" = "Open armory doors", "type" = "boolean", "value" = "[(ertemplate.opendoors ? "Yes" : "No")]"), + "leader_experience" = list("desc" = "Pick an experienced leader", "type" = "boolean", "value" = "[(ertemplate.leader_experience ? "Yes" : "No")]"), + "random_names" = list("desc" = "Randomize names", "type" = "boolean", "value" = "[(ertemplate.random_names ? "Yes" : "No")]"), + "spawn_admin" = list("desc" = "Spawn yourself as briefing officer", "type" = "boolean", "value" = "[(ertemplate.spawn_admin ? "Yes" : "No")]") ) ) @@ -339,77 +346,110 @@ ertemplate.teamsize = prefs["teamsize"]["value"] ertemplate.mission = prefs["mission"]["value"] ertemplate.polldesc = prefs["polldesc"]["value"] - ertemplate.enforce_human = prefs["enforce_human"]["value"] == "Yes" ? TRUE : FALSE - ertemplate.opendoors = prefs["open_armory"]["value"] == "Yes" ? TRUE : FALSE + ertemplate.enforce_human = prefs["enforce_human"]["value"] == "Yes" // these next 5 are effectively toggles + ertemplate.opendoors = prefs["open_armory"]["value"] == "Yes" + ertemplate.leader_experience = prefs["leader_experience"]["value"] == "Yes" + ertemplate.random_names = prefs["random_names"]["value"] == "Yes" + ertemplate.spawn_admin = prefs["spawn_admin"]["value"] == "Yes" - var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you wish to be considered for [ertemplate.polldesc]?", "deathsquad", null) + var/list/spawnpoints = GLOB.emergencyresponseteamspawn + var/index = 0 + + if(ertemplate.spawn_admin) + if(isobserver(usr)) + var/mob/living/carbon/human/admin_officer = new (spawnpoints[1]) + var/chosen_outfit = usr.client?.prefs?.brief_outfit + usr.client.prefs.copy_to(admin_officer) + admin_officer.equipOutfit(chosen_outfit) + admin_officer.key = usr.key + else + to_chat(usr, "Could not spawn you in as briefing officer as you are not a ghost!") + + var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you wish to be considered for [ertemplate.polldesc]?", "deathsquad") var/teamSpawned = FALSE - if(candidates.len > 0) - //Pick the (un)lucky players - var/numagents = min(ertemplate.teamsize,candidates.len) - - //Create team - var/datum/team/ert/ert_team = new ertemplate.team - if(ertemplate.rename_team) - ert_team.name = ertemplate.rename_team - - //Asign team objective - var/datum/objective/missionobj = new - missionobj.team = ert_team - missionobj.explanation_text = ertemplate.mission - missionobj.completed = TRUE - ert_team.objectives += missionobj - ert_team.mission = missionobj - - var/list/spawnpoints = GLOB.emergencyresponseteamspawn - var/index = 0 - while(numagents && candidates.len) - var/spawnloc = spawnpoints[index+1] - //loop through spawnpoints one at a time - index = (index + 1) % spawnpoints.len - var/mob/dead/observer/chosen_candidate = pick(candidates) - candidates -= chosen_candidate - if(!chosen_candidate.key) - continue - - //Spawn the body - var/mob/living/carbon/human/ERTOperative = new ertemplate.mobtype(spawnloc) - chosen_candidate.client.prefs.copy_to(ERTOperative) - ERTOperative.key = chosen_candidate.key - - if(ertemplate.enforce_human || !ERTOperative.dna.species.changesource_flags & ERT_SPAWN) // Don't want any exploding plasmemes - ERTOperative.set_species(/datum/species/human) - - //Give antag datum - var/datum/antagonist/ert/ert_antag - - if(numagents == 1) - ert_antag = new ertemplate.leader_role - else - ert_antag = ertemplate.roles[WRAP(numagents,1,length(ertemplate.roles) + 1)] - ert_antag = new ert_antag - - ERTOperative.mind.add_antag_datum(ert_antag,ert_team) - ERTOperative.mind.assigned_role = ert_antag.name - - //Logging and cleanup - log_game("[key_name(ERTOperative)] has been selected as an [ert_antag.name]") - numagents-- - teamSpawned++ - - if (teamSpawned) - message_admins("[ertemplate.polldesc] has spawned with the mission: [ertemplate.mission]") - - //Open the Armory doors - if(ertemplate.opendoors) - for(var/obj/machinery/door/poddoor/ert/door in GLOB.airlocks) - door.open() - CHECK_TICK - return TRUE - else + if(candidates.len == 0) return FALSE + //Pick the (un)lucky players + var/numagents = min(ertemplate.teamsize,candidates.len) + + //Create team + var/datum/team/ert/ert_team = new ertemplate.team () + if(ertemplate.rename_team) + ert_team.name = ertemplate.rename_team + + //Assign team objective + var/datum/objective/missionobj = new () + missionobj.team = ert_team + missionobj.explanation_text = ertemplate.mission + missionobj.completed = TRUE + ert_team.objectives += missionobj + ert_team.mission = missionobj + + var/mob/dead/observer/earmarked_leader + var/leader_spawned = FALSE // just in case the earmarked leader disconnects or becomes unavailable, we can try giving leader to the last guy to get chosen + + if(ertemplate.leader_experience) + var/list/candidate_living_exps = list() + for(var/i in candidates) + var/mob/dead/observer/potential_leader = i + candidate_living_exps[potential_leader] = potential_leader.client?.get_exp_living(TRUE) + + candidate_living_exps = sortList(candidate_living_exps, cmp=/proc/cmp_numeric_dsc) + if(candidate_living_exps.len > ERT_EXPERIENCED_LEADER_CHOOSE_TOP) + candidate_living_exps = candidate_living_exps.Cut(ERT_EXPERIENCED_LEADER_CHOOSE_TOP+1) // pick from the top ERT_EXPERIENCED_LEADER_CHOOSE_TOP contenders in playtime + earmarked_leader = pick(candidate_living_exps) + else + earmarked_leader = pick(candidates) + + while(numagents && candidates.len) + var/spawnloc = spawnpoints[index+1] + //loop through spawnpoints one at a time + index = (index + 1) % spawnpoints.len + var/mob/dead/observer/chosen_candidate = earmarked_leader || pick(candidates) // this way we make sure that our leader gets chosen + candidates -= chosen_candidate + if(!chosen_candidate?.key) + continue + + //Spawn the body + var/mob/living/carbon/human/ert_operative = new ertemplate.mobtype(spawnloc) + chosen_candidate.client.prefs.copy_to(ert_operative) + ert_operative.key = chosen_candidate.key + + if(ertemplate.enforce_human || !ert_operative.dna.species.changesource_flags & ERT_SPAWN) // Don't want any exploding plasmemes + ert_operative.set_species(/datum/species/human) + + //Give antag datum + var/datum/antagonist/ert/ert_antag + + if((chosen_candidate == earmarked_leader) || (numagents == 1 && !leader_spawned)) + ert_antag = new ertemplate.leader_role () + earmarked_leader = null + leader_spawned = TRUE + else + ert_antag = ertemplate.roles[WRAP(numagents,1,length(ertemplate.roles) + 1)] + ert_antag = new ert_antag () + ert_antag.random_names = ertemplate.random_names + + ert_operative.mind.add_antag_datum(ert_antag,ert_team) + ert_operative.mind.assigned_role = ert_antag.name + + //Logging and cleanup + log_game("[key_name(ert_operative)] has been selected as an [ert_antag.name]") + numagents-- + teamSpawned++ + + if (teamSpawned) + message_admins("[ertemplate.polldesc] has spawned with the mission: [ertemplate.mission]") + + //Open the Armory doors + if(ertemplate.opendoors) + for(var/obj/machinery/door/poddoor/ert/door in GLOB.airlocks) + door.open() + CHECK_TICK + return TRUE + return //Abductors @@ -420,3 +460,5 @@ /datum/admins/proc/makeRevenant() new /datum/round_event/ghost_role/revenant(TRUE, TRUE) return 1 + +#undef ERT_EXPERIENCED_LEADER_CHOOSE_TOP diff --git a/code/modules/antagonists/ert/ert.dm b/code/modules/antagonists/ert/ert.dm index 3d85fa17b0a..b0ab5882c8f 100644 --- a/code/modules/antagonists/ert/ert.dm +++ b/code/modules/antagonists/ert/ert.dm @@ -38,6 +38,33 @@ /datum/antagonist/ert/proc/update_name() owner.current.fully_replace_character_name(owner.current.real_name,"[role] [pick(name_source)]") +/datum/antagonist/ert/official + name = "CentCom Official" + show_name_in_check_antagonists = TRUE + var/datum/objective/mission + role = "Inspector" + random_names = FALSE + outfit = /datum/outfit/centcom/centcom_official + +/datum/antagonist/ert/official/greet() + to_chat(owner, "You are a CentCom Official.") + if (ert_team) + to_chat(owner, "Central Command is sending you to [station_name()] with the task: [ert_team.mission.explanation_text]") + else + to_chat(owner, "Central Command is sending you to [station_name()] with the task: [mission.explanation_text]") + +/datum/antagonist/ert/official/forge_objectives() + if (ert_team) + return ..() + if(mission) + return + var/datum/objective/missionobj = new () + missionobj.owner = owner + missionobj.explanation_text = "Conduct a routine performance review of [station_name()] and its Captain." + missionobj.completed = TRUE + mission = missionobj + objectives |= mission + /datum/antagonist/ert/security // kinda handled by the base template but here for completion /datum/antagonist/ert/security/red @@ -128,8 +155,15 @@ /datum/antagonist/ert/intern/leader name = "CentCom Head Intern" outfit = /datum/outfit/centcom/centcom_intern/leader + random_names = FALSE role = "Head Intern" +/datum/antagonist/ert/intern/unarmed + outfit = /datum/outfit/centcom/centcom_intern/unarmed + +/datum/antagonist/ert/intern/leader/unarmed + outfit = /datum/outfit/centcom/centcom_intern/leader/unarmed + /datum/antagonist/ert/clown role = "Clown" outfit = /datum/outfit/centcom/ert/clown diff --git a/code/modules/antagonists/official/official.dm b/code/modules/antagonists/official/official.dm deleted file mode 100644 index 9f17769c536..00000000000 --- a/code/modules/antagonists/official/official.dm +++ /dev/null @@ -1,45 +0,0 @@ -/datum/antagonist/official - name = "CentCom Official" - show_name_in_check_antagonists = TRUE - show_in_antagpanel = FALSE - can_elimination_hijack = ELIMINATION_PREVENT - var/datum/objective/mission - var/datum/team/ert/ert_team - show_to_ghosts = TRUE - -/datum/antagonist/official/greet() - to_chat(owner, "You are a CentCom Official.") - if (ert_team) - to_chat(owner, "Central Command is sending you to [station_name()] with the task: [ert_team.mission.explanation_text]") - else - to_chat(owner, "Central Command is sending you to [station_name()] with the task: [mission.explanation_text]") - -/datum/antagonist/official/proc/equip_official() - var/mob/living/carbon/human/H = owner.current - if(!istype(H)) - return - H.equipOutfit(/datum/outfit/centcom/centcom_official) - - if(CONFIG_GET(flag/enforce_human_authority)) - H.set_species(/datum/species/human) - -/datum/antagonist/official/create_team(datum/team/new_team) - if(istype(new_team)) - ert_team = new_team - -/datum/antagonist/official/proc/forge_objectives() - if (ert_team) - objectives |= ert_team.objectives - else if (!mission) - var/datum/objective/missionobj = new - missionobj.owner = owner - missionobj.explanation_text = "Conduct a routine performance review of [station_name()] and its Captain." - missionobj.completed = 1 - mission = missionobj - objectives |= mission - - -/datum/antagonist/official/on_gain() - forge_objectives() - . = ..() - equip_official() diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index a8fbede4466..b8d2e78804a 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -16,6 +16,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/lastchangelog = "" //Saved changlog filesize to detect if there was a change var/ooccolor = "#c43b23" var/asaycolor = "#ff4500" //This won't change the color for current admins, only incoming ones. + /// If we spawn an ERT as an admin and choose to spawn as the briefing officer, we'll be given this outfit + var/brief_outfit = /datum/outfit/centcom/commander var/enable_tips = TRUE var/tip_delay = 500 //tip delay in milliseconds @@ -733,6 +735,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "Hide Radio Messages: [(chat_toggles & CHAT_RADIO)?"Shown":"Hidden"]
" dat += "Hide Prayers: [(chat_toggles & CHAT_PRAYER)?"Shown":"Hidden"]
" dat += "Ignore Being Summoned as Cult Ghost: [(toggles & ADMIN_IGNORE_CULT_GHOST)?"Don't Allow Being Summoned":"Allow Being Summoned"]
" + dat += "Briefing Officer Outfit: [brief_outfit]
" if(CONFIG_GET(flag/allow_admin_asaycolor)) dat += "
" dat += "ASAY Color:     Change
" @@ -1513,6 +1516,16 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(new_asaycolor) asaycolor = sanitize_ooccolor(new_asaycolor) + if("briefoutfit") + var/list/valid_paths = list() + for(var/datum/outfit/iter_outfit in subtypesof(/datum/outfit)) + if(initial(iter_outfit.can_be_admin_equipped)) + valid_paths[initial(iter_outfit.name)] = path + var/new_outfit = input(user, "Choose your briefing officer outfit:", "Game Preference") as null|anything in valid_paths + new_outfit = valid_paths[new_outfit] + if(new_outfit) + brief_outfit = new_outfit + if("bag") var/new_backpack = input(user, "Choose your character's style of bag:", "Character Preference") as null|anything in GLOB.backpacklist if(new_backpack) diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 3141ffd5e86..e5b82e6a379 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -159,6 +159,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car //general preferences READ_FILE(S["asaycolor"], asaycolor) + READ_FILE(S["brief_outfit"], brief_outfit) READ_FILE(S["ooccolor"], ooccolor) READ_FILE(S["lastchangelog"], lastchangelog) READ_FILE(S["UI_style"], UI_style) @@ -249,6 +250,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car ghost_others = sanitize_inlist(ghost_others, GLOB.ghost_others_options, GHOST_OTHERS_DEFAULT_OPTION) menuoptions = SANITIZE_LIST(menuoptions) be_special = SANITIZE_LIST(be_special) + brief_outfit = sanitize_inlist(brief_outfit, subtypesof(/datum/outfit), null) pda_style = sanitize_inlist(pda_style, GLOB.pda_styles, initial(pda_style)) pda_color = sanitize_hexcolor(pda_color, 6, 1, initial(pda_color)) key_bindings = sanitize_keybindings(key_bindings) @@ -285,6 +287,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car //general preferences WRITE_FILE(S["asaycolor"], asaycolor) + WRITE_FILE(S["brief_outfit"], brief_outfit) WRITE_FILE(S["ooccolor"], ooccolor) WRITE_FILE(S["lastchangelog"], lastchangelog) WRITE_FILE(S["UI_style"], UI_style) diff --git a/code/modules/clothing/outfits/ert.dm b/code/modules/clothing/outfits/ert.dm index 59705f0cfc7..fad9363db0a 100644 --- a/code/modules/clothing/outfits/ert.dm +++ b/code/modules/clothing/outfits/ert.dm @@ -346,6 +346,13 @@ W.registered_name = H.real_name W.update_label() +/datum/outfit/centcom/centcom_intern/unarmed + name = "CentCom Intern (Unarmed)" + belt = null + l_hand = null + l_pocket = null + r_pocket = null + /datum/outfit/centcom/centcom_intern/leader name = "CentCom Head Intern" belt = /obj/item/melee/baton/loaded @@ -354,6 +361,12 @@ l_hand = /obj/item/megaphone head = /obj/item/clothing/head/intern +/datum/outfit/centcom/centcom_intern/leader/unarmed // i'll be nice and let the leader keep their baton and vest + name = "CentCom Head Intern (Unarmed)" + suit_store = null + l_pocket = null + r_pocket = null + /datum/outfit/centcom/ert/janitor/party name = "ERP Cleaning Service" diff --git a/tgstation.dme b/tgstation.dme index 62aa876e2e9..5be450ab8de 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1648,7 +1648,6 @@ #include "code\modules\antagonists\nukeop\equipment\nuclear_challenge.dm" #include "code\modules\antagonists\nukeop\equipment\nuclearbomb.dm" #include "code\modules\antagonists\nukeop\equipment\pinpointer.dm" -#include "code\modules\antagonists\official\official.dm" #include "code\modules\antagonists\pirate\pirate.dm" #include "code\modules\antagonists\revenant\revenant.dm" #include "code\modules\antagonists\revenant\revenant_abilities.dm"