diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 2d717631979..3f8f45c6f0e 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -96,6 +96,7 @@ GLOBAL_LIST_INIT(admin_verbs_fun, list(
/client/proc/change_title_screen, //SKYRAT EDIT ADDITION
/client/proc/change_title_screen_notice, //SKYRAT EDIT ADDITION
/client/proc/change_title_screen_html, //SKYRAT EDIT ADDITION
+ /client/proc/one_click_antag, // SKYRAT EDIT ADDITION - ONE CLICK ANTAG
/client/proc/cmd_select_equipment,
/client/proc/cmd_admin_gib_self,
/client/proc/drop_bomb,
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index a56dae19910..193a5c09027 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -47,6 +47,48 @@
to_chat(usr, "ERROR: Mob not found.", confidential = TRUE)
return
cmd_show_exp_panel(M.client)
+
+// SKYRAT EDIT BEGIN -- ONE CLICK ANTAG
+ else if(href_list["makeAntag"])
+
+ message_admins("[key_name_admin(usr)] is attempting to make [href_list["makeAntag"]]")
+
+ if(!check_rights(R_ADMIN))
+ return
+
+ if (!SSticker.mode)
+ to_chat(usr, "Not until the round starts!", confidential = TRUE)
+ return
+
+ var/opt = null
+ switch(href_list["makeAntag"])
+ if(ROLE_BLOB)
+ opt = input("Set Blob Resource Gain Rate","Set Resource Rate",1) as num|null
+ if(ROLE_TRAITOR)
+ opt = input("How Many", ROLE_TRAITOR, 1) as num|null
+ if(ROLE_CHANGELING)
+ opt = input("How Many", ROLE_CHANGELING, 1) as num|null
+ if(ROLE_CULTIST)
+ opt = input("How Many", ROLE_CULTIST, 2) as num|null
+ if(ROLE_HERETIC)
+ opt = input("How Many", ROLE_HERETIC, 2) as num|null
+ if(ROLE_MONKEY)
+ opt = input("How Many", ROLE_MONKEY, 1) as num|null
+ if(ROLE_REV)
+ opt = input("How Many", ROLE_REV, 1) as num|null
+ if(ROLE_OPERATIVE)
+ opt = input("How Many", ROLE_OPERATIVE, 3) as num|null
+ if(ROLE_FAMILIES)
+ opt = input("How Many", ROLE_FAMILIES, 2) as num|null
+ if(ROLE_INTERNAL_AFFAIRS)
+ opt = input("How Many", ROLE_INTERNAL_AFFAIRS, 1) as num|null
+ if(ROLE_BROTHER)
+ opt = input("How Many", ROLE_BROTHER, 2) as num|null
+ if(src.make_antag(href_list["makeAntag"], opt))
+ message_admins("[key_name_admin(usr)] created '[href_list["makeAntag"]]' with a parameter of '[opt]'.")
+ else message_admins("[key_name_admin(usr)] FAILED to create '[href_list["makeAntag"]]' with a parameter of '[opt]'.")
+// SKYRAT EDIT END -- ONE CLICK ANTAG
+
else if(href_list["forceevent"])
if(!check_rights(R_FUN))
return
diff --git a/modular_skyrat/modules/oneclickantag/oneclickantag.dm b/modular_skyrat/modules/oneclickantag/oneclickantag.dm
new file mode 100644
index 00000000000..3b8032516cf
--- /dev/null
+++ b/modular_skyrat/modules/oneclickantag/oneclickantag.dm
@@ -0,0 +1,283 @@
+/datum/mind/var/list/oneclickantag = list()
+
+/datum/mind/remove_antag_datum(datum)
+ switch(datum)
+ if(/datum/antagonist/traitor)
+ src.oneclickantag += ROLE_TRAITOR
+ if(/datum/antagonist/changeling)
+ src.oneclickantag += ROLE_CHANGELING
+ if(/datum/antagonist/rev)
+ src.oneclickantag += ROLE_REV
+ if(/datum/antagonist/cult)
+ src.oneclickantag += ROLE_CULTIST
+ if(/datum/antagonist/brother)
+ src.oneclickantag += ROLE_BROTHER
+ if(/datum/antagonist/monkey)
+ src.oneclickantag += ROLE_MONKEY
+ if(/datum/antagonist/traitor/internal_affairs)
+ src.oneclickantag += ROLE_INTERNAL_AFFAIRS
+ if(/datum/antagonist/gang)
+ src.oneclickantag += ROLE_FAMILIES
+ if(/datum/antagonist/heretic)
+ src.oneclickantag += ROLE_HERETIC
+ else
+ message_admins("Unable to update [src]'s previous antag list for One Click Antag. Blame coders.")
+ return ..()
+
+/datum/mind/proc/make_antag(antagtype, opt = null)
+ message_admins("[src] was turned into [antagtype]")
+ src.oneclickantag += antagtype
+ switch(antagtype)
+ if(ROLE_TRAITOR)
+ src.add_antag_datum(/datum/antagonist/traitor)
+ if(ROLE_CHANGELING)
+ src.add_antag_datum(/datum/antagonist/changeling)
+ if(ROLE_REV)
+ var/datum/antagonist/rev/head/antag = new
+ antag.give_flash = TRUE
+ antag.give_hud = TRUE
+ src.add_antag_datum(antag)
+ if(ROLE_CULTIST)
+ src.add_antag_datum(/datum/antagonist/cult)
+ if(ROLE_BROTHER)
+ if(!istype(opt, /datum/team/brother_team))
+ message_admins("Attempted to create bloodbrothers but no team was specified!")
+ return FALSE
+ var/datum/team/brother_team/team = opt
+ src.add_antag_datum(/datum/antagonist/brother, team)
+ if(ROLE_MONKEY)
+ src.add_antag_datum(/datum/antagonist/monkey/leader)
+ if(ROLE_INTERNAL_AFFAIRS)
+ src.add_antag_datum(/datum/antagonist/traitor/internal_affairs)
+ if(ROLE_FAMILIES)
+ src.add_antag_datum(/datum/antagonist/gang)
+ if(ROLE_HERETIC)
+ src.add_antag_datum(/datum/antagonist/heretic)
+ else
+ message_admins("[src] could not be turned into [antagtype] as it is not implemented; blame coders.")
+ return FALSE
+ return TRUE
+
+/client/proc/one_click_antag()
+ set name = "Create Antagonist"
+ set desc = "Auto-create an antagonist of your choice"
+ set category = "Admin.Events"
+
+ if(holder)
+ holder.one_click_antag()
+ return
+
+/**
+If anyone can figure out how to get Obsessed to work I would be very appreciative.
+**/
+/datum/admins/proc/one_click_antag()
+ var/dat = ""
+ for(var/role in GLOB.special_roles)
+ if(role in list(ROLE_MALF, ROLE_PAI, ROLE_SENTIENCE, ROLE_OBSESSED))
+ continue
+ dat += "Make [role](s)."
+ if(antag_is_ghostrole(role))
+ dat += " (Requires Ghosts)"
+ dat += "
"
+ var/datum/browser/popup = new(usr, "oneclickantag", "Quick-Create Antagonist", 400, 400)
+ popup.set_content(dat)
+ popup.open()
+
+/datum/admins/proc/can_make_antag(mob/living/carbon/human/applicant, targetrole, onstation = TRUE, conscious = TRUE)
+ if(applicant.mind.oneclickantag.Find(targetrole))
+ return FALSE
+ if(applicant.mind.special_role)
+ return FALSE
+ if(!(targetrole in applicant.client.prefs.be_special))
+ return FALSE
+ if(onstation)
+ var/turf/T = get_turf(applicant)
+ if(!is_station_level(T.z))
+ return FALSE
+ if(conscious && applicant.stat)
+ return FALSE
+ if(!considered_alive(applicant.mind) || considered_afk(applicant.mind))
+ return FALSE
+ if(is_banned_from(applicant.ckey, list(targetrole, ROLE_SYNDICATE)))
+ return FALSE
+ return TRUE
+
+/datum/admins/
+ var/MAKEANTAG_RESTRICTLIST = list()
+ var/MAKEANTAG_PL_DEFAULT_SECURITY = list("Prisoner", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Corrections Officer", "Civil Disputes Officer", "Security Medic", "Security Sergeant", "Blueshield")
+ var/MAKEANTAG_PL_DEFAULT_HEADS = list("Captain","Head of Personnel","Research Director","Chief Engineer","Chief Medical Officer","Head of Security","Quartermaster")
+ var/MAKEANTAG_PL_DEFAULT_SILICON = list("AI", "Cyborg")
+
+/datum/admins/proc/antag_get_protected_roles(antagtype)
+ if(MAKEANTAG_RESTRICTLIST[antagtype])
+ return MAKEANTAG_RESTRICTLIST[antagtype]
+ var/c_p = CONFIG_GET(flag/protect_roles_from_antagonist)
+ var/c_a = CONFIG_GET(flag/protect_assistant_from_antagonist)
+ var/list/p_p = list()
+ var/list/p_r = list()
+ switch(antagtype)
+ if(ROLE_TRAITOR)
+ p_p += MAKEANTAG_PL_DEFAULT_SECURITY
+ p_p += MAKEANTAG_PL_DEFAULT_HEADS
+ if(ROLE_CHANGELING)
+ p_p += MAKEANTAG_PL_DEFAULT_SECURITY
+ p_p += MAKEANTAG_PL_DEFAULT_HEADS
+ if(ROLE_CULTIST)
+ p_p += MAKEANTAG_PL_DEFAULT_SECURITY
+ p_p += MAKEANTAG_PL_DEFAULT_HEADS
+ p_p += MAKEANTAG_PL_DEFAULT_SILICON
+ p_p += list("Chaplain", "Head of Personnel")
+ if(ROLE_HERETIC)
+ p_p += MAKEANTAG_PL_DEFAULT_SECURITY
+ p_p += MAKEANTAG_PL_DEFAULT_HEADS
+ p_r += MAKEANTAG_PL_DEFAULT_SILICON
+ if(ROLE_FAMILIES)
+ p_r += MAKEANTAG_PL_DEFAULT_SECURITY
+ p_p += MAKEANTAG_PL_DEFAULT_HEADS
+ p_r += MAKEANTAG_PL_DEFAULT_SILICON
+ p_r += list("Head of Personnel")
+ if(ROLE_MONKEY)
+ p_r += MAKEANTAG_PL_DEFAULT_SILICON
+ p_p += MAKEANTAG_PL_DEFAULT_HEADS
+ p_r += list("Prisoner")
+ if(ROLE_REV)
+ p_r += MAKEANTAG_PL_DEFAULT_SECURITY
+ p_r += MAKEANTAG_PL_DEFAULT_HEADS
+ p_r += MAKEANTAG_PL_DEFAULT_SILICON
+ if(c_a)
+ p_r += list("Assistant")
+ if(c_p)
+ p_r += p_p
+ MAKEANTAG_RESTRICTLIST[antagtype] = p_r
+ return p_r
+
+/datum/admins/proc/antag_is_ghostrole(antagtype)
+ switch(antagtype)
+ if(ROLE_WIZARD)
+ return TRUE
+ if(ROLE_OPERATIVE)
+ return TRUE
+ if(ROLE_NINJA)
+ return TRUE
+ if(ROLE_ABDUCTOR)
+ return TRUE
+ if(ROLE_REVENANT)
+ return TRUE
+ if(ROLE_SPACE_DRAGON)
+ return TRUE
+ if(ROLE_BLOB)
+ return TRUE
+ if(ROLE_ALIEN)
+ return TRUE
+ return FALSE
+
+/datum/admins/proc/make_antag(antagtype, opt)
+ if(antag_is_ghostrole(antagtype))
+ return make_antag_ghostrole(antagtype, opt)
+ var/datum/team/brother_team/team
+ if(antagtype == ROLE_BROTHER)
+ team = new
+ team.pick_meeting_area()
+ team.forge_brother_objectives()
+ var/list/restricted_jobs = antag_get_protected_roles(antagtype)
+ var/list/mob/living/carbon/human/candidates = list()
+ var/mob/living/carbon/human/holder = null
+ for(var/mob/living/carbon/human/applicant in GLOB.player_list)
+ if(can_make_antag(applicant, antagtype))
+ if(applicant.job in restricted_jobs)
+ continue
+ candidates += applicant
+ if(candidates.len)
+ candidates = shuffle(candidates)
+ var/canmake = min(candidates.len, opt)
+ for(var/index = 0, index