diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm
index 1fba96b1eb09..7fab07159518 100644
--- a/code/__DEFINES/antagonists.dm
+++ b/code/__DEFINES/antagonists.dm
@@ -4,8 +4,6 @@
#define ANTAG_DATUM_CLOCKCULT_SILENT /datum/antagonist/clockcult/silent
#define ANTAG_DATUM_DEVIL /datum/antagonist/devil
#define ANTAG_DATUM_NINJA /datum/antagonist/ninja
-#define ANTAG_DATUM_NINJA_FRIENDLY /datum/antagonist/ninja/friendly
-#define ANTAG_DATUM_NINJA_RANDOM /datum/antagonist/ninja/randomAllegiance/
#define ANTAG_DATUM_TRAITOR /datum/antagonist/traitor
#define ANTAG_DATUM_TRAITOR_HUMAN /datum/antagonist/traitor/human
#define ANTAG_DATUM_TRAITOR_AI /datum/antagonist/traitor/AI
diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm
index 5b48890ce676..1d3300bbf8c1 100644
--- a/code/__DEFINES/role_preferences.dm
+++ b/code/__DEFINES/role_preferences.dm
@@ -42,7 +42,7 @@ GLOBAL_LIST_INIT(special_roles, list(
ROLE_NINJA,
ROLE_MONKEY = /datum/game_mode/monkey,
ROLE_REVENANT,
- ROLE_ABDUCTOR = /datum/game_mode/abduction,
+ ROLE_ABDUCTOR,
ROLE_DEVIL = /datum/game_mode/devil,
ROLE_SERVANT_OF_RATVAR = /datum/game_mode/clockwork_cult
))
diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm
index 1966fa8219db..5ff7cd9e496a 100644
--- a/code/__HELPERS/roundend.dm
+++ b/code/__HELPERS/roundend.dm
@@ -26,6 +26,9 @@
var/list/team_ids = list()
for(var/datum/antagonist/A in GLOB.antagonists)
+ if(!A.owner)
+ continue
+
var/list/antag_info = list()
antag_info["key"] = A.owner.key
antag_info["name"] = A.owner.name
@@ -41,8 +44,6 @@
team_ids[T] = team_gid++
antag_info["team"]["id"] = team_ids[T]
- if(!A.owner)
- continue
if(A.objectives.len)
for(var/datum/objective/O in A.objectives)
var/result = O.check_completion() ? "SUCCESS" : "FAIL"
@@ -368,6 +369,8 @@
var/list/all_antagonists = list()
for(var/datum/antagonist/A in GLOB.antagonists)
+ if(!A.owner)
+ continue
all_teams |= A.get_team()
all_antagonists += A
diff --git a/code/datums/antagonists/abductor.dm b/code/datums/antagonists/abductor.dm
index a98acf054e8f..fde8d0059b60 100644
--- a/code/datums/antagonists/abductor.dm
+++ b/code/datums/antagonists/abductor.dm
@@ -1,24 +1,33 @@
+#define ABDUCTOR_MAX_TEAMS 4
+
/datum/antagonist/abductor
name = "Abductor"
roundend_category = "abductors"
+ antagpanel_category = "Abductor"
job_rank = ROLE_ABDUCTOR
+ show_in_antagpanel = FALSE //should only show subtypes
var/datum/team/abductor_team/team
var/sub_role
var/outfit
var/landmark_type
var/greet_text
+
/datum/antagonist/abductor/agent
+ name = "Abductor Agent"
sub_role = "Agent"
outfit = /datum/outfit/abductor/agent
landmark_type = /obj/effect/landmark/abductor/agent
greet_text = "Use your stealth technology and equipment to incapacitate humans for your scientist to retrieve."
+ show_in_antagpanel = TRUE
/datum/antagonist/abductor/scientist
+ name = "Abductor Scientist"
sub_role = "Scientist"
outfit = /datum/outfit/abductor/scientist
landmark_type = /obj/effect/landmark/abductor/scientist
greet_text = "Use your stealth technology and equipment to incapacitate humans for your scientist to retrieve."
+ show_in_antagpanel = TRUE
/datum/antagonist/abductor/create_team(datum/team/abductor_team/new_team)
if(!new_team)
@@ -33,6 +42,7 @@
/datum/antagonist/abductor/on_gain()
SSticker.mode.abductors += owner
owner.special_role = "[name] [sub_role]"
+ owner.assigned_role = "[name] [sub_role]"
owner.objectives += team.objectives
finalize_abductor()
return ..()
@@ -72,11 +82,48 @@
var/datum/species/abductor/A = H.dna.species
A.scientist = TRUE
+/datum/antagonist/abductor/admin_add(datum/mind/new_owner,mob/admin)
+ var/list/current_teams = list()
+ for(var/datum/team/abductor_team/T in get_all_teams(/datum/team/abductor_team))
+ current_teams[T.name] = T
+ var/choice = input(admin,"Add to which team ?") as null|anything in (current_teams + "new team")
+ if (choice == "new team")
+ team = new
+ else if(choice in current_teams)
+ team = current_teams[choice]
+ else
+ return
+ new_owner.add_antag_datum(src)
+ log_admin("[key_name(usr)] made [key_name(new_owner.current)] [name] on [choice]!")
+ message_admins("[key_name_admin(usr)] made [key_name_admin(new_owner.current)] [name] on [choice] !")
+
+/datum/antagonist/abductor/get_admin_commands()
+ . = ..()
+ .["Equip"] = CALLBACK(src,.proc/admin_equip)
+
+/datum/antagonist/abductor/proc/admin_equip(mob/admin)
+ if(!ishuman(owner.current))
+ to_chat(admin, "This only works on humans!")
+ return
+ var/mob/living/carbon/human/H = owner.current
+ var/gear = alert(admin,"Agent or Scientist Gear","Gear","Agent","Scientist")
+ if(gear)
+ if(gear=="Agent")
+ H.equipOutfit(/datum/outfit/abductor/agent)
+ else
+ H.equipOutfit(/datum/outfit/abductor/scientist)
/datum/team/abductor_team
member_name = "abductor"
var/team_number
var/list/datum/mind/abductees = list()
+ var/static/team_count = 1
+
+/datum/team/abductor_team/New()
+ ..()
+ team_number = team_count++
+ name = "Mothership [pick(GLOB.possible_changeling_IDs)]" //TODO Ensure unique and actual alieny names
+ add_objective(new/datum/objective/experiment)
/datum/team/abductor_team/is_solo()
return FALSE
@@ -105,10 +152,10 @@
return result.Join("
")
-
/datum/antagonist/abductee
name = "Abductee"
roundend_category = "abductees"
+ antagpanel_category = "Abductee"
/datum/antagonist/abductee/on_gain()
give_objective()
diff --git a/code/datums/antagonists/antag_datum.dm b/code/datums/antagonists/antag_datum.dm
index 9b5dbb6d7584..6140dc67978d 100644
--- a/code/datums/antagonists/antag_datum.dm
+++ b/code/datums/antagonists/antag_datum.dm
@@ -12,12 +12,15 @@ GLOBAL_LIST_EMPTY(antagonists)
var/job_rank
var/replace_banned = TRUE //Should replace jobbaned player with ghosts if granted.
var/list/objectives = list()
+ var/antag_memory = ""//These will be removed with antag datum
+
+ //Antag panel properties
+ var/show_in_antagpanel = TRUE //This will hide adding this antag type in antag panel, use only for internal subtypes that shouldn't be added directly but still show if possessed by mind
+ var/antagpanel_category = "Uncategorized" //Antagpanel will display these together, REQUIRED
-/datum/antagonist/New(datum/mind/new_owner)
+/datum/antagonist/New()
GLOB.antagonists += src
typecache_datum_blacklist = typecacheof(typecache_datum_blacklist)
- if(new_owner)
- owner = new_owner
/datum/antagonist/Destroy()
GLOB.antagonists -= src
@@ -36,6 +39,11 @@ GLOBAL_LIST_EMPTY(antagonists)
if(is_type_in_typecache(src, A.typecache_datum_blacklist))
return FALSE
+//This will be called in add_antag_datum before owner assignment.
+//Should return antag datum without owner.
+/datum/antagonist/proc/specialization(datum/mind/new_owner)
+ return src
+
/datum/antagonist/proc/on_body_transfer(mob/living/old_body, mob/living/new_body)
remove_innate_effects(old_body)
apply_innate_effects(new_body)
@@ -131,18 +139,82 @@ GLOBAL_LIST_EMPTY(antagonists)
/datum/antagonist/proc/roundend_report_footer()
return
+
+//ADMIN TOOLS
+
+//Called when using admin tools to give antag status
+/datum/antagonist/proc/admin_add(datum/mind/new_owner,mob/admin)
+ message_admins("[key_name_admin(admin)] made [new_owner.current] into [name].")
+ log_admin("[key_name(admin)] made [new_owner.current] into [name].")
+ new_owner.add_antag_datum(src)
+
+//Called when removing antagonist using admin tools
+/datum/antagonist/proc/admin_remove(mob/user)
+ if(!user)
+ return
+ message_admins("[key_name_admin(user)] has removed [name] antagonist status from [owner.current].")
+ log_admin("[key_name(user)] has removed [name] antagonist status from [owner.current].")
+ on_removal()
+
+//gamemode/proc/is_mode_antag(antagonist/A) => TRUE/FALSE
+
+//Additional data to display in antagonist panel section
+//nuke disk code, genome count, etc
+/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()
+
+/datum/antagonist/Topic(href,href_list)
+ if(!check_rights(R_ADMIN))
+ return
+ //Antag memory edit
+ if (href_list["memory_edit"])
+ edit_memory(usr)
+ owner.traitor_panel()
+ return
+
+ //Some commands might delete/modify this datum clearing or changing owner
+ var/datum/mind/persistent_owner = owner
+
+ var/commands = get_admin_commands()
+ for(var/admin_command in commands)
+ if(href_list["command"] == admin_command)
+ var/datum/callback/C = commands[admin_command]
+ C.Invoke(usr)
+ persistent_owner.traitor_panel()
+ return
+
+/datum/antagonist/proc/edit_memory(mob/user)
+ var/new_memo = copytext(trim(input(user,"Write new memory", "Memory", antag_memory) as null|message),1,MAX_MESSAGE_LEN)
+ if (isnull(new_memo))
+ return
+ antag_memory = new_memo
+
//Should probably be on ticker or job ss ?
/proc/get_antagonists(antag_type,specific = FALSE)
. = list()
for(var/datum/antagonist/A in GLOB.antagonists)
- if(!specific && istype(A,antag_type) || specific && A.type == antag_type)
+ if(!A.owner)
+ continue
+ if(!antag_type || !specific && istype(A,antag_type) || specific && A.type == antag_type)
. += A.owner
-
-
//This datum will autofill the name with special_role
//Used as placeholder for minor antagonists, please create proper datums for these
/datum/antagonist/auto_custom
+ show_in_antagpanel = FALSE
+ antagpanel_category = "Other"
/datum/antagonist/auto_custom/on_gain()
..()
@@ -156,5 +228,20 @@ GLOBAL_LIST_EMPTY(antagonists)
already_registered_objectives |= A.objectives
objectives = owner.objectives - already_registered_objectives
+/datum/antagonist/auto_custom/antag_listing_name()
+ return ..() + "([name])"
+
//This one is created by admin tools for custom objectives
-/datum/antagonist/custom
\ No newline at end of file
+/datum/antagonist/custom
+ antagpanel_category = "Custom"
+
+/datum/antagonist/custom/admin_add(datum/mind/new_owner,mob/admin)
+ var/custom_name = stripped_input(admin, "Custom antagonist name:", "Custom antag", "Antagonist")
+ if(custom_name)
+ name = custom_name
+ else
+ return
+ ..()
+
+/datum/antagonist/custom/antag_listing_name()
+ return ..() + "([name])"
\ No newline at end of file
diff --git a/code/datums/antagonists/blob.dm b/code/datums/antagonists/blob.dm
index 5689e6a5679e..964bc9931160 100644
--- a/code/datums/antagonists/blob.dm
+++ b/code/datums/antagonists/blob.dm
@@ -1,6 +1,7 @@
/datum/antagonist/blob
name = "Blob"
roundend_category = "blobs"
+ antagpanel_category = "Blob"
job_rank = ROLE_BLOB
var/datum/action/innate/blobpop/pop_action
@@ -56,4 +57,11 @@
var/mob/camera/blob/B = new /mob/camera/blob(get_turf(old_body), blobtag.starting_points_human_blob)
owner.mind.transfer_to(B)
old_body.gib()
- B.place_blob_core(blobtag.point_rate_human_blob, pop_override = TRUE)
\ No newline at end of file
+ B.place_blob_core(blobtag.point_rate_human_blob, pop_override = TRUE)
+
+/datum/antagonist/blob/antag_listing_status()
+ . = ..()
+ if(owner && owner.current)
+ var/mob/camera/blob/B = owner.current
+ if(istype(B))
+ . += "(Progress: [B.blobs_legit.len]/[B.blobwincount])"
\ No newline at end of file
diff --git a/code/datums/antagonists/brother.dm b/code/datums/antagonists/brother.dm
index b06c75e4fa34..e4c43ef78858 100644
--- a/code/datums/antagonists/brother.dm
+++ b/code/datums/antagonists/brother.dm
@@ -1,12 +1,10 @@
/datum/antagonist/brother
name = "Brother"
+ antagpanel_category = "Brother"
job_rank = ROLE_BROTHER
var/special_role = "blood brother"
var/datum/team/brother_team/team
-/datum/antagonist/brother/New(datum/mind/new_owner)
- return ..()
-
/datum/antagonist/brother/create_team(datum/team/brother_team/new_team)
if(!new_team)
return
@@ -36,7 +34,7 @@
if(!owner.current || !team || !team.meeting_area)
return
to_chat(owner.current, "Your designated meeting area: [team.meeting_area]")
- owner.store_memory("Meeting Area: [team.meeting_area]")
+ antag_memory += "Meeting Area: [team.meeting_area]
"
/datum/antagonist/brother/greet()
var/brother_text = ""
@@ -56,15 +54,42 @@
/datum/antagonist/brother/proc/finalize_brother()
SSticker.mode.update_brother_icons_added(owner)
+/datum/antagonist/brother/admin_add(datum/mind/new_owner,mob/admin)
+ //show list of possible brothers
+ var/list/candidates = list()
+ for(var/mob/living/L in GLOB.alive_mob_list)
+ if(!L.mind || L.mind == new_owner || !can_be_owned(L.mind))
+ continue
+ candidates[L.mind.name] = L.mind
+
+ var/choice = input(admin,"Choose the blood brother.", "Brother") as null|anything in candidates
+ if(!choice)
+ return
+ var/datum/mind/bro = candidates[choice]
+ var/datum/team/brother_team/T = new
+ T.add_member(new_owner)
+ T.add_member(bro)
+ T.pick_meeting_area()
+ T.forge_brother_objectives()
+ new_owner.add_antag_datum(ANTAG_DATUM_BROTHER,T)
+ bro.add_antag_datum(ANTAG_DATUM_BROTHER, T)
+ T.update_name()
+ message_admins("[key_name_admin(admin)] made [new_owner.current] and [bro.current] into blood brothers.")
+ log_admin("[key_name(admin)] made [new_owner.current] and [bro.current] into blood brothers.")
/datum/team/brother_team
name = "brotherhood"
member_name = "blood brother"
var/meeting_area
+ var/static/meeting_areas = list("The Bar", "Dorms", "Escape Dock", "Arrivals", "Holodeck", "Primary Tool Storage", "Recreation Area", "Chapel", "Library")
/datum/team/brother_team/is_solo()
return FALSE
+/datum/team/brother_team/proc/pick_meeting_area()
+ meeting_area = pick(meeting_areas)
+ meeting_areas -= meeting_area
+
/datum/team/brother_team/proc/update_name()
var/list/last_names = list()
for(var/datum/mind/M in members)
@@ -122,4 +147,7 @@
else
add_objective(new/datum/objective/assassinate, TRUE)
else
- add_objective(new/datum/objective/steal, TRUE)
\ No newline at end of file
+ add_objective(new/datum/objective/steal, TRUE)
+
+/datum/team/brother_team/antag_listing_name()
+ return "[name] blood brothers"
\ No newline at end of file
diff --git a/code/datums/antagonists/changeling.dm b/code/datums/antagonists/changeling.dm
index 53d0c37143ec..5d4e34cd9706 100644
--- a/code/datums/antagonists/changeling.dm
+++ b/code/datums/antagonists/changeling.dm
@@ -5,6 +5,7 @@
/datum/antagonist/changeling
name = "Changeling"
roundend_category = "changelings"
+ antagpanel_category = "Changeling"
job_rank = ROLE_CHANGELING
var/you_are_greet = TRUE
@@ -40,11 +41,6 @@
var/static/list/all_powers = typecacheof(/obj/effect/proc_holder/changeling,TRUE)
-/datum/antagonist/changeling/New()
- . = ..()
- generate_name()
- create_actions()
-
/datum/antagonist/changeling/Destroy()
QDEL_NULL(cellular_emporium)
QDEL_NULL(emporium_action)
@@ -68,6 +64,8 @@
emporium_action = new(cellular_emporium)
/datum/antagonist/changeling/on_gain()
+ generate_name()
+ create_actions()
reset_powers()
create_initial_profile()
if(give_objectives)
@@ -340,6 +338,9 @@
owner.announce_objectives()
+/datum/antagonist/changeling/farewell()
+ to_chat(owner.current, "You grow weak and lose your powers! You are no longer a changeling and are stuck in your current form!")
+
/datum/antagonist/changeling/proc/forge_team_objectives()
if(GLOB.changeling_team_objective_type)
var/datum/objective/changeling_team_objective/team_objective = new GLOB.changeling_team_objective_type
@@ -436,6 +437,25 @@
hud.leave_hud(owner.current)
set_antag_hud(owner.current, null)
+/datum/antagonist/changeling/admin_add(datum/mind/new_owner,mob/admin)
+ . = ..()
+ to_chat(new_owner.current, "Our powers have awoken. A flash of memory returns to us...we are [changelingID], a changeling!")
+
+/datum/antagonist/changeling/get_admin_commands()
+ . = ..()
+ if(stored_profiles.len && (owner.current.real_name != first_prof.name))
+ .["Transform to initial appearance."] = CALLBACK(src,.proc/admin_restore_appearance)
+
+/datum/antagonist/changeling/proc/admin_restore_appearance(mob/admin)
+ if(!stored_profiles.len || !iscarbon(owner.current))
+ to_chat(admin, "Resetting DNA failed!")
+ else
+ var/mob/living/carbon/C = owner.current
+ first_prof.dna.transfer_identity(C, transfer_SE=1)
+ C.real_name = first_prof.name
+ C.updateappearance(mutcolor_update=1)
+ C.domutcheck()
+
// Profile
/datum/changelingprofile
@@ -509,4 +529,10 @@
else
parts += "The changeling has failed."
- return parts.Join("
")
\ No newline at end of file
+ return parts.Join("
")
+
+/datum/antagonist/changeling/antag_listing_name()
+ return ..() + "([changelingID])"
+
+/datum/antagonist/changeling/xenobio/antag_listing_name()
+ return ..() + "(Xenobio)"
\ No newline at end of file
diff --git a/code/datums/antagonists/clockcult.dm b/code/datums/antagonists/clockcult.dm
index 48f9b5342552..6b57e3d0dcaa 100644
--- a/code/datums/antagonists/clockcult.dm
+++ b/code/datums/antagonists/clockcult.dm
@@ -2,6 +2,7 @@
/datum/antagonist/clockcult
name = "Clock Cultist"
roundend_category = "clock cultists"
+ antagpanel_category = "Clockcult"
job_rank = ROLE_SERVANT_OF_RATVAR
var/datum/action/innate/hierophant/hierophant_network = new()
var/datum/team/clockcult/clock_team
@@ -9,6 +10,7 @@
/datum/antagonist/clockcult/silent
silent = TRUE
+ show_in_antagpanel = FALSE //internal
/datum/antagonist/clockcult/Destroy()
qdel(hierophant_network)
@@ -21,6 +23,8 @@
if(!new_team && make_team)
//TODO blah blah same as the others, allow multiple
for(var/datum/antagonist/clockcult/H in GLOB.antagonists)
+ if(!H.owner)
+ continue
if(H.clock_team)
clock_team = H.clock_team
return
@@ -33,28 +37,7 @@
/datum/antagonist/clockcult/can_be_owned(datum/mind/new_owner)
. = ..()
if(.)
- if(iscyborg(new_owner.current))
- var/mob/living/silicon/robot/R = new_owner.current
- if(R.deployed)
- var/mob/living/silicon/ai/AI = R.mainframe
- R.undeploy()
- to_chat(AI, "Anomaly Detected. Returned to core!") //The AI needs to be in its core to properly be converted
. = is_eligible_servant(new_owner.current)
- if(!silent && new_owner.current)
- if(.)
- to_chat(new_owner.current, "The world before you suddenly glows a brilliant yellow. [issilicon(new_owner.current) ? "You cannot compute this truth!" : \
- "Your mind is racing!"] You hear the whooshing steam and cl[pick("ank", "ink", "unk", "ang")]ing cogs of a billion billion machines, and all at once it comes to you.
\
- Ratvar, the Clockwork Justiciar, [GLOB.ratvar_awakens ? "has been freed from his eternal prison" : "lies in exile, derelict and forgotten in an unseen realm"].")
- flash_color(new_owner.current, flash_color = list("#BE8700", "#BE8700", "#BE8700", rgb(0,0,0)), flash_time = 50)
- else
- new_owner.current.visible_message("[new_owner.current] seems to resist an unseen force!", null, null, 7, new_owner.current)
- to_chat(new_owner.current, "The world before you suddenly glows a brilliant yellow. [issilicon(new_owner.current) ? "You cannot compute this truth!" : \
- "Your mind is racing!"] You hear the whooshing steam and cl[pick("ank", "ink", "unk", "ang")]ing cogs of a billion billion machines, and the sound \
- is a meaningless cacophony.
\
- You see an abomination of rusting parts[GLOB.ratvar_awakens ? ", and it is here.
It is too late" : \
- " in an endless grey void.
It cannot be allowed to escape"].")
- owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/clockcultalr.ogg', 40, TRUE, frequency = 100000, pressure_affected = FALSE)
- flash_color(new_owner.current, flash_color = list("#BE8700", "#BE8700", "#BE8700", rgb(0,0,0)), flash_time = 5)
/datum/antagonist/clockcult/greet()
if(!owner.current || silent)
@@ -85,7 +68,7 @@
to_chat(current, "You can communicate with other servants by using the Hierophant Network action button in the upper left.")
..()
to_chat(current, "This is Ratvar's will: [CLOCKCULT_OBJECTIVE]")
- owner.memory += "Ratvar's will: [CLOCKCULT_OBJECTIVE]
" //Memorize the objectives
+ antag_memory += "Ratvar's will: [CLOCKCULT_OBJECTIVE]
" //Memorize the objectives
/datum/antagonist/clockcult/apply_innate_effects(mob/living/mob_override)
. = ..()
@@ -178,13 +161,32 @@
owner.current.visible_message("[owner] seems to have remembered their true allegiance!", ignored_mob = owner.current)
to_chat(owner, "A cold, cold darkness flows through your mind, extinguishing the Justiciar's light and all of your memories as his servant.")
owner.current.log_message("Has renounced the cult of Ratvar!", INDIVIDUAL_ATTACK_LOG)
- owner.wipe_memory()
owner.special_role = null
if(iscyborg(owner.current))
to_chat(owner.current, "Despite your freedom from Ratvar's influence, you are still irreparably damaged and no longer possess certain functions such as AI linking.")
. = ..()
+/datum/antagonist/clockcult/admin_add(datum/mind/new_owner,mob/admin)
+ add_servant_of_ratvar(new_owner.current, TRUE)
+ message_admins("[key_name_admin(admin)] has made [new_owner.current] into a servant of Ratvar.")
+ log_admin("[key_name(admin)] has made [new_owner.current] into a servant of Ratvar.")
+
+/datum/antagonist/clockcult/admin_remove(mob/user)
+ remove_servant_of_ratvar(owner.current, TRUE)
+ message_admins("[key_name_admin(user)] has removed clockwork servant status from [owner.current].")
+ log_admin("[key_name(user)] has removed clockwork servant status from [owner.current].")
+
+/datum/antagonist/clockcult/get_admin_commands()
+ . = ..()
+ .["Give slab"] = CALLBACK(src,.proc/admin_give_slab)
+
+/datum/antagonist/clockcult/proc/admin_give_slab(mob/admin)
+ if(!SSticker.mode.equip_servant(owner.current))
+ to_chat(admin, "Failed to outfit [owner.current]!")
+ else
+ to_chat(admin, "Successfully gave [owner.current] servant equipment!")
+
/datum/team/clockcult
name = "Clockcult"
var/list/objective
diff --git a/code/datums/antagonists/cult.dm b/code/datums/antagonists/cult.dm
index cccc442c4d3d..6089e8d1f077 100644
--- a/code/datums/antagonists/cult.dm
+++ b/code/datums/antagonists/cult.dm
@@ -3,6 +3,7 @@
/datum/antagonist/cult
name = "Cultist"
roundend_category = "cultists"
+ antagpanel_category = "Cult"
var/datum/action/innate/cult/comm/communion = new
var/datum/action/innate/cult/mastervote/vote = new
job_rank = ROLE_CULTIST
@@ -18,6 +19,8 @@
if(!new_team)
//todo remove this and allow admin buttons to create more than one cult
for(var/datum/antagonist/cult/H in GLOB.antagonists)
+ if(!H.owner)
+ continue
if(H.cult_team)
cult_team = H.cult_team
return
@@ -127,7 +130,6 @@
/datum/antagonist/cult/on_removal()
remove_objectives()
- owner.wipe_memory()
SSticker.mode.cult -= owner
SSticker.mode.update_cult_icons_removed(owner)
if(!silent)
@@ -138,11 +140,36 @@
owner.current.client.images -= cult_team.blood_target_image
. = ..()
+/datum/antagonist/cult/admin_add(datum/mind/new_owner,mob/admin)
+ give_equipment = FALSE
+ new_owner.add_antag_datum(src)
+ message_admins("[key_name_admin(admin)] has cult'ed [new_owner.current].")
+ log_admin("[key_name(admin)] has cult'ed [new_owner.current].")
+
+/datum/antagonist/cult/admin_remove(mob/user)
+ message_admins("[key_name_admin(user)] has decult'ed [owner.current].")
+ log_admin("[key_name(user)] has decult'ed [owner.current].")
+ SSticker.mode.remove_cultist(owner,silent=TRUE) //disgusting
+
+/datum/antagonist/cult/get_admin_commands()
+ . = ..()
+ .["Tome"] = CALLBACK(src,.proc/admin_give_tome)
+ .["Amulet"] = CALLBACK(src,.proc/admin_give_amulet)
+
+/datum/antagonist/cult/proc/admin_give_tome(mob/admin)
+ if(equip_cultist(owner.current,1))
+ to_chat(admin, "Spawning tome failed!")
+
+/datum/antagonist/cult/proc/admin_give_amulet(mob/admin)
+ if (equip_cultist(owner.current))
+ to_chat(admin, "Spawning amulet failed!")
+
/datum/antagonist/cult/master
+ ignore_implant = TRUE
+ show_in_antagpanel = FALSE //Feel free to add this later
var/datum/action/innate/cult/master/finalreck/reckoning = new
var/datum/action/innate/cult/master/cultmark/bloodmark = new
var/datum/action/innate/cult/master/pulse/throwing = new
- ignore_implant = TRUE
/datum/antagonist/cult/master/Destroy()
QDEL_NULL(reckoning)
@@ -296,4 +323,7 @@
parts += ""
parts += printplayerlist(members)
- return "
[parts.Join("
")]
"
\ No newline at end of file
+ return "[parts.Join("
")]
"
+
+/datum/team/cult/is_gamemode_hero()
+ return SSticker.mode.name == "cult"
\ No newline at end of file
diff --git a/code/datums/antagonists/datum_traitor.dm b/code/datums/antagonists/datum_traitor.dm
index 420dae46503b..23cf95e6aea8 100644
--- a/code/datums/antagonists/datum_traitor.dm
+++ b/code/datums/antagonists/datum_traitor.dm
@@ -1,8 +1,9 @@
/datum/antagonist/traitor
name = "Traitor"
roundend_category = "traitors"
+ antagpanel_category = "Traitor"
job_rank = ROLE_TRAITOR
- var/should_specialise = FALSE //do we split into AI and human, set to true on inital assignment only
+ var/should_specialise = TRUE //do we split into AI and human, set to true on inital assignment only
var/ai_datum = ANTAG_DATUM_TRAITOR_AI
var/human_datum = ANTAG_DATUM_TRAITOR_HUMAN
var/special_role = "traitor"
@@ -10,23 +11,28 @@
var/give_objectives = TRUE
var/should_give_codewords = TRUE
+
+
/datum/antagonist/traitor/human
+ show_in_antagpanel = FALSE
+ should_specialise = FALSE
var/should_equip = TRUE
-/datum/antagonist/traitor/AI
-/datum/antagonist/traitor/proc/specialise()
- silent = TRUE
- if(owner.current && isAI(owner.current))
- owner.add_antag_datum(ai_datum)
- else
- owner.add_antag_datum(human_datum)
- on_removal()
+/datum/antagonist/traitor/AI
+ show_in_antagpanel = FALSE
+ should_specialise = FALSE
+
+/datum/antagonist/traitor/specialization(datum/mind/new_owner)
+ if(should_specialise)
+ if(new_owner.current && isAI(new_owner.current))
+ return new ai_datum()
+ else
+ return new human_datum()
+ else
+ return ..()
/datum/antagonist/traitor/on_gain()
- if(should_specialise)
- specialise()
- return
SSticker.mode.traitors += owner
owner.special_role = special_role
if(give_objectives)
@@ -49,8 +55,6 @@
traitor_mob.dna.add_mutation(CLOWNMUT)
/datum/antagonist/traitor/on_removal()
- if(should_specialise)
- return ..()//we never did any of this anyway
SSticker.mode.traitors -= owner
for(var/O in objectives)
owner.objectives -= O
@@ -79,6 +83,7 @@
/datum/antagonist/traitor/proc/forge_traitor_objectives()
return
+
/datum/antagonist/traitor/human/forge_traitor_objectives()
var/is_hijacker = prob(10)
var/martyr_chance = prob(20)
@@ -229,8 +234,8 @@
to_chat(traitor_mob, "Code Phrase: [GLOB.syndicate_code_phrase]")
to_chat(traitor_mob, "Code Response: [GLOB.syndicate_code_response]")
- traitor_mob.mind.store_memory("Code Phrase: [GLOB.syndicate_code_phrase]")
- traitor_mob.mind.store_memory("Code Response: [GLOB.syndicate_code_response]")
+ antag_memory += "Code Phrase: [GLOB.syndicate_code_phrase]
"
+ antag_memory += "Code Response: [GLOB.syndicate_code_response]
"
to_chat(traitor_mob, "Use the code words in the order provided, during regular conversation, to identify other agents. Proceed with caution, however, as everyone is a potential foe.")
@@ -249,7 +254,7 @@
return
/datum/antagonist/traitor/human/equip(var/silent = FALSE)
- owner.equip_traitor(employer, silent)
+ owner.equip_traitor(employer, silent, src)
/datum/antagonist/traitor/human/proc/assign_exchange_role()
//set faction
@@ -339,4 +344,7 @@
/datum/antagonist/traitor/roundend_report_footer()
return "
The code phrases were: [GLOB.syndicate_code_phrase]
\
- The code responses were: [GLOB.syndicate_code_response]
"
\ No newline at end of file
+ The code responses were: [GLOB.syndicate_code_response]
"
+
+/datum/antagonist/traitor/is_gamemode_hero()
+ return SSticker.mode.name == "traitor"
\ No newline at end of file
diff --git a/code/datums/antagonists/devil.dm b/code/datums/antagonists/devil.dm
index 97e0d8c18aa7..858b2d1ef11a 100644
--- a/code/datums/antagonists/devil.dm
+++ b/code/datums/antagonists/devil.dm
@@ -87,6 +87,7 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
/datum/antagonist/devil
name = "Devil"
roundend_category = "devils"
+ antagpanel_category = "Devil"
job_rank = ROLE_DEVIL
//Don't delete upon mind destruction, otherwise soul re-selling will break.
delete_on_mind_deletion = FALSE
@@ -111,17 +112,35 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
/obj/effect/proc_holder/spell/targeted/summon_dancefloor))
var/ascendable = FALSE
+/datum/antagonist/devil/can_be_owned(datum/mind/new_owner)
+ . = ..()
+ return . && (ishuman(new_owner.current) || iscyborg(new_owner.current))
-/datum/antagonist/devil/New()
- ..()
- truename = randomDevilName()
- ban = randomdevilban()
- bane = randomdevilbane()
- obligation = randomdevilobligation()
- banish = randomdevilbanish()
- GLOB.allDevils[lowertext(truename)] = src
+/datum/antagonist/devil/get_admin_commands()
+ . = ..()
+ .["Toggle ascendable"] = CALLBACK(src,.proc/admin_toggle_ascendable)
+/datum/antagonist/devil/proc/admin_toggle_ascendable(mob/admin)
+ ascendable = !ascendable
+ message_admins("[key_name_admin(admin)] set [owner.current] devil ascendable to [ascendable]")
+ log_admin("[key_name_admin(admin)] set [owner.current] devil ascendable to [ascendable])")
+
+/datum/antagonist/devil/admin_add(datum/mind/new_owner,mob/admin)
+ switch(alert(admin,"Should the devil be able to ascend",,"Yes","No","Cancel"))
+ if("Yes")
+ ascendable = TRUE
+ if("No")
+ ascendable = FALSE
+ else
+ return
+ new_owner.add_antag_datum(src)
+ message_admins("[key_name_admin(admin)] has devil'ed [new_owner.current]. [ascendable ? "(Ascendable)":""]")
+ log_admin("[key_name(admin)] has devil'ed [new_owner.current]. [ascendable ? "(Ascendable)":""]")
+
+/datum/antagonist/devil/antag_listing_name()
+ return ..() + "([truename])"
+
/proc/devilInfo(name)
if(GLOB.allDevils[lowertext(name)])
return GLOB.allDevils[lowertext(name)]
@@ -480,7 +499,14 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
.=..()
/datum/antagonist/devil/on_gain()
- owner.store_memory("Your devilic true name is [truename]
[GLOB.lawlorify[LAW][ban]]
You may not use violence to coerce someone into selling their soul.
You may not directly and knowingly physically harm a devil, other than yourself.
[GLOB.lawlorify[LAW][bane]]
[GLOB.lawlorify[LAW][obligation]]
[GLOB.lawlorify[LAW][banish]]
")
+ truename = randomDevilName()
+ ban = randomdevilban()
+ bane = randomdevilbane()
+ obligation = randomdevilobligation()
+ banish = randomdevilbanish()
+ GLOB.allDevils[lowertext(truename)] = src
+
+ antag_memory += "Your devilic true name is [truename]
[GLOB.lawlorify[LAW][ban]]
You may not use violence to coerce someone into selling their soul.
You may not directly and knowingly physically harm a devil, other than yourself.
[GLOB.lawlorify[LAW][bane]]
[GLOB.lawlorify[LAW][obligation]]
[GLOB.lawlorify[LAW][banish]]
"
if(issilicon(owner.current))
var/mob/living/silicon/robot_devil = owner.current
var/laws = list("You may not use violence to coerce someone into selling their soul.", "You may not directly and knowingly physically harm a devil, other than yourself.", GLOB.lawlorify[LAW][ban], GLOB.lawlorify[LAW][obligation], "Accomplish your objectives at all costs.")
diff --git a/code/datums/antagonists/internal_affairs.dm b/code/datums/antagonists/internal_affairs.dm
index b06d8ea068d8..e06d8983e363 100644
--- a/code/datums/antagonists/internal_affairs.dm
+++ b/code/datums/antagonists/internal_affairs.dm
@@ -5,32 +5,31 @@
#define TRAITOR_AGENT_ROLE "Syndicate External Affairs Agent"
/datum/antagonist/traitor/internal_affairs
+ name = "Internal Affairs Agent"
human_datum = ANTAG_DATUM_IAA_HUMAN
ai_datum = ANTAG_DATUM_IAA_AI
-
-
+ antagpanel_category = "IAA"
/datum/antagonist/traitor/AI/internal_affairs
name = "Internal Affairs Agent"
employer = "Nanotrasen"
special_role = "internal affairs agent"
+ antagpanel_category = "IAA"
var/syndicate = FALSE
var/last_man_standing = FALSE
var/list/datum/mind/targets_stolen
-
-/datum/antagonist/traitor/AI/internal_affairs/custom
- silent = TRUE
- should_give_codewords = FALSE
- give_objectives = FALSE
+
/datum/antagonist/traitor/human/internal_affairs
name = "Internal Affairs Agent"
employer = "Nanotrasen"
special_role = "internal affairs agent"
+ antagpanel_category = "IAA"
var/syndicate = FALSE
var/last_man_standing = FALSE
var/list/datum/mind/targets_stolen
+
/datum/antagonist/traitor/human/internal_affairs/proc/give_pinpointer()
if(owner && owner.current)
owner.current.apply_status_effect(/datum/status_effect/agent_pinpointer)
@@ -292,6 +291,7 @@
/datum/antagonist/traitor/AI/internal_affairs/greet()
greet_iaa()
+
/datum/antagonist/traitor/human/internal_affairs/greet()
greet_iaa()
diff --git a/code/datums/antagonists/monkey.dm b/code/datums/antagonists/monkey.dm
index d2c5d5e7620b..4d218b612cbe 100644
--- a/code/datums/antagonists/monkey.dm
+++ b/code/datums/antagonists/monkey.dm
@@ -7,7 +7,15 @@
name = "Monkey"
job_rank = ROLE_MONKEY
roundend_category = "monkeys"
+ antagpanel_category = "Monkey"
var/datum/team/monkey/monkey_team
+ var/monkey_only = TRUE
+
+/datum/antagonist/monkey/can_be_owned(datum/mind/new_owner)
+ return ..() && (!monkey_only || ismonkey(new_owner.current))
+
+/datum/antagonist/monkey/get_team()
+ return monkey_team
/datum/antagonist/monkey/on_gain()
. = ..()
@@ -29,13 +37,15 @@
SEND_SOUND(owner.current, sound('sound/ambience/antag/monkey.ogg'))
/datum/antagonist/monkey/on_removal()
- . = ..()
owner.special_role = null
SSticker.mode.ape_infectees -= owner
- var/datum/disease/D = (/datum/disease/transformation/jungle_fever in owner.current.viruses)
+ var/datum/disease/transformation/jungle_fever/D = locate() in owner.current.viruses
if(D)
- D.cure()
+ D.remove_virus()
+ qdel(D)
+
+ . = ..()
/datum/antagonist/monkey/create_team(datum/team/monkey/new_team)
if(!new_team)
@@ -50,15 +60,45 @@
stack_trace("Wrong team type passed to [type] initialization.")
monkey_team = new_team
-/datum/antagonist/monkey/get_team()
- return monkey_team
-
/datum/antagonist/monkey/proc/forge_objectives()
objectives |= monkey_team.objectives
owner.objectives |= objectives
+/datum/antagonist/monkey/admin_remove(mob/admin)
+ var/mob/living/carbon/monkey/M = owner.current
+ if(istype(M))
+ switch(alert(admin, "Humanize?", "Humanize", "Yes", "No"))
+ if("Yes")
+ if(admin == M)
+ admin = M.humanize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPORGANS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_DEFAULTMSG)
+ else
+ M.humanize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPORGANS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_DEFAULTMSG)
+ if("No")
+ //nothing
+ else
+ return
+ . = ..()
+
/datum/antagonist/monkey/leader
name = "Monkey Leader"
+ monkey_only = FALSE
+
+/datum/antagonist/monkey/leader/admin_add(datum/mind/new_owner,mob/admin)
+ var/mob/living/carbon/human/H = new_owner.current
+ if(istype(H))
+ switch(alert(admin, "Monkeyize?", "Monkeyize", "Yes", "No"))
+ if("Yes")
+ if(admin == H)
+ admin = H.monkeyize()
+ else
+ H.monkeyize()
+ if("No")
+ //nothing
+ else
+ return
+ new_owner.add_antag_datum(src)
+ log_admin("[key_name(admin)] made [key_name(new_owner.current)] a monkey leader!")
+ message_admins("[key_name_admin(admin)] made [key_name_admin(new_owner.current)] a monkey leader!")
/datum/antagonist/monkey/leader/on_gain()
. = ..()
@@ -68,11 +108,12 @@
owner.special_role = "Monkey Leader"
/datum/antagonist/monkey/leader/on_removal()
- . = ..()
SSticker.mode.ape_leaders -= owner
var/obj/item/organ/heart/H = new
H.Insert(owner.current, drop_if_replaced = FALSE) //replace freedom heart with normal heart
+ . = ..()
+
/datum/antagonist/monkey/leader/greet()
to_chat(owner, "You are the Jungle Fever patient zero!!")
to_chat(owner, "You have been planted onto this station by the Animal Rights Consortium.")
diff --git a/code/datums/antagonists/ninja.dm b/code/datums/antagonists/ninja.dm
index 8201cd879d16..3d46d3ef0538 100644
--- a/code/datums/antagonists/ninja.dm
+++ b/code/datums/antagonists/ninja.dm
@@ -1,31 +1,27 @@
/datum/antagonist/ninja
name = "Ninja"
+ antagpanel_category = "Ninja"
job_rank = ROLE_NINJA
- var/helping_station = 0
+ var/helping_station = FALSE
var/give_objectives = TRUE
+ var/give_equipment = TRUE
-/datum/antagonist/ninja/friendly
- helping_station = 1
-/datum/antagonist/ninja/friendly/noobjective
- give_objectives = FALSE
+/datum/antagonist/ninja/apply_innate_effects(mob/living/mob_override)
+ var/mob/living/M = mob_override || owner.current
+ update_ninja_icons_added(M)
-/datum/antagonist/ninja/New(datum/mind/new_owner)
- if(new_owner && !ishuman(new_owner.current))//It's fine if we aren't passed a mind, but if we are, they have to be human.
- throw EXCEPTION("Only humans and/or humanoids may be ninja'ed")
- ..(new_owner)
-
-/datum/antagonist/ninja/randomAllegiance/New(datum/mind/new_owner)
- ..(new_owner)
- helping_station = rand(0,1)
+/datum/antagonist/ninja/remove_innate_effects(mob/living/mob_override)
+ var/mob/living/M = mob_override || owner.current
+ update_ninja_icons_removed(M)
/datum/antagonist/ninja/proc/equip_space_ninja(mob/living/carbon/human/H = owner.current)
return H.equipOutfit(/datum/outfit/ninja)
/datum/antagonist/ninja/proc/addMemories()
- owner.store_memory("I am an elite mercenary assassin of the mighty Spider Clan. A SPACE NINJA!")
- owner.store_memory("Surprise is my weapon. Shadows are my armor. Without them, I am nothing. (//initialize your suit by right clicking on it, to use abilities like stealth)!")
- owner.store_memory("Officially, [helping_station?"Nanotrasen":"The Syndicate"] are my employer.")
+ antag_memory += "I am an elite mercenary assassin of the mighty Spider Clan. A SPACE NINJA!
"
+ antag_memory += "Surprise is my weapon. Shadows are my armor. Without them, I am nothing. (//initialize your suit by right clicking on it, to use abilities like stealth)!
"
+ antag_memory += "Officially, [helping_station?"Nanotrasen":"The Syndicate"] are my employer.
"
/datum/antagonist/ninja/proc/addObjectives(quantity = 6)
var/list/possible_targets = list()
@@ -103,11 +99,6 @@
datum.on_removal()
return TRUE
-/proc/add_ninja(mob/living/carbon/human/H, type = ANTAG_DATUM_NINJA_RANDOM)
- if(!H || !H.mind)
- return FALSE
- return H.mind.add_antag_datum(type)
-
/proc/is_ninja(mob/living/M)
return M && M.mind && M.mind.has_antag_datum(ANTAG_DATUM_NINJA)
@@ -123,3 +114,42 @@
if(give_objectives)
addObjectives()
addMemories()
+ if(give_equipment)
+ equip_space_ninja(owner.current)
+ . = ..()
+
+/datum/antagonist/ninja/admin_add(datum/mind/new_owner,mob/admin)
+ var/adj
+ switch(input("What kind of ninja?", "Ninja") as null|anything in list("Random","Syndicate","Nanotrasen","No objectives"))
+ if("Random")
+ helping_station = pick(TRUE,FALSE)
+ adj = ""
+ if("Syndicate")
+ helping_station = FALSE
+ adj = "syndie"
+ if("Nanotrasen")
+ helping_station = TRUE
+ adj = "friendly"
+ if("No objectives")
+ give_objectives = FALSE
+ adj = "objectiveless"
+ else
+ return
+ new_owner.assigned_role = "Space Ninja"
+ new_owner.special_role = "Space Ninja"
+ new_owner.add_antag_datum(src)
+ message_admins("[key_name_admin(admin)] has [adj] ninja'ed [new_owner.current].")
+ log_admin("[key_name(admin)] has [adj] ninja'ed [new_owner.current].")
+
+/datum/antagonist/ninja/antag_listing_name()
+ return ..() + "(Ninja)"
+
+/datum/antagonist/ninja/proc/update_ninja_icons_added(var/mob/living/carbon/human/ninja)
+ var/datum/atom_hud/antag/ninjahud = GLOB.huds[ANTAG_HUD_NINJA]
+ ninjahud.join_hud(ninja)
+ set_antag_hud(ninja, "ninja")
+
+/datum/antagonist/ninja/proc/update_ninja_icons_removed(var/mob/living/carbon/human/ninja)
+ var/datum/atom_hud/antag/ninjahud = GLOB.huds[ANTAG_HUD_NINJA]
+ ninjahud.leave_hud(ninja)
+ set_antag_hud(ninja, null)
\ No newline at end of file
diff --git a/code/datums/antagonists/nukeop.dm b/code/datums/antagonists/nukeop.dm
index 99d273ac977d..5fac18c6f702 100644
--- a/code/datums/antagonists/nukeop.dm
+++ b/code/datums/antagonists/nukeop.dm
@@ -11,6 +11,7 @@
/datum/antagonist/nukeop
name = "Nuclear Operative"
roundend_category = "syndicate operatives" //just in case
+ antagpanel_category = "NukeOp"
job_rank = ROLE_OPERATIVE
var/datum/team/nuclear/nuke_team
var/always_new_team = FALSE //If not assigned a team by default ops will try to join existing ones, set this to TRUE to always create new team.
@@ -85,7 +86,7 @@
/datum/antagonist/nukeop/proc/memorize_code()
if(nuke_team && nuke_team.tracked_nuke && nuke_team.memorized_code)
- owner.store_memory("[nuke_team.tracked_nuke] Code: [nuke_team.memorized_code]", 0, 0)
+ antag_memory += "[nuke_team.tracked_nuke] Code: [nuke_team.memorized_code]
"
to_chat(owner, "The nuclear authorization code is: [nuke_team.memorized_code]")
else
to_chat(owner, "Unfortunately the syndicate was unable to provide you with nuclear authorization code.")
@@ -107,6 +108,8 @@
if(!new_team)
if(!always_new_team)
for(var/datum/antagonist/nukeop/N in GLOB.antagonists)
+ if(!N.owner)
+ continue
if(N.nuke_team)
nuke_team = N.nuke_team
return
@@ -118,6 +121,32 @@
stack_trace("Wrong team type passed to [type] initialization.")
nuke_team = new_team
+/datum/antagonist/nukeop/admin_add(datum/mind/new_owner,mob/admin)
+ new_owner.assigned_role = "Syndicate"
+ new_owner.add_antag_datum(src)
+ message_admins("[key_name_admin(admin)] has nuke op'ed [new_owner.current].")
+ log_admin("[key_name(admin)] has nuke op'ed [new_owner.current].")
+
+/datum/antagonist/nukeop/get_admin_commands()
+ . = ..()
+ .["Send to base"] = CALLBACK(src,.proc/admin_send_to_base)
+ .["Tell code"] = CALLBACK(src,.proc/admin_tell_code)
+
+/datum/antagonist/nukeop/proc/admin_send_to_base(mob/admin)
+ owner.current.forceMove(pick(GLOB.nukeop_start))
+
+/datum/antagonist/nukeop/proc/admin_tell_code(mob/admin)
+ var/code
+ for (var/obj/machinery/nuclearbomb/bombue in GLOB.machines)
+ if (length(bombue.r_code) <= 5 && bombue.r_code != initial(bombue.r_code))
+ code = bombue.r_code
+ break
+ if (code)
+ antag_memory += "Syndicate Nuclear Bomb Code: [code]
"
+ to_chat(owner.current, "The nuclear authorization code is: [code]")
+ else
+ to_chat(admin, "No valid nuke found!")
+
/datum/antagonist/nukeop/leader
name = "Nuclear Operative Leader"
nukeop_outfit = /datum/outfit/syndicate/leader
@@ -201,6 +230,10 @@
stack_trace("Station self destruct ot found during lone op team creation.")
nuke_team.memorized_code = null
+/datum/antagonist/nukeop/reinforcement
+ send_to_spawnpoint = FALSE
+ nukeop_outfit = /datum/outfit/syndicate/no_crystals
+
/datum/team/nuclear
var/syndicate_name
var/obj/machinery/nuclearbomb/tracked_nuke
@@ -316,3 +349,31 @@
parts += text
return "[parts.Join("
")]
"
+
+/datum/team/nuclear/antag_listing_name()
+ if(syndicate_name)
+ return "[syndicate_name] Syndicates"
+ else
+ return "Syndicates"
+
+/datum/team/nuclear/antag_listing_entry()
+ var/disk_report = "Nuclear Disk(s)
"
+ disk_report += ""
+ for(var/obj/item/disk/nuclear/N in GLOB.poi_list)
+ disk_report += "| [N.name], "
+ var/atom/disk_loc = N.loc
+ while(!isturf(disk_loc))
+ if(ismob(disk_loc))
+ var/mob/M = disk_loc
+ disk_report += "carried by [M.real_name] "
+ if(isobj(disk_loc))
+ var/obj/O = disk_loc
+ disk_report += "in \a [O.name] "
+ disk_loc = disk_loc.loc
+ disk_report += "in [disk_loc.loc] at ([disk_loc.x], [disk_loc.y], [disk_loc.z]) | FLW |
"
+ disk_report += "
"
+ var/common_part = ..()
+ return common_part + disk_report
+
+/datum/team/nuclear/is_gamemode_hero()
+ return SSticker.mode.name == "nuclear emergency"
\ No newline at end of file
diff --git a/code/datums/antagonists/pirate.dm b/code/datums/antagonists/pirate.dm
index 9bf20a4bf58b..cdd871ff352d 100644
--- a/code/datums/antagonists/pirate.dm
+++ b/code/datums/antagonists/pirate.dm
@@ -2,6 +2,7 @@
name = "Space Pirate"
job_rank = ROLE_TRAITOR
roundend_category = "space pirates"
+ antagpanel_category = "Pirate"
var/datum/team/pirate/crew
/datum/antagonist/pirate/greet()
@@ -15,6 +16,8 @@
/datum/antagonist/pirate/create_team(datum/team/pirate/new_team)
if(!new_team)
for(var/datum/antagonist/pirate/P in GLOB.antagonists)
+ if(!P.owner)
+ continue
if(P.crew)
crew = P.crew
return
diff --git a/code/datums/antagonists/revolution.dm b/code/datums/antagonists/revolution.dm
index 3209b9221c71..b0637f236117 100644
--- a/code/datums/antagonists/revolution.dm
+++ b/code/datums/antagonists/revolution.dm
@@ -4,16 +4,20 @@
/datum/antagonist/rev
name = "Revolutionary"
roundend_category = "revolutionaries" // if by some miracle revolutionaries without revolution happen
+ antagpanel_category = "Revolution"
job_rank = ROLE_REV
var/hud_type = "rev"
var/datum/team/revolution/rev_team
/datum/antagonist/rev/can_be_owned(datum/mind/new_owner)
. = ..()
- if(new_owner.assigned_role in GLOB.command_positions)
- return FALSE
- if(new_owner.unconvertable)
- return FALSE
+ if(.)
+ if(new_owner.assigned_role in GLOB.command_positions)
+ return FALSE
+ if(new_owner.unconvertable)
+ return FALSE
+ if(new_owner.current && new_owner.current.isloyal())
+ return FALSE
/datum/antagonist/rev/apply_innate_effects(mob/living/mob_override)
var/mob/living/M = mob_override || owner.current
@@ -26,9 +30,6 @@
/datum/antagonist/rev/proc/equip_rev()
return
-/datum/antagonist/rev/New()
- . = ..()
-
/datum/antagonist/rev/on_gain()
. = ..()
create_objectives()
@@ -47,6 +48,8 @@
if(!new_team)
//For now only one revolution at a time
for(var/datum/antagonist/rev/head/H in GLOB.antagonists)
+ if(!H.owner)
+ continue
if(H.rev_team)
rev_team = H.rev_team
return
@@ -73,12 +76,73 @@
var/datum/mind/old_owner = owner
silent = TRUE
owner.remove_antag_datum(/datum/antagonist/rev)
- var/datum/antagonist/rev/head/new_revhead = new(old_owner)
+ var/datum/antagonist/rev/head/new_revhead = new()
new_revhead.silent = TRUE
old_owner.add_antag_datum(new_revhead,old_team)
new_revhead.silent = FALSE
to_chat(old_owner, "You have proved your devotion to revolution! You are a head revolutionary now!")
+/datum/antagonist/rev/get_admin_commands()
+ . = ..()
+ .["Promote"] = CALLBACK(src,.proc/admin_promote)
+
+/datum/antagonist/rev/proc/admin_promote(mob/admin)
+ var/datum/mind/O = owner
+ promote()
+ message_admins("[key_name_admin(admin)] has head-rev'ed [O].")
+ log_admin("[key_name(admin)] has head-rev'ed [O].")
+
+/datum/antagonist/rev/head/admin_add(datum/mind/new_owner,mob/admin)
+ give_flash = TRUE
+ give_hud = TRUE
+ remove_clumsy = TRUE
+ new_owner.add_antag_datum(src)
+ message_admins("[key_name_admin(admin)] has head-rev'ed [new_owner.current].")
+ log_admin("[key_name(admin)] has head-rev'ed [new_owner.current].")
+ to_chat(new_owner.current, "You are a member of the revolutionaries' leadership now!")
+
+/datum/antagonist/rev/head/get_admin_commands()
+ . = ..()
+ . -= "Promote"
+ .["Take flash"] = CALLBACK(src,.proc/admin_take_flash)
+ .["Give flash"] = CALLBACK(src,.proc/admin_give_flash)
+ .["Repair flash"] = CALLBACK(src,.proc/admin_repair_flash)
+ .["Demote"] = CALLBACK(src,.proc/admin_demote)
+
+/datum/antagonist/rev/head/proc/admin_take_flash(mob/admin)
+ var/list/L = owner.current.get_contents()
+ var/obj/item/device/assembly/flash/flash = locate() in L
+ if (!flash)
+ to_chat(admin, "Deleting flash failed!")
+ return
+ qdel(flash)
+
+/datum/antagonist/rev/head/proc/admin_give_flash(mob/admin)
+ //This is probably overkill but making these impact state annoys me
+ var/old_give_flash = give_flash
+ var/old_give_hud = give_hud
+ var/old_remove_clumsy = remove_clumsy
+ give_flash = TRUE
+ give_hud = FALSE
+ remove_clumsy = FALSE
+ equip_rev()
+ give_flash = old_give_flash
+ give_hud = old_give_hud
+ remove_clumsy = old_remove_clumsy
+
+/datum/antagonist/rev/head/proc/admin_repair_flash(mob/admin)
+ var/list/L = owner.current.get_contents()
+ var/obj/item/device/assembly/flash/flash = locate() in L
+ if (!flash)
+ to_chat(admin, "Repairing flash failed!")
+ else
+ flash.crit_fail = 0
+ flash.update_icon()
+
+/datum/antagonist/rev/head/proc/admin_demote(datum/mind/target,mob/user)
+ message_admins("[key_name_admin(user)] has demoted [owner.current] from head revolutionary.")
+ log_admin("[key_name(user)] has demoted [owner.current] from head revolutionary.")
+ demote()
/datum/antagonist/rev/head
name = "Head Revolutionary"
@@ -87,6 +151,9 @@
var/give_flash = FALSE
var/give_hud = TRUE
+/datum/antagonist/rev/head/antag_listing_name()
+ return ..() + "(Leader)"
+
/datum/antagonist/rev/proc/update_rev_icons_added(mob/living/M)
var/datum/atom_hud/antag/revhud = GLOB.huds[ANTAG_HUD_REV]
revhud.join_hud(M)
@@ -105,8 +172,6 @@
var/mob/living/carbon/C = candidate //Check to see if the potential rev is implanted
if(!istype(C)) //Can't convert simple animals
return FALSE
- if(C.isloyal())
- return FALSE
return TRUE
/datum/antagonist/rev/proc/add_revolutionary(datum/mind/rev_mind,stun = TRUE)
@@ -127,7 +192,7 @@
var/old_team = rev_team
silent = TRUE
owner.remove_antag_datum(/datum/antagonist/rev/head)
- var/datum/antagonist/rev/new_rev = new /datum/antagonist/rev(old_owner)
+ var/datum/antagonist/rev/new_rev = new /datum/antagonist/rev()
new_rev.silent = TRUE
old_owner.add_antag_datum(new_rev,old_team)
new_rev.silent = FALSE
@@ -279,4 +344,25 @@
result += ""
- return result.Join()
\ No newline at end of file
+ return result.Join()
+
+/datum/team/revolution/antag_listing_entry()
+ var/common_part = ..()
+ var/heads_report = "Heads of Staff
"
+ heads_report += ""
+ for(var/datum/mind/N in SSjob.get_living_heads())
+ var/mob/M = N.current
+ if(M)
+ heads_report += "| [M.real_name][M.client ? "" : " (No Client)"][M.stat == DEAD ? " (DEAD)" : ""] | "
+ heads_report += "PM | "
+ heads_report += "FLW | "
+ var/turf/mob_loc = get_turf(M)
+ heads_report += "[mob_loc.loc] |
"
+ else
+ heads_report += "| [N.name]([N.key])Head body destroyed! | "
+ heads_report += "PM |
"
+ heads_report += "
"
+ return common_part + heads_report
+
+/datum/team/revolution/is_gamemode_hero()
+ return SSticker.mode.name == "revolution"
\ No newline at end of file
diff --git a/code/datums/antagonists/wizard.dm b/code/datums/antagonists/wizard.dm
index e856a6642f66..c4f029e5e3b6 100644
--- a/code/datums/antagonists/wizard.dm
+++ b/code/datums/antagonists/wizard.dm
@@ -6,6 +6,7 @@
/datum/antagonist/wizard
name = "Space Wizard"
roundend_category = "wizards/witches"
+ antagpanel_category = "Wizard"
job_rank = ROLE_WIZARD
var/give_objectives = TRUE
var/strip = TRUE //strip before equipping
@@ -167,6 +168,14 @@
update_wiz_icons_removed(M)
M.faction -= "wizard"
+
+/datum/antagonist/wizard/get_admin_commands()
+ . = ..()
+ .["Send to Lair"] = CALLBACK(src,.proc/admin_send_to_lair)
+
+/datum/antagonist/wizard/proc/admin_send_to_lair(mob/admin)
+ owner.current.forceMove(pick(GLOB.wizardstart))
+
/datum/antagonist/wizard/apprentice
name = "Wizard Apprentice"
hud_version = "apprentice"
diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm
index 1df8d60d3948..8f8fa8f1f0a4 100644
--- a/code/datums/datumvars.dm
+++ b/code/datums/datumvars.dm
@@ -740,28 +740,6 @@
src.give_disease(M)
href_list["datumrefresh"] = href_list["give_spell"]
- else if(href_list["ninja"])
- if(!check_rights(R_FUN))
- return
-
- var/mob/living/carbon/human/M = locate(href_list["ninja"]) in GLOB.carbon_list
- if(!istype(M))
- to_chat(usr, "This can only be used on instances of type /mob")
- return
-
- if(tgalert(usr, "Are you sure you want to make [M] into a ninja?", "Confirmation", "Yes", "No") == "No")
- return
-
- if(!M.mind)
- M.mind_initialize()
-
- var/datum/antagonist/ninja/hiyah = M.mind.has_antag_datum(/datum/antagonist/ninja)
- if(!hiyah)
- hiyah = add_ninja(M)
- if(hiyah)
- hiyah.equip_space_ninja()
- href_list["datumrefresh"] = href_list["ninja"]
-
else if(href_list["gib"])
if(!check_rights(R_FUN))
return
diff --git a/code/datums/diseases/transformation.dm b/code/datums/diseases/transformation.dm
index 06e091d9029b..17aebc46299d 100644
--- a/code/datums/diseases/transformation.dm
+++ b/code/datums/diseases/transformation.dm
@@ -88,7 +88,7 @@
stage5 = list("You feel like monkeying around.")
/datum/disease/transformation/jungle_fever/do_disease_transformation(mob/living/carbon/affected_mob)
- if(affected_mob.mind && !is_monkey(affected_mob))
+ if(affected_mob.mind && !is_monkey(affected_mob.mind))
add_monkey(affected_mob.mind)
if(ishuman(affected_mob))
var/mob/living/carbon/monkey/M = affected_mob.monkeyize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPORGANS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_KEEPSE)
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index 1722673fc26c..d47a25ee55f4 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -140,10 +140,16 @@
if(!istype(A))
return
else
- A = new datum_type_or_instance(src, team)
+ A = new datum_type_or_instance()
+ //Choose snowflake variation if antagonist handles it
+ var/datum/antagonist/S = A.specialization(src)
+ if(S && S != A)
+ qdel(A)
+ A = S
if(!A.can_be_owned(src))
qdel(A)
return
+ A.owner = src
LAZYADD(antag_datums, A)
A.create_team(team)
var/datum/team/antag_team = A.get_team()
@@ -242,7 +248,7 @@
SSticker.mode.update_traitor_icons_removed(src)
SSticker.mode.update_cult_icons_removed(src)
-/datum/mind/proc/equip_traitor(var/employer = "The Syndicate", var/silent = FALSE)
+/datum/mind/proc/equip_traitor(employer = "The Syndicate", silent = FALSE, datum/antagonist/uplink_owner)
if(!current)
return
var/mob/living/carbon/human/traitor_mob = current
@@ -289,27 +295,32 @@
. = 0
else
uplink_loc.AddComponent(/datum/component/uplink, traitor_mob.key)
-
+ var/unlock_note
+
if(uplink_loc == R)
R.traitor_frequency = sanitize_frequency(rand(MIN_FREQ, MAX_FREQ))
if(!silent)
to_chat(traitor_mob, "[employer] has cunningly disguised a Syndicate Uplink as your [R.name]. Simply dial the frequency [format_frequency(R.traitor_frequency)] to unlock its hidden features.")
- traitor_mob.mind.store_memory("Radio Frequency: [format_frequency(R.traitor_frequency)] ([R.name]).")
-
+ unlock_note = "Radio Frequency: [format_frequency(R.traitor_frequency)] ([R.name])."
else if(uplink_loc == PDA)
PDA.lock_code = "[rand(100,999)] [pick(GLOB.phonetic_alphabet)]"
if(!silent)
to_chat(traitor_mob, "[employer] has cunningly disguised a Syndicate Uplink as your [PDA.name]. Simply enter the code \"[PDA.lock_code]\" into the ringtone select to unlock its hidden features.")
- traitor_mob.mind.store_memory("Uplink Passcode: [PDA.lock_code] ([PDA.name]).")
+ unlock_note = "Uplink Passcode: [PDA.lock_code] ([PDA.name])."
else if(uplink_loc == P)
P.traitor_unlock_degrees = rand(1, 360)
if(!silent)
to_chat(traitor_mob, "[employer] has cunningly disguised a Syndicate Uplink as your [P.name]. Simply twist the top of the pen [P.traitor_unlock_degrees] from its starting position to unlock its hidden features.")
- traitor_mob.mind.store_memory("Uplink Degrees: [P.traitor_unlock_degrees] ([P.name]).")
+ unlock_note = "Uplink Degrees: [P.traitor_unlock_degrees] ([P.name])."
+
+ if(uplink_owner)
+ uplink_owner.antag_memory += unlock_note + "
"
+ else
+ traitor_mob.mind.store_memory(unlock_note)
//Link a new mobs mind to the creator of said mob. They will join any team they are currently on, and will only switch teams when their creator does.
@@ -326,7 +337,7 @@
else if(is_nuclear_operative(creator))
var/datum/antagonist/nukeop/converter = creator.mind.has_antag_datum(/datum/antagonist/nukeop,TRUE)
- var/datum/antagonist/nukeop/N = new(src)
+ var/datum/antagonist/nukeop/N = new()
N.send_to_spawnpoint = FALSE
N.nukeop_outfit = null
add_antag_datum(N,converter.nuke_team)
@@ -347,6 +358,10 @@
var/output = "[current.real_name]'s Memories:
"
output += memory
+
+ for(var/datum/antagonist/A in antag_datums)
+ output += A.antag_memory
+
if(objectives.len)
output += "Objectives:"
var/obj_count = 1
@@ -364,396 +379,21 @@
else if(objectives.len || memory)
to_chat(recipient, "[output]")
-/datum/mind/proc/edit_memory()
- if(!SSticker.HasRoundStarted())
- alert("Not before round-start!", "Alert")
- return
- if(QDELETED(src) || QDELETED(current))
- alert("This mind doesn't have a mob, or is deleted! For some reason!", "Edit Memory")
- return
-
- var/out = "[name][(current&&(current.real_name!=name))?" (as [current.real_name])":""]
"
- out += "Mind currently owned by key: [key] [active?"(synced)":"(not synced)"]
"
- out += "Assigned role: [assigned_role]. Edit
"
- out += "Faction and special role: [special_role]
"
-
- var/list/sections = list(
- "traitor", // "traitorchan",
- "changeling",
- "nuclear",
- "wizard",
- "revolution",
- "cult",
- "clockcult",
- "abductor",
- "devil",
- "ninja",
- "monkey"
- )
- var/text = ""
-
- /** TRAITOR ***/
- text = "traitor"
- if (SSticker.mode.config_tag=="traitor" || SSticker.mode.config_tag=="traitorchan" || SSticker.mode.config_tag=="traitorbro")
- text = uppertext(text)
- text = "[text]: "
- if (src in SSticker.mode.traitors)
- text += "TRAITOR | loyal"
- if (objectives.len==0)
- text += "
Objectives are empty! Randomize!"
- else
- text += "traitor | LOYAL"
-
- if(current && current.client && (ROLE_TRAITOR in current.client.prefs.be_special))
- text += " | Enabled in Prefs"
- else
- text += " | Disabled in Prefs"
-
- sections["traitor"] = text
-
-
- if(ishuman(current) || ismonkey(current))
-
- /** BROTHER **/
- text = "brother"
- if(SSticker.mode.config_tag == "traitorbro")
- text = uppertext(text)
- text = "[text]: "
- if(src in SSticker.mode.brothers)
- text += "Brother | no"
-
- if(current && current.client && (ROLE_BROTHER in current.client.prefs.be_special))
- text += " | Enabled in Prefs"
- else
- text += " | Disabled in Prefs"
-
- sections["brother"] = text
-
- /** CHANGELING ***/
- text = "changeling"
- if (SSticker.mode.config_tag=="changeling" || SSticker.mode.config_tag=="traitorchan")
- text = uppertext(text)
- text = "[text]: "
- var/datum/antagonist/changeling/C = has_antag_datum(/datum/antagonist/changeling)
- if(C)
- text += "[C.name] | No"
- if (objectives.len==0)
- text += "
Objectives are empty! Randomize!"
- if(C.stored_profiles.len && (current.real_name != C.first_prof.name) )
- text += "
Transform to initial appearance."
- else
- text += "yes | NO"
-
- if(current && current.client && (ROLE_CHANGELING in current.client.prefs.be_special))
- text += " | Enabled in Prefs"
- else
- text += " | Disabled in Prefs"
-
- sections["changeling"] = text
-
-
- /** MONKEY ***/
- text = "monkey"
- if (SSticker.mode.config_tag=="monkey")
- text = uppertext(text)
- text = "[text]: "
- if (ishuman(current))
- if(is_monkey_leader(src))
- text += "healthy | infected LEADER | human | other"
- else
- text += "healthy | infected | leader | HUMAN | other"
- else if(ismonkey(current))
- var/found = FALSE
- for(var/datum/disease/transformation/jungle_fever/JF in current.viruses)
- found = TRUE
- break
-
- var/isLeader = is_monkey_leader(src)
-
- if(isLeader)
- text += "healthy | infected LEADER | human | other"
- else if(found)
- text += "healthy | INFECTED | leader | human | other"
- else
- text += "HEALTHY | infected | leader | human | other"
-
- else
- text += "healthy | infected | leader | human | OTHER"
-
- if(current && current.client && (ROLE_MONKEY in current.client.prefs.be_special))
- text += " | Enabled in Prefs"
- else
- text += " | Disabled in Prefs"
-
- sections["monkey"] = text
-
- if(ishuman(current))
-
- /** NUCLEAR ***/
- text = "nuclear"
- if (SSticker.mode.config_tag=="nuclear")
- text = uppertext(text)
- text = "[text]: "
- var/datum/antagonist/nukeop/N = has_antag_datum(/datum/antagonist/nukeop,TRUE)
- if(N)
- text += "OPERATIVE | nanotrasen"
- text += "
To shuttle, undress, dress up."
- var/code
- for (var/obj/machinery/nuclearbomb/bombue in GLOB.machines)
- if (length(bombue.r_code) <= 5 && bombue.r_code != "LOLNO" && bombue.r_code != "ADMIN")
- code = bombue.r_code
- break
- if (code)
- text += " Code is [code]. tell the code."
- else
- text += "operative | NANOTRASEN"
-
- if(current && current.client && (ROLE_OPERATIVE in current.client.prefs.be_special))
- text += " | Enabled in Prefs"
- else
- text += " | Disabled in Prefs"
-
- sections["nuclear"] = text
-
-
- /** WIZARD ***/
- text = "wizard"
- if (SSticker.mode.config_tag=="wizard")
- text = uppertext(text)
- text = "[text]: "
- if (has_antag_datum(/datum/antagonist/wizard))
- text += "YES | no"
- text += "
To lair, undress"
- else
- text += "yes | NO"
-
- if(current && current.client && (ROLE_WIZARD in current.client.prefs.be_special))
- text += " | Enabled in Prefs"
- else
- text += " | Disabled in Prefs"
-
- sections["wizard"] = text
-
-
- /** REVOLUTION ***/
- text = "revolution"
- if (SSticker.mode.config_tag=="revolution")
- text = uppertext(text)
- text = "[text]: "
- if (assigned_role in GLOB.command_positions)
- text += "HEAD | not mindshielded | employee | headrev | rev"
- else if (has_antag_datum(/datum/antagonist/rev/head))
- var/datum/antagonist/rev/head = has_antag_datum(/datum/antagonist/rev/head)
- var/last_healthy_headrev = TRUE
- for(var/datum/mind/I in head.rev_team.head_revolutionaries())
- if(I == src)
- continue
- var/mob/M = I.current
- if(M && is_station_level(M.z) && !M.stat)
- last_healthy_headrev = FALSE
- break
- text += "head | not mindshielded | employee | [last_healthy_headrev ? "LAST " : ""]HEADREV | rev"
- text += "
Flash: give"
-
- var/list/L = current.get_contents()
- var/obj/item/device/assembly/flash/flash = locate() in L
- if (flash)
- if(!flash.crit_fail)
- text += " | take."
- else
- text += " | take | repair."
- else
- text += "."
-
- text += " Reequip (gives traitor uplink)."
- if (objectives.len==0)
- text += "
Objectives are empty! Set to kill all heads."
- else if(current.isloyal())
- text += "head | MINDSHIELDED | employee | headrev | rev"
- else if (has_antag_datum(/datum/antagonist/rev))
- text += "head | not mindshielded | employee | headrev | REV"
- else
- text += "head | not mindshielded | EMPLOYEE | headrev | rev"
-
- if(current && current.client && (ROLE_REV in current.client.prefs.be_special))
- text += " | Enabled in Prefs"
- else
- text += " | Disabled in Prefs"
-
- sections["revolution"] = text
-
- /** ABDUCTION **/
- text = "abductor"
- if(SSticker.mode.config_tag == "abductor")
- text = uppertext(text)
- text = "[text]: "
- if(src in SSticker.mode.abductors)
- text += "Abductor | human"
- text += " | undress | equip"
-
- if(current && current.client && (ROLE_ABDUCTOR in current.client.prefs.be_special))
- text += " | Enabled in Prefs"
- else
- text += " | Disabled in Prefs"
-
- sections["abductor"] = text
-
-
- /** DEVIL ***/
- text = "devil"
- if(SSticker.mode.config_tag == "devil")
- text = uppertext(text)
- text = "[text]: "
- var/datum/antagonist/devil/devilinfo = has_antag_datum(ANTAG_DATUM_DEVIL)
- if(devilinfo)
- if(!devilinfo.ascendable)
- text += "DEVIL | ascendable devil | sintouched | human"
- else
- text += "DEVIL | ASCENDABLE DEVIL | sintouched | human"
- else if(src in SSticker.mode.sintouched)
- text += "devil | ascendable devil | SINTOUCHED | human"
- else
- text += "devil | ascendable devil | sintouched | HUMAN"
-
- if(current && current.client && (ROLE_DEVIL in current.client.prefs.be_special))
- text += " | Enabled in Prefs"
- else
- text += " | Disabled in Prefs"
- sections["devil"] = text
-
-
- /** NINJA ***/
- text = "ninja"
- if(SSticker.mode.config_tag == "ninja")
- text = uppertext(text)
- text = "[text]: "
- var/datum/antagonist/ninja/ninjainfo = has_antag_datum(ANTAG_DATUM_NINJA)
- if(ninjainfo)
- if(ninjainfo.helping_station)
- text += "employee | syndicate | NANOTRASEN | EQUIP"
- else
- text += "employee | SYNDICATE | nanotrasen | EQUIP"
- else
- text += "EMPLOYEE | syndicate | nanotrasen | random allegiance"
- if(current && current.client && (ROLE_NINJA in current.client.prefs.be_special))
- text += " | Enabled in Prefs"
- else
- text += " | Disabled in Prefs"
- sections["ninja"] = text
-
-
- if(!issilicon(current))
- /** CULT ***/
- text = "cult"
- if (SSticker.mode.config_tag=="cult")
- text = uppertext(text)
- text = "[text]: "
- if(iscultist(current))
- text += "not mindshielded | employee | CULTIST"
- text += "
Give tome | amulet."
- else if(is_convertable_to_cult(current))
- text += "not mindshielded | EMPLOYEE | cultist"
- else
- text += "[!current.isloyal() ? "not mindshielded" : "MINDSHIELDED"] | EMPLOYEE | cannot serve Nar-Sie"
-
- if(current && current.client && (ROLE_CULTIST in current.client.prefs.be_special))
- text += " | Enabled in Prefs"
- else
- text += " | Disabled in Prefs"
-
- sections["cult"] = text
-
-
- if(ishuman(current) || issilicon(current))
- /** CLOCKWORK CULT **/
- text = "clockwork cult"
- if(SSticker.mode.config_tag == "clockwork cult")
- text = uppertext(text)
- text = "[text]: "
- if(is_servant_of_ratvar(current))
- text += "not mindshielded | employee | SERVANT"
- text += "
Equip"
- else if(is_eligible_servant(current))
- text += "not mindshielded | EMPLOYEE | servant"
- else
- text += "[!current.isloyal() ? "not mindshielded" : "MINDSHIELDED"] | EMPLOYEE | cannot serve Ratvar"
-
- if(current && current.client && (ROLE_SERVANT_OF_RATVAR in current.client.prefs.be_special))
- text += " | Enabled in Prefs"
- else
- text += " | Disabled in Prefs"
-
- sections["clockcult"] = text
-
-
- /** SILICON ***/
- if(issilicon(current))
- text = "silicon"
- var/mob/living/silicon/robot/robot = current
- if (istype(robot) && robot.emagged)
- text += "
Cyborg: Is emagged! Unemag!
0th law: [robot.laws.zeroth]"
- var/mob/living/silicon/ai/ai = current
- if (istype(ai) && ai.connected_robots.len)
- var/n_e_robots = 0
- for (var/mob/living/silicon/robot/R in ai.connected_robots)
- if (R.emagged)
- n_e_robots++
- text += "
[n_e_robots] of [ai.connected_robots.len] slaved cyborgs are emagged. Unemag"
- if (SSticker.mode.config_tag == "traitorchan")
- if (sections["traitor"])
- out += sections["traitor"]+"
"
- if (sections["changeling"])
- out += sections["changeling"]+"
"
- sections -= "traitor"
- sections -= "changeling"
- else
- if (sections[SSticker.mode.config_tag])
- out += sections[SSticker.mode.config_tag]+"
"
- sections -= SSticker.mode.config_tag
- for (var/i in sections)
- if (sections[i])
- out += sections[i]+"
"
-
-
- if(((src in SSticker.mode.traitors) || is_nuclear_operative(current)) && ishuman(current))
- text = "Uplink: give"
- var/datum/component/uplink/U = find_syndicate_uplink()
- if(U)
- text += " | take"
- if (check_rights(R_FUN, 0))
- text += ", [U.telecrystals] TC"
- else
- text += ", [U.telecrystals] TC"
- text += "." //hiel grammar
- out += text
-
- out += "
"
-
- out += "Memory:
"
- out += memory
- out += "
Edit memory
"
- out += "Objectives:
"
- if (objectives.len == 0)
- out += "EMPTY
"
- else
- var/obj_count = 1
- for(var/datum/objective/objective in objectives)
- out += "[obj_count]: [objective.explanation_text] Edit Delete [objective.completed ? "Mark as incomplete" : "Mark as complete"]
"
- obj_count++
- out += "Add objective
"
-
- out += "Announce objectives
"
-
- var/datum/browser/popup = new(usr, "edit_memory", "", 600, 600)
- popup.set_content(out)
- popup.open()
- //usr << browse(out, "window=edit_memory[src];size=575x600")
-
-
/datum/mind/Topic(href, href_list)
if(!check_rights(R_ADMIN))
return
+ var/self_antagging = usr == current
+
+ if(href_list["add_antag"])
+ add_antag_wrapper(text2path(href_list["add_antag"]),usr)
+ if(href_list["remove_antag"])
+ var/datum/antagonist/A = locate(href_list["remove_antag"]) in antag_datums
+ if(!istype(A))
+ to_chat(usr,"Invalid antagonist ref to be removed.")
+ return
+ A.admin_remove(usr)
+
if (href_list["role_edit"])
var/new_role = input("Select new role", "Assigned role", assigned_role) as null|anything in get_all_jobs()
if (!new_role)
@@ -771,8 +411,6 @@
var/objective_pos
var/def_value
-
-
var/datum/antagonist/target_antag
if (href_list["obj_edit"])
@@ -786,7 +424,7 @@
objective_pos = A.objectives.Find(objective)
break
- if(!target_antag) //Shouldn't happen
+ if(!target_antag) //Shouldn't happen anymore
stack_trace("objective without antagonist found")
objective_pos = objectives.Find(objective)
@@ -796,19 +434,25 @@
if(!def_value)//If it's a custom objective, it will be an empty string.
def_value = "custom"
else
- switch(antag_datums.len)
- if(0)
- target_antag = add_antag_datum(/datum/antagonist/custom)
- if(1)
- target_antag = antag_datums[1]
- else
- var/datum/antagonist/target = input("Which antagonist gets the objective:", "Antagonist", def_value) as null|anything in antag_datums + "(new custom antag)"
- if (QDELETED(target))
- return
- else if(target == "(new custom antag)")
+ //We're adding this objective
+ if(href_list["target_antag"])
+ var/datum/antagonist/X = locate(href_list["target_antag"]) in antag_datums
+ if(X)
+ target_antag = X
+ if(!target_antag)
+ switch(antag_datums.len)
+ if(0)
target_antag = add_antag_datum(/datum/antagonist/custom)
+ if(1)
+ target_antag = antag_datums[1]
else
- target_antag = target
+ var/datum/antagonist/target = input("Which antagonist gets the objective:", "Antagonist", def_value) as null|anything in antag_datums + "(new custom antag)"
+ if (QDELETED(target))
+ return
+ else if(target == "(new custom antag)")
+ target_antag = add_antag_datum(/datum/antagonist/custom)
+ else
+ target_antag = target
var/new_obj_type = input("Select objective type:", "Objective type", def_value) as null|anything in list("assassinate", "maroon", "debrain", "protect", "destroy", "prevent", "hijack", "escape", "survive", "martyr", "steal", "download", "nuclear", "capture", "absorb", "custom")
if (!new_obj_type)
@@ -957,344 +601,6 @@
objective.completed = !objective.completed
log_admin("[key_name(usr)] toggled the win state for [current]'s objective: [objective.explanation_text]")
- else if (href_list["revolution"])
- switch(href_list["revolution"])
- if("clear")
- remove_rev()
- message_admins("[key_name_admin(usr)] has de-rev'ed [current].")
- log_admin("[key_name(usr)] has de-rev'ed [current].")
- if("rev")
- if(has_antag_datum(/datum/antagonist/rev/head))
- var/datum/antagonist/rev/head/head = has_antag_datum(/datum/antagonist/rev/head)
- head.demote()
- else if(!has_antag_datum(/datum/antagonist/rev))
- add_antag_datum(/datum/antagonist/rev)
- special_role = "Revolutionary"
- message_admins("[key_name_admin(usr)] has rev'ed [current].")
- log_admin("[key_name(usr)] has rev'ed [current].")
- else
- return
-
- if("headrev")
- if(has_antag_datum(/datum/antagonist/rev))
- var/datum/antagonist/rev/rev = has_antag_datum(/datum/antagonist/rev)
- rev.promote()
- else if(!has_antag_datum(/datum/antagonist/rev/head))
- //what about the team here.
- var/datum/antagonist/rev/head/new_head = new /datum/antagonist/rev/head(src)
- new_head.give_flash = TRUE
- new_head.give_hud = TRUE
- new_head.remove_clumsy = TRUE
- add_antag_datum(new_head)
- to_chat(current, "You are a member of the revolutionaries' leadership now!")
- else
- return
- special_role = "Head Revolutionary"
- message_admins("[key_name_admin(usr)] has head-rev'ed [current].")
- log_admin("[key_name(usr)] has head-rev'ed [current].")
-
- if("flash")
- var/datum/antagonist/rev/head/head = has_antag_datum(/datum/antagonist/rev/head)
- if(!head.equip_rev())
- to_chat(usr, "Spawning flash failed!")
-
- if("takeflash")
- var/list/L = current.get_contents()
- var/obj/item/device/assembly/flash/flash = locate() in L
- if (!flash)
- to_chat(usr, "Deleting flash failed!")
- qdel(flash)
-
- if("repairflash")
- var/list/L = current.get_contents()
- var/obj/item/device/assembly/flash/flash = locate() in L
- if (!flash)
- to_chat(usr, "Repairing flash failed!")
- else
- flash.crit_fail = 0
- flash.update_icon()
-
-
-
- else if (href_list["cult"])
- switch(href_list["cult"])
- if("clear")
- remove_cultist()
- message_admins("[key_name_admin(usr)] has de-cult'ed [current].")
- log_admin("[key_name(usr)] has de-cult'ed [current].")
- if("cultist")
- if(!(src in SSticker.mode.cult))
- SSticker.mode.add_cultist(src, 0)
- message_admins("[key_name_admin(usr)] has cult'ed [current].")
- log_admin("[key_name(usr)] has cult'ed [current].")
- if("tome")
- var/datum/antagonist/cult/C = has_antag_datum(/datum/antagonist/cult,TRUE)
- if (C.equip_cultist(current,1))
- to_chat(usr, "Spawning tome failed!")
-
- if("amulet")
- var/datum/antagonist/cult/C = has_antag_datum(/datum/antagonist/cult,TRUE)
- if (C.equip_cultist(current))
- to_chat(usr, "Spawning amulet failed!")
-
- else if(href_list["clockcult"])
- switch(href_list["clockcult"])
- if("clear")
- remove_servant_of_ratvar(current, TRUE)
- message_admins("[key_name_admin(usr)] has removed clockwork servant status from [current].")
- log_admin("[key_name(usr)] has removed clockwork servant status from [current].")
- if("servant")
- if(!is_servant_of_ratvar(current))
- add_servant_of_ratvar(current, TRUE)
- message_admins("[key_name_admin(usr)] has made [current] into a servant of Ratvar.")
- log_admin("[key_name(usr)] has made [current] into a servant of Ratvar.")
- if("slab")
- if(!SSticker.mode.equip_servant(current))
- to_chat(usr, "Failed to outfit [current]!")
- else
- to_chat(usr, "Successfully gave [current] servant equipment!")
-
- else if (href_list["wizard"])
- switch(href_list["wizard"])
- if("clear")
- remove_wizard()
- log_admin("[key_name(usr)] has de-wizard'ed [current].")
- if("wizard")
- if(!has_antag_datum(/datum/antagonist/wizard))
- special_role = "Wizard"
- add_antag_datum(/datum/antagonist/wizard)
- message_admins("[key_name_admin(usr)] has wizard'ed [current].")
- log_admin("[key_name(usr)] has wizard'ed [current].")
- if("lair")
- current.forceMove(pick(GLOB.wizardstart))
-
- else if (href_list["changeling"])
- switch(href_list["changeling"])
- if("clear")
- remove_antag_datum(/datum/antagonist/changeling)
- special_role = null
- to_chat(current, "You grow weak and lose your powers! You are no longer a changeling and are stuck in your current form!")
- message_admins("[key_name_admin(usr)] has de-changeling'ed [current].")
- log_admin("[key_name(usr)] has de-changeling'ed [current].")
- if("changeling")
- var/datum/antagonist/changeling/C = make_Changling()
- to_chat(current, "Our powers have awoken. A flash of memory returns to us...we are [C.changelingID], a changeling!")
- message_admins("[key_name_admin(usr)] has changeling'ed [current].")
- log_admin("[key_name(usr)] has changeling'ed [current].")
- if("autoobjectives")
- var/datum/antagonist/changeling/C = has_antag_datum(/datum/antagonist/changeling)
- if(C)
- C.forge_objectives()
- to_chat(usr, "The objectives for changeling [key] have been generated. You can edit them and anounce manually.")
- if("initialdna")
- var/datum/antagonist/changeling/ling = has_antag_datum(/datum/antagonist/changeling)
- if( !ling || !ling.stored_profiles.len || !iscarbon(current))
- to_chat(usr, "Resetting DNA failed!")
- else
- var/mob/living/carbon/C = current
- ling.first_prof.dna.transfer_identity(C, transfer_SE=1)
- C.real_name = ling.first_prof.name
- C.updateappearance(mutcolor_update=1)
- C.domutcheck()
-
- else if (href_list["nuclear"])
- switch(href_list["nuclear"])
- if("clear")
- remove_nukeop()
- to_chat(current, "You have been brainwashed! You are no longer a syndicate operative!")
- message_admins("[key_name_admin(usr)] has de-nuke op'ed [current].")
- log_admin("[key_name(usr)] has de-nuke op'ed [current].")
- if("nuclear")
- if(!has_antag_datum(/datum/antagonist/nukeop,TRUE))
- add_antag_datum(/datum/antagonist/nukeop)
- special_role = "Syndicate"
- assigned_role = "Syndicate"
- message_admins("[key_name_admin(usr)] has nuke op'ed [current].")
- log_admin("[key_name(usr)] has nuke op'ed [current].")
- if("lair")
- current.forceMove(pick(GLOB.nukeop_start))
- if("tellcode")
- var/code
- for (var/obj/machinery/nuclearbomb/bombue in GLOB.machines)
- if (length(bombue.r_code) <= 5 && bombue.r_code != "LOLNO" && bombue.r_code != "ADMIN")
- code = bombue.r_code
- break
- if (code)
- store_memory("Syndicate Nuclear Bomb Code: [code]", 0, 0)
- to_chat(current, "The nuclear authorization code is: [code]")
- else
- to_chat(usr, "No valid nuke found!")
-
- else if (href_list["traitor"])
- switch(href_list["traitor"])
- if("clear")
- to_chat(current, "You have been brainwashed!")
- remove_traitor()
- message_admins("[key_name_admin(usr)] has de-traitor'ed [current].")
- log_admin("[key_name(usr)] has de-traitor'ed [current].")
- SSticker.mode.update_traitor_icons_removed(src)
-
- if("traitor")
- if(!(src in SSticker.mode.traitors))
- message_admins("[key_name_admin(usr)] has traitor'ed [current].")
- log_admin("[key_name(usr)] has traitor'ed [current].")
- make_Traitor()
-
- if("autoobjectives")
- var/datum/antagonist/traitor/traitordatum = has_antag_datum(ANTAG_DATUM_TRAITOR)
- if(!traitordatum)
- message_admins("[key_name_admin(usr)] has traitor'ed [current] as part of autoobjectives.")
- log_admin("[key_name(usr)] has traitor'ed [current] as part of autoobjectives.")
- make_Traitor()
- else
- log_admin("[key_name(usr)] has forged objectives for [current] as part of autoobjectives.")
- traitordatum.forge_traitor_objectives()
- to_chat(usr, "The objectives for traitor [key] have been generated. You can edit them and anounce manually.")
-
- else if(href_list["devil"])
- var/datum/antagonist/devil/devilinfo = has_antag_datum(ANTAG_DATUM_DEVIL)
- switch(href_list["devil"])
- if("clear")
- if(src in SSticker.mode.devils)
- remove_devil(current)
- message_admins("[key_name_admin(usr)] has de-devil'ed [current].")
- log_admin("[key_name(usr)] has de-devil'ed [current].")
- if(src in SSticker.mode.sintouched)
- SSticker.mode.sintouched -= src
- message_admins("[key_name_admin(usr)] has de-sintouch'ed [current].")
- log_admin("[key_name(usr)] has de-sintouch'ed [current].")
- if("devil")
- if(devilinfo)
- devilinfo.ascendable = FALSE
- message_admins("[key_name_admin(usr)] has made [current] unable to ascend as a devil.")
- log_admin("[key_name(usr)] has made [current] unable to ascend as a devil.")
- return
- if(!ishuman(current) && !iscyborg(current))
- to_chat(usr, "This only works on humans and cyborgs!")
- return
- add_devil(current, FALSE)
- message_admins("[key_name_admin(usr)] has devil'ed [current].")
- log_admin("[key_name(usr)] has devil'ed [current].")
- if("ascendable_devil")
- if(devilinfo)
- devilinfo.ascendable = TRUE
- message_admins("[key_name_admin(usr)] has made [current] able to ascend as a devil.")
- log_admin("[key_name(usr)] has made [current] able to ascend as a devil.")
- return
- if(!ishuman(current) && !iscyborg(current))
- to_chat(usr, "This only works on humans and cyborgs!")
- return
- add_devil(current, TRUE)
- message_admins("[key_name_admin(usr)] has devil'ed [current]. The devil has been marked as ascendable.")
- log_admin("[key_name(usr)] has devil'ed [current]. The devil has been marked as ascendable.")
- if("sintouched")
- if(ishuman(current))
- var/mob/living/carbon/human/H = current
- H.influenceSin()
- message_admins("[key_name_admin(usr)] has sintouch'ed [current].")
- else
- to_chat(usr, "This only works on humans!")
- return
- else if(href_list["ninja"])
- var/datum/antagonist/ninja/ninjainfo = has_antag_datum(ANTAG_DATUM_NINJA)
- switch(href_list["ninja"])
- if("clear")
- remove_ninja(current)
- message_admins("[key_name_admin(usr)] has de-ninja'ed [current].")
- log_admin("[key_name(usr)] has de-ninja'ed [current].")
- if("equip")
- ninjainfo.equip_space_ninja()
- return
- if("nanotrasen")
- add_ninja(current, ANTAG_DATUM_NINJA_FRIENDLY)
- message_admins("[key_name_admin(usr)] has friendly ninja'ed [current].")
- log_admin("[key_name(usr)] has friendly ninja'ed [current].")
- if("syndicate")
- add_ninja(current, ANTAG_DATUM_NINJA)
- message_admins("[key_name_admin(usr)] has syndie ninja'ed [current].")
- log_admin("[key_name(usr)] has syndie ninja'ed [current].")
- if("random")
- add_ninja(current)
- message_admins("[key_name_admin(usr)] has random ninja'ed [current].")
- log_admin("[key_name(usr)] has random ninja'ed [current].")
- else if(href_list["abductor"])
- switch(href_list["abductor"])
- if("clear")
- to_chat(usr, "Not implemented yet. Sorry!")
- //SSticker.mode.update_abductor_icons_removed(src)
- if("equip")
- if(!ishuman(current))
- to_chat(usr, "This only works on humans!")
- return
-
- var/mob/living/carbon/human/H = current
- var/gear = alert("Agent or Scientist Gear","Gear","Agent","Scientist")
- if(gear)
- if(gear=="Agent")
- H.equipOutfit(/datum/outfit/abductor/agent)
- else
- H.equipOutfit(/datum/outfit/abductor/scientist)
-
- else if (href_list["monkey"])
- var/mob/living/L = current
- if (L.notransform)
- return
- switch(href_list["monkey"])
- if("healthy")
- if (check_rights(R_ADMIN))
- var/mob/living/carbon/human/H = current
- var/mob/living/carbon/monkey/M = current
- if (istype(H))
- log_admin("[key_name(usr)] attempting to monkeyize [key_name(current)]")
- message_admins("[key_name_admin(usr)] attempting to monkeyize [key_name_admin(current)]")
- src = null
- M = H.monkeyize()
- src = M.mind
- else if (istype(M) && length(M.viruses))
- for(var/thing in M.viruses)
- var/datum/disease/D = thing
- D.cure(FALSE)
- if("leader")
- if(check_rights(R_ADMIN, 0))
- add_monkey_leader(src)
- log_admin("[key_name(usr)] made [key_name(current)] a monkey leader!")
- message_admins("[key_name_admin(usr)] made [key_name_admin(current)] a monkey leader!")
- if("infected")
- if(check_rights(R_ADMIN, 0))
- var/mob/living/carbon/human/H = current
- var/mob/living/carbon/monkey/M = current
- add_monkey(src)
- if (istype(H))
- log_admin("[key_name(usr)] attempting to monkeyize and infect [key_name(current)]")
- message_admins("[key_name_admin(usr)] attempting to monkeyize and infect [key_name_admin(current)]")
- src = null
- M = H.monkeyize()
- src = M.mind
- current.ForceContractDisease(new /datum/disease/transformation/jungle_fever)
- else if (istype(M))
- current.ForceContractDisease(new /datum/disease/transformation/jungle_fever)
- if("human")
- if (check_rights(R_ADMIN, 0))
- var/mob/living/carbon/human/H = current
- var/mob/living/carbon/monkey/M = current
- if (istype(M))
- for(var/datum/disease/transformation/jungle_fever/JF in M.viruses)
- JF.cure(0)
- stoplag() //because deleting of virus is doing throught spawn(0) //What
- remove_monkey(src)
- log_admin("[key_name(usr)] attempting to humanize [key_name(current)]")
- message_admins("[key_name_admin(usr)] attempting to humanize [key_name_admin(current)]")
- H = M.humanize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPORGANS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_DEFAULTMSG)
- if(H)
- src = H.mind
-
- else if (href_list["brother"])
- switch(href_list["brother"])
- if("clear")
- remove_brother()
- log_admin("[key_name(usr)] has de-brother'ed [current].")
- SSticker.mode.update_brother_icons_removed(src)
-
else if (href_list["silicon"])
switch(href_list["silicon"])
if("unemag")
@@ -1340,7 +646,10 @@
else if (href_list["obj_announce"])
announce_objectives()
- edit_memory()
+ //Something in here might have changed your mob
+ if(self_antagging && (!usr || !usr.client) && current.client)
+ usr = current
+ traitor_panel()
/datum/mind/proc/announce_objectives()
var/obj_count = 1
@@ -1363,9 +672,7 @@
/datum/mind/proc/make_Traitor()
if(!(has_antag_datum(ANTAG_DATUM_TRAITOR)))
- var/datum/antagonist/traitor/T = new(src)
- T.should_specialise = TRUE
- add_antag_datum(T)
+ add_antag_datum(/datum/antagonist/traitor)
/datum/mind/proc/make_Changling()
var/datum/antagonist/changeling/C = has_antag_datum(/datum/antagonist/changeling)
@@ -1389,7 +696,7 @@
to_chat(current, "Assist your new bretheren in their dark dealings. Their goal is yours, and yours is theirs. You serve the Dark One above all else. Bring It back.")
/datum/mind/proc/make_Rev()
- var/datum/antagonist/rev/head/head = new(src)
+ var/datum/antagonist/rev/head/head = new()
head.give_flash = TRUE
head.give_hud = TRUE
add_antag_datum(head)
diff --git a/code/game/gamemodes/antag_spawner.dm b/code/game/gamemodes/antag_spawner.dm
index 3b8937d9fb4c..8d4c1cf5ba95 100644
--- a/code/game/gamemodes/antag_spawner.dm
+++ b/code/game/gamemodes/antag_spawner.dm
@@ -73,8 +73,8 @@
C.prefs.copy_to(M)
M.key = C.key
var/datum/mind/app_mind = M.mind
-
- var/datum/antagonist/wizard/apprentice/app = new(app_mind)
+
+ var/datum/antagonist/wizard/apprentice/app = new()
app.master = user
app.school = kind
@@ -136,7 +136,7 @@
C.prefs.copy_to(M)
M.key = C.key
- var/datum/antagonist/nukeop/new_op = new(M.mind)
+ var/datum/antagonist/nukeop/new_op = new()
new_op.send_to_spawnpoint = FALSE
new_op.nukeop_outfit = /datum/outfit/syndicate/no_crystals
@@ -187,8 +187,8 @@
R.real_name = R.name
R.key = C.key
-
- var/datum/antagonist/nukeop/new_borg = new(R.mind)
+
+ var/datum/antagonist/nukeop/new_borg = new()
new_borg.send_to_spawnpoint = FALSE
R.mind.add_antag_datum(new_borg,creator_op.nuke_team)
R.mind.special_role = "Syndicate Cyborg"
@@ -235,7 +235,6 @@
S.key = C.key
S.mind.assigned_role = S.name
S.mind.special_role = S.name
- SSticker.mode.traitors += S.mind
var/datum/objective/assassinate/new_objective
if(user)
new_objective = new /datum/objective/assassinate
diff --git a/code/game/gamemodes/antag_team.dm b/code/game/gamemodes/antag_team.dm
index 372ee26dfad6..56ca7c76e224 100644
--- a/code/game/gamemodes/antag_team.dm
+++ b/code/game/gamemodes/antag_team.dm
@@ -31,4 +31,16 @@
report += "The [member_name]s were:"
report += printplayerlist(members)
- return report.Join("
")
\ No newline at end of file
+ return report.Join("
")
+
+//Get all teams [of type team_type]
+//TODO move these to some antag helpers file with get_antagonists
+/proc/get_all_teams(team_type)
+ . = list()
+ for(var/V in GLOB.antagonists)
+ var/datum/antagonist/A = V
+ if(!A.owner)
+ continue
+ var/datum/team/T = A.get_team()
+ if(!team_type || istype(T,team_type))
+ . |= T
diff --git a/code/game/gamemodes/brother/traitor_bro.dm b/code/game/gamemodes/brother/traitor_bro.dm
index 5052fa0cf5be..1634983a1b50 100644
--- a/code/game/gamemodes/brother/traitor_bro.dm
+++ b/code/game/gamemodes/brother/traitor_bro.dm
@@ -18,8 +18,6 @@
var/const/min_team_size = 2
traitors_required = FALSE //Only teams are possible
- var/meeting_areas = list("The Bar", "Dorms", "Escape Dock", "Arrivals", "Holodeck", "Primary Tool Storage", "Recreation Area", "Chapel", "Library")
-
/datum/game_mode/traitor/bros/pre_setup()
if(CONFIG_GET(flag/protect_roles_from_antagonist))
restricted_jobs += protected_jobs
@@ -51,8 +49,7 @@
/datum/game_mode/traitor/bros/post_setup()
for(var/datum/team/brother_team/team in pre_brother_teams)
- team.meeting_area = pick(meeting_areas)
- meeting_areas -= team.meeting_area
+ team.pick_meeting_area()
team.forge_brother_objectives()
for(var/datum/mind/M in team.members)
M.add_antag_datum(ANTAG_DATUM_BROTHER, team)
diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm
index ad76d41d473f..491378c5de29 100644
--- a/code/game/gamemodes/changeling/changeling.dm
+++ b/code/game/gamemodes/changeling/changeling.dm
@@ -70,7 +70,7 @@ GLOBAL_VAR(changeling_team_objective_type) //If this is not null, we hand our th
for(var/datum/mind/changeling in changelings)
log_game("[changeling.key] (ckey) has been selected as a changeling")
- var/datum/antagonist/changeling/new_antag = new(changeling)
+ var/datum/antagonist/changeling/new_antag = new()
new_antag.team_mode = TRUE
changeling.add_antag_datum(new_antag)
..()
diff --git a/code/game/gamemodes/changeling/powers/absorb.dm b/code/game/gamemodes/changeling/powers/absorb.dm
index 56003d91ebf4..bd641757806d 100644
--- a/code/game/gamemodes/changeling/powers/absorb.dm
+++ b/code/game/gamemodes/changeling/powers/absorb.dm
@@ -78,12 +78,12 @@
recent_speech[spoken_memory] = say_log[spoken_memory]
if(recent_speech.len)
- user.mind.store_memory("Some of [target]'s speech patterns, we should study these to better impersonate them!")
+ changeling.antag_memory += "Some of [target]'s speech patterns, we should study these to better impersonate them!
"
to_chat(user, "Some of [target]'s speech patterns, we should study these to better impersonate them!")
for(var/spoken_memory in recent_speech)
- user.mind.store_memory("\"[recent_speech[spoken_memory]]\"")
+ changeling.antag_memory += "\"[recent_speech[spoken_memory]]\"
"
to_chat(user, "\"[recent_speech[spoken_memory]]\"")
- user.mind.store_memory("We have no more knowledge of [target]'s speech patterns.")
+ changeling.antag_memory += "We have no more knowledge of [target]'s speech patterns.
"
to_chat(user, "We have no more knowledge of [target]'s speech patterns.")
diff --git a/code/game/gamemodes/clock_cult/clock_cult.dm b/code/game/gamemodes/clock_cult/clock_cult.dm
index f5484e91f51b..c7765b19bfe5 100644
--- a/code/game/gamemodes/clock_cult/clock_cult.dm
+++ b/code/game/gamemodes/clock_cult/clock_cult.dm
@@ -74,8 +74,35 @@ Credit where due:
var/datum/antagonist/clockcult/C = new update_type(L.mind)
C.make_team = create_team
C.show_in_roundend = create_team //tutorial scarabs begone
+
+ if(iscyborg(L))
+ var/mob/living/silicon/robot/R = L
+ if(R.deployed)
+ var/mob/living/silicon/ai/AI = R.mainframe
+ R.undeploy()
+ to_chat(AI, "Anomaly Detected. Returned to core!") //The AI needs to be in its core to properly be converted
+
. = L.mind.add_antag_datum(C)
+ if(!silent && L)
+ if(.)
+ to_chat(L, "The world before you suddenly glows a brilliant yellow. [issilicon(L) ? "You cannot compute this truth!" : \
+ "Your mind is racing!"] You hear the whooshing steam and cl[pick("ank", "ink", "unk", "ang")]ing cogs of a billion billion machines, and all at once it comes to you.
\
+ Ratvar, the Clockwork Justiciar, [GLOB.ratvar_awakens ? "has been freed from his eternal prison" : "lies in exile, derelict and forgotten in an unseen realm"].")
+ flash_color(L, flash_color = list("#BE8700", "#BE8700", "#BE8700", rgb(0,0,0)), flash_time = 50)
+ else
+ L.visible_message("[L] seems to resist an unseen force!", null, null, 7, L)
+ to_chat(L, "The world before you suddenly glows a brilliant yellow. [issilicon(L) ? "You cannot compute this truth!" : \
+ "Your mind is racing!"] You hear the whooshing steam and cl[pick("ank", "ink", "unk", "ang")]ing cogs of a billion billion machines, and the sound \
+ is a meaningless cacophony.
\
+ You see an abomination of rusting parts[GLOB.ratvar_awakens ? ", and it is here.
It is too late" : \
+ " in an endless grey void.
It cannot be allowed to escape"].")
+ L.playsound_local(get_turf(L), 'sound/ambience/antag/clockcultalr.ogg', 40, TRUE, frequency = 100000, pressure_affected = FALSE)
+ flash_color(L, flash_color = list("#BE8700", "#BE8700", "#BE8700", rgb(0,0,0)), flash_time = 5)
+
+
+
+
/proc/remove_servant_of_ratvar(mob/L, silent = FALSE)
if(!L || !L.mind)
return
diff --git a/code/game/gamemodes/clock_cult/clock_structures/eminence_spire.dm b/code/game/gamemodes/clock_cult/clock_structures/eminence_spire.dm
index 2edaba3b2389..2fa682ff5c42 100644
--- a/code/game/gamemodes/clock_cult/clock_structures/eminence_spire.dm
+++ b/code/game/gamemodes/clock_cult/clock_structures/eminence_spire.dm
@@ -38,7 +38,8 @@
/obj/structure/destructible/clockwork/eminence_spire/attack_ghost(mob/user)
if(!IsAdminGhost(user))
return
- var/datum/antagonist/clockcult/random_cultist = locate() in GLOB.antagonists //if theres no cultists new team without eminence will be created anyway.
+
+ var/datum/antagonist/clockcult/random_cultist = locate() in get_antagonists(/datum/antagonist/clockcult) //if theres no cultists new team without eminence will be created anyway.
if(random_cultist && random_cultist.clock_team && random_cultist.clock_team.eminence)
to_chat(user, "There's already an Eminence - too late!")
return
diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm
index 35e8c3cb4e42..42939460730f 100644
--- a/code/game/gamemodes/cult/cult.dm
+++ b/code/game/gamemodes/cult/cult.dm
@@ -99,7 +99,7 @@
if (!istype(cult_mind))
return 0
- var/datum/antagonist/cult/new_cultist = new(cult_mind)
+ var/datum/antagonist/cult/new_cultist = new()
new_cultist.give_equipment = equip
if(cult_mind.add_antag_datum(new_cultist))
diff --git a/code/game/gamemodes/cult/cult_comms.dm b/code/game/gamemodes/cult/cult_comms.dm
index b809f2419c95..be029c31788e 100644
--- a/code/game/gamemodes/cult/cult_comms.dm
+++ b/code/game/gamemodes/cult/cult_comms.dm
@@ -338,6 +338,7 @@
return ..()
/datum/action/innate/cult/master/pulse/Destroy()
+ PM.attached_action = null //What the fuck is even going on here.
QDEL_NULL(PM)
return ..()
diff --git a/code/game/gamemodes/miniantags/abduction/abduction.dm b/code/game/gamemodes/miniantags/abduction/abduction.dm
index f9e8f8d75253..ff4d80cd6e9c 100644
--- a/code/game/gamemodes/miniantags/abduction/abduction.dm
+++ b/code/game/gamemodes/miniantags/abduction/abduction.dm
@@ -1,92 +1,6 @@
/datum/game_mode
var/list/datum/mind/abductors = list()
-/datum/game_mode/abduction
- name = "abduction"
- config_tag = "abduction"
- antag_flag = ROLE_ABDUCTOR
- false_report_weight = 1
- recommended_enemies = 2
- required_players = 15
- maximum_players = 50
- var/max_teams = 4
- var/list/datum/team/abductor_team/abductor_teams = list()
- var/finished = FALSE
- var/static/team_count = 0
-
-/datum/game_mode/abduction/announce()
- to_chat(world, "The current game mode is - Abduction!")
- to_chat(world, "There are alien abductors sent to [station_name()] to perform nefarious experiments!")
- to_chat(world, "Abductors - kidnap the crew and replace their organs with experimental ones.")
- to_chat(world, "Crew - don't get abducted and stop the abductors.")
-
-/datum/game_mode/abduction/pre_setup()
- var/num_teams = max(1, min(max_teams, round(num_players() / CONFIG_GET(number/abductor_scaling_coeff))))
- var/possible_teams = max(1, round(antag_candidates.len / 2))
- num_teams = min(num_teams, possible_teams)
-
- for(var/i = 1 to num_teams)
- if(!make_abductor_team())
- return FALSE
- return TRUE
-
-/datum/game_mode/abduction/proc/make_abductor_team(datum/mind/agent, datum/mind/scientist)
- team_count++ //TODO: Fix the edge case of abductor game mode rolling twice+ and failing to setup on first time.
- var/team_number = team_count
-
- if(team_number > max_teams)
- return //or should it try to stuff them in anway ?
-
- var/datum/team/abductor_team/team = new
- team.team_number = team_number
- team.name = "Mothership [pick(GLOB.possible_changeling_IDs)]" //TODO Ensure unique and actual alieny names
- team.add_objective(new/datum/objective/experiment)
-
- if(antag_candidates.len < (!agent + !scientist))
- return
-
- if(!scientist)
- scientist = pick(antag_candidates)
- antag_candidates -= scientist
- team.members |= scientist
- scientist.assigned_role = "Abductor Scientist"
- scientist.special_role = "Abductor Scientist"
- log_game("[scientist.key] (ckey) has been selected as [team.name] abductor scientist.")
-
- if(!agent)
- agent = pick(antag_candidates)
- antag_candidates -= agent
- team.members |= agent
- agent.assigned_role = "Abductor Agent"
- agent.special_role = "Abductor Agent"
- log_game("[agent.key] (ckey) has been selected as [team.name] abductor agent.")
-
- abductor_teams += team
- return team
-
-/datum/game_mode/abduction/post_setup()
- for(var/datum/team/abductor_team/team in abductor_teams)
- post_setup_team(team)
- return ..()
-
-//Used for create antag buttons
-/datum/game_mode/abduction/proc/post_setup_team(datum/team/abductor_team/team)
- for(var/datum/mind/M in team.members)
- if(M.assigned_role == "Abductor Scientist")
- M.add_antag_datum(ANTAG_DATUM_ABDUCTOR_SCIENTIST, team)
- else
- M.add_antag_datum(ANTAG_DATUM_ABDUCTOR_AGENT, team)
-
-/datum/game_mode/abduction/check_finished()
- if(!finished)
- for(var/datum/team/abductor_team/team in abductor_teams)
- for(var/datum/objective/O in team.objectives)
- if(O.check_completion())
- SSshuttle.emergency.request(null, set_coefficient = 0.5)
- finished = TRUE
- return ..()
- return ..()
-
// LANDMARKS
/obj/effect/landmark/abductor
var/team_number = 1
@@ -118,8 +32,4 @@
/datum/game_mode/proc/update_abductor_icons_removed(datum/mind/alien_mind)
var/datum/atom_hud/antag/hud = GLOB.huds[ANTAG_HUD_ABDUCTOR]
hud.leave_hud(alien_mind.current)
- set_antag_hud(alien_mind.current, null)
-
-/datum/game_mode/abduction/generate_report()
- return "Nearby spaceships report crewmembers having been [pick("kidnapped", "abducted", "captured")] and [pick("tortured", "experimented on", "probed", "implanted")] by mysterious \
- grey humanoids, before being sent back. Be advised that the kidnapped crewmembers behave strangely upon return to duties."
+ set_antag_hud(alien_mind.current, null)
\ No newline at end of file
diff --git a/code/game/gamemodes/miniantags/morph/morph.dm b/code/game/gamemodes/miniantags/morph/morph.dm
index 158ba09d43c8..6d0759c52bdc 100644
--- a/code/game/gamemodes/miniantags/morph/morph.dm
+++ b/code/game/gamemodes/miniantags/morph/morph.dm
@@ -226,7 +226,6 @@
player_mind.transfer_to(S)
player_mind.assigned_role = "Morph"
player_mind.special_role = "Morph"
- SSticker.mode.traitors |= player_mind
player_mind.add_antag_datum(/datum/antagonist/auto_custom)
to_chat(S, S.playstyle_string)
SEND_SOUND(S, sound('sound/magic/mutate.ogg'))
diff --git a/code/game/gamemodes/miniantags/revenant/revenant.dm b/code/game/gamemodes/miniantags/revenant/revenant.dm
index 002e1b3809c3..0719072077f2 100644
--- a/code/game/gamemodes/miniantags/revenant/revenant.dm
+++ b/code/game/gamemodes/miniantags/revenant/revenant.dm
@@ -86,7 +86,6 @@
to_chat(src, "Objective #2: [objective2.explanation_text]")
mind.assigned_role = "revenant"
mind.special_role = "Revenant"
- SSticker.mode.traitors |= mind //Necessary for announcing
mind.add_antag_datum(/datum/antagonist/auto_custom)
AddSpell(new /obj/effect/proc_holder/spell/targeted/night_vision/revenant(null))
AddSpell(new /obj/effect/proc_holder/spell/targeted/revenant_transmit(null))
diff --git a/code/game/gamemodes/miniantags/slaughter/slaughterevent.dm b/code/game/gamemodes/miniantags/slaughter/slaughterevent.dm
index e62665f21bd7..4ac480b3452e 100644
--- a/code/game/gamemodes/miniantags/slaughter/slaughterevent.dm
+++ b/code/game/gamemodes/miniantags/slaughter/slaughterevent.dm
@@ -37,7 +37,6 @@
player_mind.transfer_to(S)
player_mind.assigned_role = "Slaughter Demon"
player_mind.special_role = "Slaughter Demon"
- SSticker.mode.traitors |= player_mind
player_mind.add_antag_datum(/datum/antagonist/auto_custom)
to_chat(S, S.playstyle_string)
to_chat(S, "You are currently not currently in the same plane of existence as the station. Blood Crawl near a blood pool to manifest.")
diff --git a/code/game/gamemodes/revolution/revolution.dm b/code/game/gamemodes/revolution/revolution.dm
index 71947fc682b7..4c78ecca909a 100644
--- a/code/game/gamemodes/revolution/revolution.dm
+++ b/code/game/gamemodes/revolution/revolution.dm
@@ -96,7 +96,7 @@
for(var/datum/mind/rev_mind in headrev_candidates)
log_game("[rev_mind.key] (ckey) has been selected as a head rev")
- var/datum/antagonist/rev/head/new_head = new(rev_mind)
+ var/datum/antagonist/rev/head/new_head = new()
new_head.give_flash = TRUE
new_head.give_hud = TRUE
new_head.remove_clumsy = TRUE
diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm
index 42c96cb5c0ee..09e31810f167 100644
--- a/code/game/gamemodes/traitor/traitor.dm
+++ b/code/game/gamemodes/traitor/traitor.dm
@@ -61,8 +61,7 @@
/datum/game_mode/traitor/post_setup()
for(var/datum/mind/traitor in pre_traitors)
- var/datum/antagonist/traitor/new_antag = new antag_datum(traitor)
- new_antag.should_specialise = TRUE
+ var/datum/antagonist/traitor/new_antag = new antag_datum()
addtimer(CALLBACK(traitor, /datum/mind.proc/add_antag_datum, new_antag), rand(10,100))
if(!exchange_blue)
exchange_blue = -1 //Block latejoiners from getting exchange objectives
@@ -82,8 +81,7 @@
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(character)
- new_antag.should_specialise = TRUE
+ var/datum/antagonist/traitor/new_antag = new antag_datum()
character.add_antag_datum(new_antag)
/datum/game_mode/traitor/generate_report()
@@ -98,4 +96,4 @@
/datum/game_mode/proc/update_traitor_icons_removed(datum/mind/traitor_mind)
var/datum/atom_hud/antag/traitorhud = GLOB.huds[ANTAG_HUD_TRAITOR]
traitorhud.leave_hud(traitor_mind.current)
- set_antag_hud(traitor_mind.current, null)
+ set_antag_hud(traitor_mind.current, null)
\ No newline at end of file
diff --git a/code/game/machinery/wishgranter.dm b/code/game/machinery/wishgranter.dm
index 59465cf5b2e8..6f0c281730c2 100644
--- a/code/game/machinery/wishgranter.dm
+++ b/code/game/machinery/wishgranter.dm
@@ -39,7 +39,6 @@
user.dna.add_mutation(COLDRES)
user.dna.add_mutation(TK)
- SSticker.mode.traitors += user.mind
user.mind.special_role = "Avatar of the Wish Granter"
var/datum/objective/hijack/hijack = new
diff --git a/code/game/objects/items/devices/doorCharge.dm b/code/game/objects/items/devices/doorCharge.dm
index cf11b2c94122..2fc3770f1ccf 100644
--- a/code/game/objects/items/devices/doorCharge.dm
+++ b/code/game/objects/items/devices/doorCharge.dm
@@ -35,7 +35,7 @@
/obj/item/device/doorCharge/examine(mob/user)
..()
- if(user.mind in SSticker.mode.traitors) //No nuke ops because the device is excluded from nuclear
+ if(user.mind && user.mind.has_antag_datum(/datum/antagonist/traitor)) //No nuke ops because the device is excluded from nuclear
to_chat(user, "A small explosive device that can be used to sabotage airlocks to cause an explosion upon opening. To apply, remove the airlock's maintenance panel and place it within.")
else
to_chat(user, "A small, suspicious object that feels lukewarm when held.")
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index 4c7b8c5b4036..fc4e04f97e2d 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -48,7 +48,10 @@
body += "
\[ "
body += "VV - "
- body += "TP - "
+ if(M.mind)
+ body += "TP - "
+ else
+ body += "Init Mind - "
body += "PM - "
body += "SM - "
body += "FLW - "
@@ -649,7 +652,7 @@
to_chat(usr, "This mob has no mind!")
return
- M.mind.edit_memory()
+ M.mind.traitor_panel()
SSblackbox.record_feedback("tally", "admin_verb", 1, "Traitor Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
diff --git a/code/modules/admin/antag_panel.dm b/code/modules/admin/antag_panel.dm
new file mode 100644
index 000000000000..7546fa85423e
--- /dev/null
+++ b/code/modules/admin/antag_panel.dm
@@ -0,0 +1,217 @@
+GLOBAL_VAR(antag_prototypes)
+
+//Things to do somewhere in the future (If you're reading this feel free to do any of these)
+//Add HrefTokens to these
+//Make this template or at least remove + "
" with joins where you can grasp the big picture.
+//Span classes for the headers, wrap sections in div's and style them.
+//Move common admin commands to /mob (maybe integrate with vv dropdown so the list is one thing with some flag where to show it)
+//Move objective initialization/editing stuff from mind to objectives and completely remove mind.objectives
+
+/proc/cmp_antagpanel(datum/antagonist/A,datum/antagonist/B)
+ var/a_cat = initial(A.antagpanel_category)
+ var/b_cat = initial(B.antagpanel_category)
+ if(!a_cat && !b_cat)
+ return sorttext(initial(A.name),initial(B.name))
+ return sorttext(b_cat,a_cat)
+
+/datum/mind/proc/add_antag_wrapper(antag_type,mob/user)
+ var/datum/antagonist/new_antag = new antag_type()
+ new_antag.admin_add(src,user)
+ //If something gone wrong/admin-add assign another antagonist due to whatever clean it up
+ if(!new_antag.owner)
+ qdel(new_antag)
+
+/proc/listtrim(list/L)
+ for(var/x in L)
+ if(istext(x) && !x)
+ L -= x
+ return L
+
+/datum/antagonist/proc/antag_panel()
+ var/list/commands = list()
+ for(var/command in get_admin_commands())
+ commands += "[command]"
+ var/command_part = commands.Join(" | ")
+ var/data_part = antag_panel_data()
+ var/objective_part = antag_panel_objectives()
+ var/memory_part = antag_panel_memory()
+
+ var/list/parts = listtrim(list(command_part,data_part,objective_part,memory_part))
+
+ return parts.Join("
")
+
+/datum/antagonist/proc/antag_panel_objectives()
+ var/result = "Objectives:
"
+ if (objectives.len == 0)
+ result += "EMPTY
"
+ else
+ var/obj_count = 1
+ for(var/datum/objective/objective in objectives)
+ result += "[obj_count]: [objective.explanation_text] Edit Delete [objective.completed ? "Mark as incomplete" : "Mark as complete"]
"
+ obj_count++
+ result += "Add objective
"
+ result += "Announce objectives
"
+ return result
+
+/datum/antagonist/proc/antag_panel_memory()
+ var/out = "Memory:
"
+ out += antag_memory
+ out += "
Edit memory
"
+ return out
+
+/datum/mind/proc/get_common_admin_commands()
+ var/common_commands = "Common Commands:"
+ if(ishuman(current))
+ common_commands += "undress"
+ else if(iscyborg(current))
+ var/mob/living/silicon/robot/R = current
+ if(R.emagged)
+ common_commands += "Unemag"
+ else if(isAI(current))
+ var/mob/living/silicon/ai/A = current
+ if (A.connected_robots.len)
+ for (var/mob/living/silicon/robot/R in A.connected_robots)
+ if (R.emagged)
+ common_commands += "Unemag slaved cyborgs"
+ break
+ return common_commands
+
+/datum/mind/proc/get_special_statuses()
+ var/list/result = list()
+ if(!current)
+ result += "No body!"
+ if(current && current.isloyal())
+ result += "Mindshielded"
+ //Move these to mob
+ if(iscyborg(current))
+ var/mob/living/silicon/robot/robot = current
+ if (robot.emagged)
+ result += "Emagged"
+ return result.Join(" | ")
+
+/datum/mind/proc/traitor_panel()
+ if(!SSticker.HasRoundStarted())
+ alert("Not before round-start!", "Alert")
+ return
+ if(QDELETED(src))
+ alert("This mind doesn't have a mob, or is deleted! For some reason!", "Edit Memory")
+ return
+
+ var/out = "[name][(current && (current.real_name!=name))?" (as [current.real_name])":""]
"
+ out += "Mind currently owned by key: [key] [active?"(synced)":"(not synced)"]
"
+ out += "Assigned role: [assigned_role]. Edit
"
+ out += "Faction and special role: [special_role]
"
+
+ var/special_statuses = get_special_statuses()
+ if(length(special_statuses))
+ out += get_special_statuses() + "
"
+
+ if(!GLOB.antag_prototypes)
+ GLOB.antag_prototypes = list()
+ for(var/antag_type in subtypesof(/datum/antagonist))
+ var/datum/antagonist/A = new antag_type
+ var/cat_id = A.antagpanel_category
+ if(!GLOB.antag_prototypes[cat_id])
+ GLOB.antag_prototypes[cat_id] = list(A)
+ else
+ GLOB.antag_prototypes[cat_id] += A
+ sortTim(GLOB.antag_prototypes,/proc/cmp_text_asc,associative=TRUE)
+
+ var/list/sections = list()
+ var/list/priority_sections = list()
+
+ for(var/antag_category in GLOB.antag_prototypes)
+ var/category_header = "[antag_category]:"
+ var/list/antag_header_parts = list(category_header)
+
+ var/datum/antagonist/current_antag
+ var/list/possible_admin_antags = list()
+
+ for(var/datum/antagonist/prototype in GLOB.antag_prototypes[antag_category])
+ var/datum/antagonist/A = has_antag_datum(prototype.type)
+ if(A)
+ //We got the antag
+ if(!current_antag)
+ current_antag = A
+ else
+ continue //Let's skip subtypes of what we already shown.
+ else if(prototype.show_in_antagpanel)
+ if(prototype.can_be_owned(src))
+ possible_admin_antags += "[prototype.name]"
+ else
+ possible_admin_antags += "[prototype.name]"
+ else
+ //We don't have it and it shouldn't be shown as an option to be added.
+ continue
+
+ if(!current_antag) //Show antagging options
+ if(possible_admin_antags.len)
+ antag_header_parts += "None"
+ antag_header_parts += possible_admin_antags
+ else
+ //If there's no antags to show in this category skip the section completely
+ continue
+ else //Show removal and current one
+ priority_sections |= antag_category
+ antag_header_parts += "[current_antag.name]"
+ antag_header_parts += "Remove"
+
+
+ //We aren't antag of this category, grab first prototype to check the prefs (This is pretty vague but really not sure how else to do this)
+ var/datum/antagonist/pref_source = current_antag
+ if(!pref_source)
+ for(var/datum/antagonist/prototype in GLOB.antag_prototypes[antag_category])
+ if(!prototype.show_in_antagpanel)
+ continue
+ pref_source = prototype
+ break
+ if(pref_source.job_rank)
+ antag_header_parts += pref_source.enabled_in_preferences(src) ? "Enabled in Prefs" : "Disabled in Prefs"
+
+ //Traitor : None | Traitor | IAA
+ // Command1 | Command2 | Command3
+ // Secret Word : Banana
+ // Objectives:
+ // 1.Do the thing [a][b]
+ // [a][b]
+ // Memory:
+ // Uplink Code: 777 Alpha
+ var/cat_section = antag_header_parts.Join(" | ") + "
"
+ if(current_antag)
+ cat_section += current_antag.antag_panel()
+ sections[antag_category] = cat_section
+
+ for(var/s in priority_sections)
+ out += sections[s]
+ for(var/s in sections - priority_sections)
+ out += sections[s]
+
+ out += "
"
+
+ //Uplink
+ if(ishuman(current))
+ var/uplink_info = "Uplink:"
+ var/datum/component/uplink/U = find_syndicate_uplink()
+ if(U)
+ uplink_info += "take"
+ if (check_rights(R_FUN, 0))
+ uplink_info += ", [U.telecrystals] TC"
+ else
+ uplink_info += ", [U.telecrystals] TC"
+ else
+ uplink_info += "give"
+ uplink_info += "." //hiel grammar
+
+ out += uplink_info + "
"
+ //Common Memory
+ var/common_memory = "Common Memory:"
+ common_memory += memory
+ common_memory += "Edit Memory"
+ out += common_memory + "
"
+ //Other stuff
+ out += get_common_admin_commands()
+
+ var/datum/browser/panel = new(usr, "traitorpanel", "", 600, 600)
+ panel.set_content(out)
+ panel.open()
+ return
\ No newline at end of file
diff --git a/code/modules/admin/check_antagonists.dm b/code/modules/admin/check_antagonists.dm
new file mode 100644
index 000000000000..f1ad21ded3bc
--- /dev/null
+++ b/code/modules/admin/check_antagonists.dm
@@ -0,0 +1,212 @@
+//I wish we had interfaces sigh, and i'm not sure giving team and antag common root is a better solution here
+
+//Name shown on antag list
+/datum/antagonist/proc/antag_listing_name()
+ if(!owner)
+ return "Unassigned"
+ if(owner.current)
+ return "[owner.current.real_name]"
+ else
+ return "[owner.name]"
+
+//Whatever interesting things happened to the antag admins should know about
+//Include additional information about antag in this part
+/datum/antagonist/proc/antag_listing_status()
+ if(!owner)
+ return "(Unassigned)"
+ if(!owner.current)
+ return "(Body destroyed)"
+ else
+ if(owner.current.stat == DEAD)
+ return "(DEAD)"
+ else if(!owner.current.client)
+ return "(No client)"
+
+//Builds the common FLW PM TP commands part
+//Probably not going to be overwritten by anything but you never know
+/datum/antagonist/proc/antag_listing_commands()
+ if(!owner)
+ return
+ var/list/parts = list()
+ parts += "PM"
+ if(owner.current) //There's body to follow
+ parts += "FLW"
+ else
+ parts += ""
+ parts += "Show Objective"
+ return parts //Better as one cell or two/three
+
+//Builds table row for the antag
+// Jim (Status) FLW PM TP
+/datum/antagonist/proc/antag_listing_entry()
+ var/list/parts = list()
+ parts += antag_listing_name()
+ parts += antag_listing_status()
+ parts += antag_listing_commands()
+ return "| [parts.Join(" | ")] |
"
+
+
+/datum/team/proc/get_team_antags(antag_type,specific = FALSE)
+ . = list()
+ for(var/datum/antagonist/A in GLOB.antagonists)
+ if(A.get_team() == src && (!antag_type || !specific && istype(A,antag_type) || specific && A.type == antag_type))
+ . += A
+
+//Builds section for the team
+/datum/team/proc/antag_listing_entry()
+ //NukeOps:
+ // Jim (Status) FLW PM TP
+ // Joe (Status) FLW PM TP
+ //Disk:
+ // Deep Space FLW
+ var/list/parts = list()
+ parts += "[antag_listing_name()]
"
+ parts += ""
+ for(var/datum/antagonist/A in get_team_antags())
+ parts += A.antag_listing_entry()
+ parts += "
"
+ parts += antag_listing_footer()
+ return parts.Join()
+
+/datum/team/proc/antag_listing_name()
+ return name
+
+/datum/team/proc/antag_listing_footer()
+ return
+
+//Moves them to the top of the list if TRUE
+/datum/antagonist/proc/is_gamemode_hero()
+ return FALSE
+
+/datum/team/proc/is_gamemode_hero()
+ return FALSE
+
+/datum/admins/proc/build_antag_listing()
+ var/list/sections = list()
+ var/list/priority_sections = list()
+
+ var/list/all_teams = list()
+ var/list/all_antagonists = list()
+
+ for(var/datum/antagonist/A in GLOB.antagonists)
+ if(!A.owner)
+ continue
+ all_teams |= A.get_team()
+ all_antagonists += A
+
+ for(var/datum/team/T in all_teams)
+ for(var/datum/antagonist/X in all_antagonists)
+ if(X.get_team() == T)
+ all_antagonists -= X
+ if(T.is_gamemode_hero())
+ priority_sections += T.antag_listing_entry()
+ else
+ sections += T.antag_listing_entry()
+
+ sortTim(all_antagonists, /proc/cmp_antag_category)
+
+ var/current_category
+ var/list/current_section = list()
+ for(var/i in 1 to all_antagonists.len)
+ var/datum/antagonist/current_antag = all_antagonists[i]
+ var/datum/antagonist/next_antag
+ if(i < all_antagonists.len)
+ next_antag = all_antagonists[i+1]
+ if(!current_category)
+ current_category = current_antag.roundend_category
+ current_section += "[capitalize(current_category)]
"
+ current_section += ""
+ current_section += current_antag.antag_listing_entry() // Name - (Traitor) - FLW | PM | TP
+
+ if(!next_antag || next_antag.roundend_category != current_antag.roundend_category) //End of section
+ current_section += "
"
+ if(current_antag.is_gamemode_hero())
+ priority_sections += current_section.Join()
+ else
+ sections += current_section.Join()
+ current_section.Cut()
+ current_category = null
+ var/list/all_sections = priority_sections + sections
+ return all_sections.Join("
")
+
+/datum/admins/proc/check_antagonists()
+ if (SSticker.HasRoundStarted())
+ var/dat = "Round StatusRound Status
"
+ if(SSticker.mode.replacementmode)
+ dat += "Former Game Mode: [SSticker.mode.name]
"
+ dat += "Replacement Game Mode: [SSticker.mode.replacementmode.name]
"
+ else
+ dat += "Current Game Mode: [SSticker.mode.name]
"
+ dat += "Round Duration: [DisplayTimeText(world.time - SSticker.round_start_time)]
"
+ dat += "Emergency shuttle
"
+ if(EMERGENCY_IDLE_OR_RECALLED)
+ dat += "Call Shuttle
"
+ else
+ var/timeleft = SSshuttle.emergency.timeLeft()
+ if(SSshuttle.emergency.mode == SHUTTLE_CALL)
+ dat += "ETA: [(timeleft / 60) % 60]:[add_zero(num2text(timeleft % 60), 2)]
"
+ dat += "Send Back
"
+ else
+ dat += "ETA: [(timeleft / 60) % 60]:[add_zero(num2text(timeleft % 60), 2)]
"
+ dat += "Continuous Round Status
"
+ dat += "[CONFIG_GET(keyed_flag_list/continuous)[SSticker.mode.config_tag] ? "Continue if antagonists die" : "End on antagonist death"]"
+ if(CONFIG_GET(keyed_flag_list/continuous)[SSticker.mode.config_tag])
+ dat += ", [CONFIG_GET(keyed_flag_list/midround_antag)[SSticker.mode.config_tag] ? "creating replacement antagonists" : "not creating new antagonists"]
"
+ else
+ dat += "
"
+ if(CONFIG_GET(keyed_flag_list/midround_antag)[SSticker.mode.config_tag])
+ dat += "Time limit: [CONFIG_GET(number/midround_antag_time_check)] minutes into round
"
+ dat += "Living crew limit: [CONFIG_GET(number/midround_antag_life_check) * 100]% of crew alive
"
+ dat += "If limits past: [SSticker.mode.round_ends_with_antag_death ? "End The Round" : "Continue As Extended"]
"
+ dat += "End Round Now
"
+ dat += "[SSticker.delay_end ? "End Round Normally" : "Delay Round End"]"
+ var/connected_players = GLOB.clients.len
+ var/lobby_players = 0
+ var/observers = 0
+ var/observers_connected = 0
+ var/living_players = 0
+ var/living_players_connected = 0
+ var/living_players_antagonist = 0
+ var/brains = 0
+ var/other_players = 0
+ var/living_skipped = 0
+ var/drones = 0
+ for(var/mob/M in GLOB.mob_list)
+ if(M.ckey)
+ if(isnewplayer(M))
+ lobby_players++
+ continue
+ else if(M.stat != DEAD && M.mind && !isbrain(M))
+ if(isdrone(M))
+ drones++
+ continue
+ if(is_centcom_level(M.z))
+ living_skipped++
+ continue
+ living_players++
+ if(M.mind.special_role)
+ living_players_antagonist++
+ if(M.client)
+ living_players_connected++
+ else if(M.stat == DEAD || isobserver(M))
+ observers++
+ if(M.client)
+ observers_connected++
+ else if(isbrain(M))
+ brains++
+ else
+ other_players++
+ dat += "
Players:|[connected_players - lobby_players] ingame|[connected_players] connected|[lobby_players] lobby|"
+ dat += "
Living Players:|[living_players_connected] active|[living_players - living_players_connected] disconnected|[living_players_antagonist] antagonists|"
+ dat += "
SKIPPED \[On centcom Z-level\]: [living_skipped] living players|[drones] living drones|"
+ dat += "
Dead/Observing players:|[observers_connected] active|[observers - observers_connected] disconnected|[brains] brains|"
+ if(other_players)
+ dat += "
[other_players] players in invalid state or the statistics code is bugged!"
+ dat += "
"
+
+ dat += build_antag_listing()
+
+ dat += ""
+ usr << browse(dat, "window=roundstatus;size=500x500")
+ else
+ alert("The game hasn't started yet!")
\ No newline at end of file
diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm
index e38f857cd469..6e15da69ef82 100644
--- a/code/modules/admin/player_panel.dm
+++ b/code/modules/admin/player_panel.dm
@@ -307,342 +307,4 @@