mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-21 12:04:48 +01:00
Refactors antag team code. Adds an admin UI to interact with teams (#19870)
* adds antag team framework code * Apply suggestions from code review Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> * sirryan review * adds the ability for admins to add members * oops Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com>
This commit is contained in:
@@ -172,6 +172,12 @@
|
||||
if(initial(D.name))
|
||||
GLOB.keybindings += new path()
|
||||
|
||||
for(var/path in subtypesof(/datum/objective))
|
||||
var/datum/objective/O = path
|
||||
if(isnull(initial(O.name)))
|
||||
continue // These are not valid objectives to add.
|
||||
GLOB.admin_objective_list[initial(O.name)] = path
|
||||
|
||||
/* // Uncomment to debug chemical reaction list.
|
||||
/client/verb/debug_chemical_list()
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
team_names[team_number] = "Mothership [pick(GLOB.possible_changeling_IDs)]" //TODO Ensure unique and actual alieny names
|
||||
//Team Objective
|
||||
var/datum/objective/experiment/team_objective = new
|
||||
team_objective.abductor_team = team_number
|
||||
team_objective.abductor_team_number = team_number
|
||||
team_objectives[team_number] = team_objective
|
||||
//Team Members
|
||||
|
||||
@@ -238,7 +238,8 @@
|
||||
// OBJECTIVES
|
||||
/datum/objective/experiment
|
||||
target_amount = 6
|
||||
var/abductor_team
|
||||
/// Which abductor team number does this belong to.
|
||||
var/abductor_team_number
|
||||
|
||||
/datum/objective/stay_hidden
|
||||
|
||||
@@ -251,7 +252,7 @@
|
||||
explanation_text = "Experiment on [target_amount] humans."
|
||||
|
||||
/datum/objective/experiment/check_completion()
|
||||
var/ab_team = abductor_team
|
||||
var/ab_team = abductor_team_number
|
||||
var/list/owners = get_owners()
|
||||
for(var/datum/mind/M in owners)
|
||||
if(!M.current || !ishuman(M.current) || !isabductor(M.current))
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
/// Stores a reference to every [objective][/datum/objective] which currently exists.
|
||||
GLOBAL_LIST_EMPTY(all_objectives)
|
||||
// Used in admin procs to give them a pretty list to look at, and to also have sane reusable code.
|
||||
/// Stores objective [names][/datum/objective/var/name] as list keys, and their corresponding typepaths as list values.
|
||||
GLOBAL_LIST_EMPTY(admin_objective_list)
|
||||
|
||||
GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective) - /datum/theft_objective/steal - /datum/theft_objective/number - /datum/theft_objective/unique))
|
||||
|
||||
/datum/objective
|
||||
/**
|
||||
* Proper name of the objective. Not player facing, only shown to admins when adding objectives.
|
||||
* Leave as null (or override to null) if you don't want admins to see that objective as a viable one to add (such as the mindslave objective).
|
||||
*/
|
||||
var/name
|
||||
/**
|
||||
* Owner of the objective.
|
||||
* Note that it's fine to set this directly, but when needing to check completion of the objective or otherwise check conditions on the owner of the objective,
|
||||
@@ -76,13 +85,13 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
|
||||
return ..()
|
||||
|
||||
|
||||
/datum/objective/proc/find_target()
|
||||
/datum/objective/proc/find_target(list/target_blacklist)
|
||||
if(!needs_target)
|
||||
return
|
||||
|
||||
var/list/possible_targets = list()
|
||||
for(var/datum/mind/possible_target in SSticker.minds)
|
||||
if(is_invalid_target(possible_target))
|
||||
if(is_invalid_target(possible_target) || (possible_target in target_blacklist))
|
||||
continue
|
||||
|
||||
possible_targets += possible_target
|
||||
@@ -117,9 +126,10 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
|
||||
M.announce_objectives()
|
||||
|
||||
/datum/objective/assassinate
|
||||
name = "Assassinate"
|
||||
martyr_compatible = 1
|
||||
|
||||
/datum/objective/assassinate/find_target()
|
||||
/datum/objective/assassinate/find_target(list/target_blacklist)
|
||||
..()
|
||||
if(target && target.current)
|
||||
explanation_text = "Assassinate [target.current.real_name], the [target.assigned_role]."
|
||||
@@ -140,9 +150,10 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
|
||||
|
||||
|
||||
/datum/objective/mutiny
|
||||
name = "Mutiny"
|
||||
martyr_compatible = 1
|
||||
|
||||
/datum/objective/mutiny/find_target()
|
||||
/datum/objective/mutiny/find_target(list/target_blacklist)
|
||||
..()
|
||||
if(target && target.current)
|
||||
explanation_text = "Assassinate [target.current.real_name], the [target.assigned_role]."
|
||||
@@ -166,9 +177,10 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
|
||||
qdel(src)
|
||||
|
||||
/datum/objective/maroon
|
||||
name = "Maroon"
|
||||
martyr_compatible = 1
|
||||
|
||||
/datum/objective/maroon/find_target()
|
||||
/datum/objective/maroon/find_target(list/target_blacklist)
|
||||
..()
|
||||
if(target && target.current)
|
||||
explanation_text = "Prevent [target.current.real_name], the [target.assigned_role] from escaping alive."
|
||||
@@ -194,9 +206,10 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
|
||||
|
||||
|
||||
/datum/objective/debrain //I want braaaainssss
|
||||
name = "Debrain"
|
||||
martyr_compatible = 0
|
||||
|
||||
/datum/objective/debrain/find_target()
|
||||
/datum/objective/debrain/find_target(list/target_blacklist)
|
||||
..()
|
||||
if(target && target.current)
|
||||
explanation_text = "Steal the brain of [target.current.real_name] the [target.assigned_role]."
|
||||
@@ -219,9 +232,10 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
|
||||
|
||||
|
||||
/datum/objective/protect //The opposite of killing a dude.
|
||||
name = "Protect"
|
||||
martyr_compatible = 1
|
||||
|
||||
/datum/objective/protect/find_target()
|
||||
/datum/objective/protect/find_target(list/target_blacklist)
|
||||
..()
|
||||
if(target && target.current)
|
||||
explanation_text = "Protect [target.current.real_name], the [target.assigned_role]."
|
||||
@@ -256,6 +270,7 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
|
||||
qdel(src)
|
||||
|
||||
/datum/objective/hijack
|
||||
name = "Hijack"
|
||||
martyr_compatible = 0 //Technically you won't get both anyway.
|
||||
explanation_text = "Hijack the shuttle by escaping on it with no loyalist Nanotrasen crew on board and free. \
|
||||
Syndicate agents, other enemies of Nanotrasen, cyborgs, pets, and cuffed/restrained hostages may be allowed on the shuttle alive. \
|
||||
@@ -271,6 +286,7 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
|
||||
return SSshuttle.emergency.is_hijacked()
|
||||
|
||||
/datum/objective/hijackclone
|
||||
name = "Hijack (with clones)"
|
||||
explanation_text = "Hijack the shuttle by ensuring only you (or your copies) escape."
|
||||
martyr_compatible = 0
|
||||
needs_target = FALSE
|
||||
@@ -303,6 +319,7 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
|
||||
return FALSE
|
||||
|
||||
/datum/objective/block
|
||||
name = "Silicon hijack"
|
||||
explanation_text = "Hijack the shuttle with no loyalist Nanotrasen crew on board and free. \
|
||||
Syndicate agents, other enemies of Nanotrasen, cyborgs, pets, and cuffed/restrained hostages may be allowed on the shuttle alive. \
|
||||
Using the doomsday device successfully is also an option."
|
||||
@@ -322,6 +339,7 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
|
||||
return TRUE
|
||||
|
||||
/datum/objective/escape
|
||||
name = "Escape"
|
||||
explanation_text = "Escape on the shuttle or an escape pod alive and free."
|
||||
needs_target = FALSE
|
||||
|
||||
@@ -350,6 +368,7 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
|
||||
|
||||
|
||||
/datum/objective/escape/escape_with_identity
|
||||
name = null
|
||||
/// Stored because the target's `[mob/var/real_name]` can change over the course of the round.
|
||||
var/target_real_name
|
||||
/// If the objective has an assassinate objective tied to it.
|
||||
@@ -371,7 +390,7 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
|
||||
// If the target is geneless, then it's an invalid target.
|
||||
return HAS_TRAIT(possible_target.current, TRAIT_GENELESS)
|
||||
|
||||
/datum/objective/escape/escape_with_identity/find_target()
|
||||
/datum/objective/escape/escape_with_identity/find_target(list/target_blacklist)
|
||||
..()
|
||||
if(target && target.current)
|
||||
target_real_name = target.current.real_name
|
||||
@@ -413,6 +432,7 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
|
||||
return FALSE
|
||||
|
||||
/datum/objective/die
|
||||
name = "Die a glorious death"
|
||||
explanation_text = "Die a glorious death."
|
||||
needs_target = FALSE
|
||||
|
||||
@@ -428,6 +448,7 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
|
||||
|
||||
|
||||
/datum/objective/survive
|
||||
name = "Survive"
|
||||
explanation_text = "Stay alive until the end."
|
||||
needs_target = FALSE
|
||||
|
||||
@@ -440,11 +461,13 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
|
||||
return TRUE
|
||||
|
||||
/datum/objective/nuclear
|
||||
name = "Nuke station"
|
||||
explanation_text = "Destroy the station with a nuclear device."
|
||||
martyr_compatible = 1
|
||||
needs_target = FALSE
|
||||
|
||||
/datum/objective/steal
|
||||
name = "Steal Item"
|
||||
var/datum/theft_objective/steal_target
|
||||
martyr_compatible = 0
|
||||
var/theft_area
|
||||
@@ -452,7 +475,7 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
|
||||
/datum/objective/steal/proc/get_location()
|
||||
return steal_target.location_override || "an unknown area"
|
||||
|
||||
/datum/objective/steal/find_target()
|
||||
/datum/objective/steal/find_target(list/target_blacklist)
|
||||
var/potential = GLOB.potential_theft_objectives.Copy()
|
||||
while(!steal_target && length(potential))
|
||||
var/thefttype = pick_n_take(potential)
|
||||
@@ -531,6 +554,7 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
|
||||
|
||||
|
||||
/datum/objective/absorb
|
||||
name = "Absorb DNA"
|
||||
needs_target = FALSE
|
||||
|
||||
/datum/objective/absorb/proc/gen_amount_goal(lowbound = 4, highbound = 6)
|
||||
@@ -562,10 +586,11 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
|
||||
return FALSE
|
||||
|
||||
/datum/objective/destroy
|
||||
name = "Destroy AI"
|
||||
martyr_compatible = 1
|
||||
var/target_real_name
|
||||
|
||||
/datum/objective/destroy/find_target()
|
||||
/datum/objective/destroy/find_target(list/target_blacklist)
|
||||
var/list/possible_targets = active_ais(1)
|
||||
var/mob/living/silicon/ai/target_ai = pick(possible_targets)
|
||||
target = target_ai.mind
|
||||
@@ -584,6 +609,7 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
|
||||
return TRUE
|
||||
|
||||
/datum/objective/steal_five_of_type
|
||||
name = "Steal Five Items"
|
||||
explanation_text = "Steal at least five items!"
|
||||
needs_target = FALSE
|
||||
var/list/wanted_items = list()
|
||||
@@ -606,10 +632,12 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
|
||||
return stolen_count >= 5
|
||||
|
||||
/datum/objective/steal_five_of_type/summon_guns
|
||||
name = "Steal Five Guns"
|
||||
explanation_text = "Steal at least five guns!"
|
||||
wanted_items = list(/obj/item/gun)
|
||||
|
||||
/datum/objective/steal_five_of_type/summon_magic
|
||||
name = "Steal Five Artefacts"
|
||||
explanation_text = "Steal at least five magical artefacts!"
|
||||
wanted_items = list()
|
||||
|
||||
@@ -639,6 +667,7 @@ GLOBAL_LIST_INIT(potential_theft_objectives, (subtypesof(/datum/theft_objective)
|
||||
return stolen_count >= 5
|
||||
|
||||
/datum/objective/blood
|
||||
name = "Spread blood"
|
||||
needs_target = FALSE
|
||||
|
||||
/datum/objective/blood/New()
|
||||
|
||||
@@ -363,6 +363,8 @@
|
||||
dat += "ETA: <a href='?_src_=holder;edit_shuttle_time=1'>[(timeleft / 60) % 60]:[add_zero(num2text(timeleft % 60), 2)]</a><BR>"
|
||||
|
||||
dat += "<a href='?src=[UID()];delay_round_end=1'>[SSticker.delay_end ? "End Round Normally" : "Delay Round End"]</a><br>"
|
||||
dat += "<br><b>Antagonist Teams</b><br>"
|
||||
dat += "<a href='?src=[UID()];check_teams=1'>View Teams</a><br>"
|
||||
if(SSticker.mode.syndicates.len)
|
||||
dat += "<br><table cellspacing=5><tr><td><B>Syndicates</B></td><td></td></tr>"
|
||||
for(var/datum/mind/N in SSticker.mode.syndicates)
|
||||
|
||||
@@ -1609,6 +1609,49 @@
|
||||
else if(href_list["check_antagonist"])
|
||||
check_antagonists()
|
||||
|
||||
else if(href_list["check_teams"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
check_teams()
|
||||
|
||||
else if(href_list["team_command"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
var/datum/team/team
|
||||
var/datum/mind/member
|
||||
if(href_list["team"])
|
||||
team = locateUID(href_list["team"])
|
||||
if(QDELETED(team))
|
||||
to_chat(usr, "<span class='warning'>This team doesn't exist anymore!</span>")
|
||||
return
|
||||
if(href_list["member"])
|
||||
member = locateUID(href_list["member"])
|
||||
if(QDELETED(member))
|
||||
to_chat(usr, "<span class='warning'>This team member doesn't exist anymore!</span>")
|
||||
return
|
||||
switch(href_list["team_command"])
|
||||
if("communicate")
|
||||
team.admin_communicate(usr)
|
||||
if("delete_team")
|
||||
message_admins("[key_name_admin(usr)] has deleted the '[team.name]' team.")
|
||||
log_admin("[key_name_admin(usr)] has deleted the '[team.name]' team.")
|
||||
qdel(team)
|
||||
if("rename_team")
|
||||
team.admin_rename_team(usr)
|
||||
if("admin_add_member")
|
||||
team.admin_add_member(usr)
|
||||
if("remove_member")
|
||||
team.admin_remove_member(usr, member)
|
||||
if("view_member")
|
||||
show_player_panel(member.current)
|
||||
if("add_objective")
|
||||
team.admin_add_objective(usr)
|
||||
if("remove_objective")
|
||||
var/datum/objective/O = locateUID(href_list["objective"])
|
||||
if(O)
|
||||
team.admin_remove_objective(usr, O)
|
||||
check_teams()
|
||||
|
||||
else if(href_list["take_question"])
|
||||
var/index = text2num(href_list["take_question"])
|
||||
|
||||
|
||||
@@ -44,7 +44,10 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
assigned_targets = list()
|
||||
|
||||
/datum/antagonist/Destroy(force, ...)
|
||||
QDEL_LIST(objectives)
|
||||
for(var/datum/objective/O as anything in objectives)
|
||||
objectives -= O
|
||||
if(!O.team)
|
||||
qdel(O)
|
||||
remove_owner_from_gamemode()
|
||||
GLOB.antagonists -= src
|
||||
if(!silent)
|
||||
|
||||
@@ -6,14 +6,3 @@
|
||||
continue
|
||||
if(!antag_type || !specific && istype(A, antag_type) || specific && A.type == antag_type)
|
||||
. += A.owner
|
||||
|
||||
//Get all teams [of type team_type]
|
||||
/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
|
||||
|
||||
@@ -1,24 +1,217 @@
|
||||
//A barebones antagonist team.
|
||||
GLOBAL_LIST_EMPTY(antagonist_teams)
|
||||
|
||||
/**
|
||||
* # Antagonist Team
|
||||
*
|
||||
* Datum used by team antagonists to track it's members and objectives the team needs to complete.
|
||||
*/
|
||||
/datum/team
|
||||
var/list/datum/mind/members = list()
|
||||
var/name = "team"
|
||||
var/member_name = "member"
|
||||
var/list/objectives = list() //common objectives, these won't be added or removed automatically, subtypes handle this, this is here for bookkeeping purposes.
|
||||
/// The name of the team.
|
||||
var/name = "Generic Team Name"
|
||||
/// A list of [minds][/datum/mind] who belong to this team.
|
||||
var/list/members
|
||||
/// A list of objectives which all team members share.
|
||||
var/list/objectives
|
||||
/// Type of antag datum members of this team have. Also given to new members added by admins.
|
||||
var/antag_datum_type
|
||||
|
||||
/datum/team/New(starting_members)
|
||||
. = ..()
|
||||
if(starting_members)
|
||||
if(islist(starting_members))
|
||||
for(var/datum/mind/M in starting_members)
|
||||
add_member(M)
|
||||
else
|
||||
add_member(starting_members)
|
||||
/datum/team/New(list/starting_members)
|
||||
..()
|
||||
members = list()
|
||||
objectives = list()
|
||||
if(starting_members && !islist(starting_members))
|
||||
starting_members = list(starting_members)
|
||||
for(var/datum/mind/M as anything in starting_members)
|
||||
add_member(M)
|
||||
GLOB.antagonist_teams += src
|
||||
|
||||
/datum/team/proc/is_solo()
|
||||
return members.len == 1
|
||||
/datum/team/Destroy(force = FALSE, ...)
|
||||
for(var/datum/mind/member as anything in members)
|
||||
remove_member(member)
|
||||
QDEL_LIST(objectives)
|
||||
members.Cut()
|
||||
GLOB.antagonist_teams -= src
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* Adds `new_member` to this team.
|
||||
*
|
||||
* Generally this should ONLY be called by `add_antag_datum()` to ensure proper order of operations.
|
||||
*/
|
||||
/datum/team/proc/add_member(datum/mind/new_member)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
var/datum/antagonist/team_antag = get_antag_datum_from_member(new_member)
|
||||
members |= new_member
|
||||
team_antag.objectives |= objectives
|
||||
|
||||
/**
|
||||
* Removes `member` from this team.
|
||||
*/
|
||||
/datum/team/proc/remove_member(datum/mind/member)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
var/datum/antagonist/A = get_antag_datum_from_member(member)
|
||||
members -= member
|
||||
A.objectives -= objectives
|
||||
|
||||
/**
|
||||
* Adds a new member to this team from a list of players in the round.
|
||||
*/
|
||||
/datum/team/proc/admin_add_member(mob/user)
|
||||
var/list/valid_minds = list()
|
||||
for(var/mob/living/carbon/human/H in GLOB.player_list)
|
||||
if(!H.mind || (H.mind in members))
|
||||
continue
|
||||
valid_minds[H.real_name] = H.mind
|
||||
|
||||
var/name = input(user, "Choose a player to add to this team", "Add Team Member") as null|anything in valid_minds
|
||||
if(!name)
|
||||
to_chat(user, "<span class='warning'>No suitable humanoid targets found!</span>")
|
||||
return
|
||||
|
||||
var/datum/mind/new_member = valid_minds[name]
|
||||
add_member(new_member)
|
||||
|
||||
/**
|
||||
* Adds a team objective to each member's matching antag datum.
|
||||
*/
|
||||
/datum/team/proc/add_objective_to_members(datum/objective/O)
|
||||
for(var/datum/mind/M as anything in members)
|
||||
var/datum/antagonist/A = get_antag_datum_from_member(M)
|
||||
A.objectives |= O
|
||||
|
||||
/**
|
||||
* Remove a team objective from each member's matching antag datum.
|
||||
*/
|
||||
/datum/team/proc/remove_objective_from_members(datum/objective/O)
|
||||
for(var/datum/mind/M as anything in members)
|
||||
var/datum/antagonist/A = get_antag_datum_from_member(M)
|
||||
A.objectives -= O
|
||||
objectives -= O
|
||||
qdel(O)
|
||||
|
||||
/**
|
||||
* Return an antag datum from a member which is linked with this team.
|
||||
*/
|
||||
/datum/team/proc/get_antag_datum_from_member(datum/mind/member)
|
||||
for(var/datum/antagonist/A as anything in member.antag_datums)
|
||||
if(A.get_team() != src)
|
||||
continue
|
||||
return A
|
||||
// If no matching antag datum was found, give them one.
|
||||
if(antag_datum_type)
|
||||
member.add_antag_datum(antag_datum_type, src)
|
||||
|
||||
/**
|
||||
* Allows admins to send a message to all members of this team.
|
||||
*/
|
||||
/datum/team/proc/admin_communicate(mob/user)
|
||||
var/message = input(user, "Enter a message to send to the team:", "Team Message") as text|null
|
||||
if(!message)
|
||||
return
|
||||
|
||||
for(var/datum/mind/M as anything in members)
|
||||
to_chat(M.current, "<font color='#d6000b'><span class='bold'>Admin Team Message ([user.key]): </span><span class='notice'>[message]</span>")
|
||||
|
||||
message_admins("Team Message: [key_name(user)] -> '[name]' team. Message: [message]")
|
||||
log_admin("Team Message: [key_name(user)] -> '[name]' team. Message: [message]")
|
||||
|
||||
/**
|
||||
* Allows admins to add a team objective.
|
||||
*/
|
||||
/datum/team/proc/admin_add_objective(mob/user)
|
||||
var/selected = input("Select an objective type:", "Objective Type") as null|anything in GLOB.admin_objective_list
|
||||
if(!selected)
|
||||
return
|
||||
|
||||
var/objective_type = GLOB.admin_objective_list[selected]
|
||||
var/datum/objective/O = new objective_type(team_to_join = src)
|
||||
O.find_target(members) // Blacklist any team members from being the target.
|
||||
objectives |= O
|
||||
add_objective_to_members(O)
|
||||
|
||||
message_admins("[key_name_admin(user)] added objective [O.type] to the team '[name]'.")
|
||||
log_admin("[key_name(user)] added objective [O.type] to the team '[name]'.")
|
||||
|
||||
/**
|
||||
* Allows admins to remove a team objective.
|
||||
*/
|
||||
/datum/team/proc/admin_remove_objective(mob/user, datum/objective/O)
|
||||
remove_objective_from_members(O)
|
||||
message_admins("[key_name_admin(user)] removed objective [O.type] from the team '[name]'.")
|
||||
log_admin("[key_name(user)] removed objective [O.type] from the team '[name]'.")
|
||||
|
||||
/**
|
||||
* Allows admins to rename the team.
|
||||
*/
|
||||
/datum/team/proc/admin_rename_team(mob/user)
|
||||
var/team_name = stripped_input(user, "Enter a new name for the team:", "Rename Team")
|
||||
if(!team_name)
|
||||
return
|
||||
|
||||
message_admins("[key_name_admin(user)] renamed the '[name]' team to '[team_name]'.")
|
||||
log_admin("[key_name(user)] renamed the '[name]' team to '[team_name]'.")
|
||||
name = team_name
|
||||
|
||||
/**
|
||||
* Allows admins to remove a team member.
|
||||
*/
|
||||
/datum/team/proc/admin_remove_member(mob/user, datum/mind/M)
|
||||
message_admins("[key_name_admin(user)] removed [key_name_admin(M)] from the team '[name]'.")
|
||||
log_admin("[key_name(user)] removed [key_name(M)] from the team '[name]'.")
|
||||
remove_member(M)
|
||||
|
||||
// Used for running team specific admin commands.
|
||||
/datum/team/Topic(href, href_list)
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
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)
|
||||
return
|
||||
|
||||
/**
|
||||
* A list of team-specific admin commands for this team. Should be in the form of `"command" = CALLBACK(x, PROC_REF(some_proc))`.
|
||||
*/
|
||||
/datum/team/proc/get_admin_commands()
|
||||
return list()
|
||||
|
||||
/**
|
||||
* Opens a window which lists the teams for the round.
|
||||
*/
|
||||
/datum/admins/proc/check_teams()
|
||||
if(!SSticker.HasRoundStarted())
|
||||
to_chat(usr, "<span class='warning'>The game hasn't started yet!</span>")
|
||||
return
|
||||
|
||||
var/datum/browser/popup = new(usr, "teams", "Team List", 500, 500)
|
||||
popup.set_content(list_teams())
|
||||
popup.open()
|
||||
|
||||
/**
|
||||
* Returns HTML content for the "check teams" window.
|
||||
*/
|
||||
/datum/admins/proc/list_teams()
|
||||
var/list/content = list()
|
||||
if(!length(GLOB.antagonist_teams))
|
||||
content += "There are currently no antag teams."
|
||||
for(var/datum/team/T as anything in GLOB.antagonist_teams)
|
||||
content += "<h3>[T.name] - [T.type]</h3>"
|
||||
content += "<a href='?_src_=holder;team_command=rename_team;team=[T.UID()]'>Rename Team</a>"
|
||||
content += "<a href='?_src_=holder;team_command=delete_team;team=[T.UID()]'>Delete Team</a>"
|
||||
content += "<a href='?_src_=holder;team_command=communicate;team=[T.UID()]'>Message Team</a>"
|
||||
for(var/command in T.get_admin_commands())
|
||||
// _src_ is T.UID() so it points to `/datum/team/Topic` instead of `/datum/admins/Topic`.
|
||||
content += "<a href='?_src_=[T.UID()];command=[command]'>[command]</a>"
|
||||
content += "<br><br>Objectives:<br><ol>"
|
||||
for(var/datum/objective/O as anything in T.objectives)
|
||||
content += "<li>[O.explanation_text] - <a href='?_src_=holder;team_command=remove_objective;team=[T.UID()];objective=[O.UID()]'>Remove</a></li>"
|
||||
content += "</ol><a href='?_src_=holder;team_command=add_objective;team=[T.UID()]'>Add Objective</a><br><br>"
|
||||
content += "Members: <br><ol>"
|
||||
for(var/datum/mind/M as anything in T.members)
|
||||
content += "<li>[M.name] - <a href='?_src_=holder;team_command=view_member;team=[T.UID()];member=[M.UID()]'>Show Player Panel</a>"
|
||||
content += "<a href='?_src_=holder;team_command=remove_member;team=[T.UID()];member=[M.UID()]'>Remove Member</a></li>"
|
||||
content += "</ol><a href='?_src_=holder;team_command=admin_add_member;team=[T.UID()]'>Add Member</a><hr>"
|
||||
return content.Join()
|
||||
|
||||
Reference in New Issue
Block a user