mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-14 00:23:29 +01:00
Antag datum clean up/refactor (#15084)
This commit is contained in:
@@ -441,7 +441,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
if("traitor")
|
||||
if(new_character.mind.has_antag_datum(/datum/antagonist/traitor))
|
||||
var/datum/antagonist/traitor/T = new_character.mind.has_antag_datum(/datum/antagonist/traitor)
|
||||
T.equip_traitor(src)
|
||||
T.give_uplink()
|
||||
else
|
||||
new_character.mind.add_antag_datum(/datum/antagonist/traitor)
|
||||
if("Wizard")
|
||||
|
||||
@@ -1,32 +1,63 @@
|
||||
GLOBAL_LIST_EMPTY(antagonists)
|
||||
|
||||
/datum/antagonist
|
||||
/// The name of the antagonist.
|
||||
var/name = "Antagonist"
|
||||
var/roundend_category = "other antagonists" //Section of roundend report, datums with same category will be displayed together, also default header for the section
|
||||
var/show_in_roundend = TRUE //Set to false to hide the antagonists from roundend report
|
||||
var/datum/mind/owner //Mind that owns this datum
|
||||
var/silent = FALSE //Silent will prevent the gain/lose texts to show
|
||||
var/can_coexist_with_others = TRUE //Whether or not the person will be able to have more than one datum
|
||||
var/list/typecache_datum_blacklist = list() //List of datums this type can't coexist with
|
||||
/// Section of roundend report, datums with same category will be displayed together, also default header for the section.
|
||||
var/roundend_category = "other antagonists"
|
||||
/// Set to false to hide the antagonists from roundend report.
|
||||
var/show_in_roundend = TRUE
|
||||
/// Mind that owns this datum.
|
||||
var/datum/mind/owner
|
||||
/// Should the owner mob get a greeting text? Determines whether or not the `greet()` proc is called.
|
||||
var/silent = FALSE
|
||||
/// List of antagonist datums that this type can't coexist with.
|
||||
var/list/typecache_datum_blacklist
|
||||
/// Should this datum be deleted when the owner's mind is deleted.
|
||||
var/delete_on_mind_deletion = TRUE
|
||||
/// Used to determine if the player jobbanned from this role. Things like `SPECIAL_ROLE_TRAITOR` should go here to determine the role.
|
||||
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
|
||||
/// Should we replace the role-banned player with a ghost?
|
||||
var/replace_banned = TRUE
|
||||
/// List of objectives connected to this datum.
|
||||
var/list/objectives
|
||||
/// A list of strings which contain [targets][/datum/objective/var/target] of the antagonist's objectives. Used to prevent duplicate objectives.
|
||||
var/list/assigned_targets
|
||||
/// Antagonist datum specific information that appears in the player's notes. Information stored here will be removed when the datum is removed from the player.
|
||||
var/antag_memory
|
||||
/// The special role that will be applied to the owner's `special_role` var. i.e. `SPECIAL_ROLE_TRAITOR`, `SPECIAL_ROLE_VAMPIRE`.
|
||||
var/special_role
|
||||
/// Should we automatically give this antagonist objectives upon them gaining the datum?
|
||||
var/give_objectives = TRUE
|
||||
/// Holds the type of antagonist hud this datum will get, i.e. `ANTAG_HUD_TRAITOR`, `ANTAG_HUD_VAMPIRE`, etc.
|
||||
var/antag_hud_type
|
||||
/// Holds the name of the hud's icon in the .dmi files, i.e "hudtraitor", "hudvampire", etc.
|
||||
var/antag_hud_name
|
||||
/// If the owner is a clown, this text will be displayed to them when they gain this datum.
|
||||
var/clown_gain_text = "You are no longer clumsy."
|
||||
/// If the owner is a clown, this text will be displayed to them when they lose this datum.
|
||||
var/clown_removal_text = "You are clumsy again."
|
||||
/// The url page name for this antagonist, appended to the end of the wiki url in the form of: [GLOB.configuration.url.wiki_url]/index.php/[wiki_page_name]
|
||||
var/wiki_page_name
|
||||
|
||||
/datum/antagonist/New()
|
||||
GLOB.antagonists += src
|
||||
objectives = list()
|
||||
assigned_targets = list()
|
||||
typecache_datum_blacklist = typecacheof(typecache_datum_blacklist)
|
||||
|
||||
/datum/antagonist/Destroy()
|
||||
QDEL_LIST(objectives)
|
||||
GLOB.antagonists -= src
|
||||
if(owner)
|
||||
LAZYREMOVE(owner.antag_datums, src)
|
||||
owner = null
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* Loops through the owner's `antag_datums` list and determines if this one is blacklisted by any others.
|
||||
*
|
||||
* If it's in one of their blacklists, return FALSE. It cannot coexist with the datum we're trying to add here.
|
||||
*/
|
||||
/datum/antagonist/proc/can_be_owned(datum/mind/new_owner)
|
||||
. = TRUE
|
||||
var/datum/mind/tested = new_owner || owner
|
||||
if(tested.has_antag_datum(type))
|
||||
return FALSE
|
||||
@@ -34,76 +65,290 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
var/datum/antagonist/A = i
|
||||
if(is_type_in_typecache(src, A.typecache_datum_blacklist))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
//This will be called in add_antag_datum before owner assignment.
|
||||
//Should return antag datum without owner.
|
||||
/**
|
||||
* This will be called in `add_antag_datum` before owner assignment.
|
||||
*
|
||||
* Should return antagonist datum without owner.
|
||||
*/
|
||||
/datum/antagonist/proc/specialization(datum/mind/new_owner)
|
||||
return src
|
||||
|
||||
/**
|
||||
* Removes antagonist datum effects from the old body and applies it to the new one.
|
||||
*
|
||||
* Called in the`/datum/mind/proc/transfer_to()`.
|
||||
*
|
||||
* Arguments:
|
||||
* * new_body - the new body the antag mob is transferring into.
|
||||
* * old_body - the old body the antag mob is leaving.
|
||||
*/
|
||||
/datum/antagonist/proc/on_body_transfer(mob/living/old_body, mob/living/new_body)
|
||||
remove_innate_effects(old_body)
|
||||
apply_innate_effects(new_body)
|
||||
|
||||
//This handles the application of antag huds/special abilities
|
||||
/datum/antagonist/proc/apply_innate_effects(mob/living/mob_override)
|
||||
/**
|
||||
* This handles the application of antag huds/special abilities.
|
||||
*
|
||||
* Gives the antag mob their assigned hud.
|
||||
* If they're a clown, removes their clumsy mutataion.
|
||||
*
|
||||
* Arguments:
|
||||
* * new_body - the new body that the antag mob is transferring into.
|
||||
*/
|
||||
/datum/antagonist/proc/apply_innate_effects(mob/living/new_body)
|
||||
var/mob/living/L = new_body || owner.current
|
||||
if(antag_hud_type && antag_hud_name)
|
||||
add_antag_hud(L)
|
||||
// If `new_body` exists it means we're only transferring this datum, we don't need to show the clown any text.
|
||||
handle_clown_mutation(L, new_body ? null : clown_gain_text, TRUE)
|
||||
|
||||
/**
|
||||
* This handles the removal of antag huds/special abilities.
|
||||
*
|
||||
* Removes the antag's assigned hud.
|
||||
* If they're a clown, gives them back their clumsy mutataion.
|
||||
*
|
||||
* Arguments:
|
||||
* * old_body - the old body the antag is leaving behind.
|
||||
*/
|
||||
/datum/antagonist/proc/remove_innate_effects(mob/living/old_body)
|
||||
var/mob/living/L = old_body || owner.current
|
||||
if(antag_hud_type && antag_hud_name)
|
||||
remove_antag_hud(L)
|
||||
// If `old_body` exists it means we're only transferring this datum, we don't need to show the clown any text.
|
||||
handle_clown_mutation(L, old_body ? null : clown_removal_text)
|
||||
|
||||
/**
|
||||
* Adds this datum's antag hud to `antag_mob`.
|
||||
*
|
||||
* Arguments:
|
||||
* * antag_mob - the mob to add the antag hud to.
|
||||
*/
|
||||
/datum/antagonist/proc/add_antag_hud(mob/living/antag_mob)
|
||||
var/datum/atom_hud/antag/hud = GLOB.huds[antag_hud_type]
|
||||
hud.join_hud(antag_mob)
|
||||
set_antag_hud(antag_mob, antag_hud_name)
|
||||
|
||||
/**
|
||||
* Removes this datum's antag hud from `antag_mob`.
|
||||
*
|
||||
* Arguments:
|
||||
* * antag_mob - the mob to remove the antag hud from.
|
||||
*/
|
||||
/datum/antagonist/proc/remove_antag_hud(mob/living/antag_mob)
|
||||
var/datum/atom_hud/antag/hud = GLOB.huds[antag_hud_type]
|
||||
hud.leave_hud(antag_mob)
|
||||
set_antag_hud(antag_mob, null)
|
||||
|
||||
/**
|
||||
* Handles adding and removing the clumsy mutation from clown antags.
|
||||
*
|
||||
* Arguments:
|
||||
* * clown - the mob in which to add or remove clumsy from.
|
||||
* * message - the chat message to display to them the clown mob
|
||||
* * granting_datum - TRUE if the datum is being applied to the clown mob.
|
||||
*/
|
||||
/datum/antagonist/proc/handle_clown_mutation(mob/living/carbon/human/clown, message, granting_datum = FALSE)
|
||||
if(!istype(clown) || owner.assigned_role != "Clown")
|
||||
return FALSE
|
||||
|
||||
// Remove clumsy and give them an action to toggle it on and off.
|
||||
if(granting_datum)
|
||||
clown.dna.SetSEState(GLOB.clumsyblock, FALSE)
|
||||
singlemutcheck(clown, GLOB.clumsyblock, MUTCHK_FORCED)
|
||||
// Don't give them another action if they already have one.
|
||||
if(!(locate(/datum/action/innate/toggle_clumsy) in clown.actions))
|
||||
var/datum/action/innate/toggle_clumsy/A = new
|
||||
A.Grant(clown)
|
||||
// Give them back the clumsy gene and remove their toggle action, but ONLY if they don't have any other antag datums.
|
||||
else if(LAZYLEN(owner.antag_datums) <= 1)
|
||||
clown.dna.SetSEState(GLOB.clumsyblock, TRUE)
|
||||
singlemutcheck(clown, GLOB.clumsyblock, MUTCHK_FORCED)
|
||||
if(locate(/datum/action/innate/toggle_clumsy) in clown.actions)
|
||||
var/datum/action/innate/toggle_clumsy/A = locate() in clown.actions
|
||||
A.Remove(clown)
|
||||
else
|
||||
return FALSE
|
||||
|
||||
if(!silent && message)
|
||||
to_chat(clown, "<span class='boldnotice'>[message]</span>")
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Give the antagonist their objectives. Base proc, override as needed.
|
||||
*/
|
||||
/datum/antagonist/proc/give_objectives()
|
||||
return
|
||||
|
||||
//This handles the removal of antag huds/special abilities
|
||||
/datum/antagonist/proc/remove_innate_effects(mob/living/mob_override)
|
||||
return
|
||||
#define NO_TARGET_OBJECTIVES list(/datum/objective/escape, /datum/objective/hijack, /datum/objective/survive, /datum/objective/block, /datum/objective/die)
|
||||
|
||||
//Assign default team and creates one for one of a kind team antagonists
|
||||
/datum/antagonist/proc/create_team(datum/team/team)
|
||||
return
|
||||
/**
|
||||
* Create and add an objective of the given type.
|
||||
*
|
||||
* If the given objective type needs a target, it will try to find a target which isn't already the target of different objective for this antag.
|
||||
* If one cannot be found, it tries one more time. If one still cannot be found, it will be added as a "Free Objective" without a target.
|
||||
*
|
||||
* Arguments:
|
||||
* * objective_type - A type path of an objective, for example: /datum/objective/steal
|
||||
*/
|
||||
/datum/antagonist/proc/add_objective(objective_type)
|
||||
var/datum/objective/O = new objective_type
|
||||
O.owner = owner
|
||||
|
||||
//Proc called when the datum is given to a mind.
|
||||
if(is_type_in_list(O, NO_TARGET_OBJECTIVES))
|
||||
objectives += O // No need to find a target, just add the objective and return.
|
||||
return
|
||||
|
||||
O.find_target()
|
||||
var/duplicate = FALSE
|
||||
|
||||
// Steal objectives need snowflake handling here unfortunately.
|
||||
if(istype(O, /datum/objective/steal))
|
||||
var/datum/objective/steal/S = O
|
||||
// Check if it's a duplicate.
|
||||
if("[S.steal_target]" in assigned_targets)
|
||||
S.find_target() // Try again.
|
||||
if("[S.steal_target]" in assigned_targets)
|
||||
S.steal_target = null
|
||||
S.explanation_text = "Free Objective" // Still a duplicate, so just make it a free objective.
|
||||
duplicate = TRUE
|
||||
if(S.steal_target && !duplicate)
|
||||
assigned_targets += "[S.steal_target]"
|
||||
else
|
||||
if("[O.target]" in assigned_targets)
|
||||
O.find_target()
|
||||
if("[O.target]" in assigned_targets)
|
||||
O.target = null
|
||||
O.explanation_text = "Free Objective"
|
||||
duplicate = TRUE
|
||||
if(O.target && !duplicate)
|
||||
assigned_targets += "[O.target]"
|
||||
|
||||
objectives += O
|
||||
|
||||
#undef NO_TARGET_OBJECTIVES
|
||||
|
||||
/**
|
||||
* Announces all objectives of this datum, and only this datum.
|
||||
*/
|
||||
/datum/antagonist/proc/announce_objectives()
|
||||
if(!length(objectives))
|
||||
return FALSE
|
||||
to_chat(owner.current, "<span class='notice'>Your current objectives:</span>")
|
||||
var/objective_num = 1
|
||||
for(var/objective in objectives)
|
||||
var/datum/objective/O = objective
|
||||
to_chat(owner.current, "<span><B>Objective #[objective_num++]</B>: [O.explanation_text]</span><br>")
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Proc called when the datum is given to a mind.
|
||||
*/
|
||||
/datum/antagonist/proc/on_gain()
|
||||
if(owner && owner.current)
|
||||
if(!silent)
|
||||
greet()
|
||||
apply_innate_effects()
|
||||
if(is_banned(owner.current) && replace_banned)
|
||||
replace_banned_player()
|
||||
owner.special_role = special_role
|
||||
if(give_objectives)
|
||||
give_objectives()
|
||||
if(!silent)
|
||||
greet()
|
||||
announce_objectives()
|
||||
apply_innate_effects()
|
||||
finalize_antag()
|
||||
if(wiki_page_name)
|
||||
to_chat(owner.current, "<span class='motd'>For more information, check the wiki page: ([GLOB.configuration.url.wiki_url]/index.php/[wiki_page_name])</span>")
|
||||
if(is_banned(owner.current) && replace_banned)
|
||||
INVOKE_ASYNC(src, .proc/replace_banned_player)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Called when `remove_antag_datum()` is called on the owner's mind.
|
||||
*
|
||||
* Removes all effects this datum granted and deletes itself afterwards.
|
||||
*/
|
||||
/datum/antagonist/proc/on_removal()
|
||||
if(!silent)
|
||||
farewell()
|
||||
remove_innate_effects()
|
||||
antag_memory = null
|
||||
var/datum/team/team = get_team()
|
||||
team?.remove_member(owner)
|
||||
LAZYREMOVE(owner.antag_datums, src)
|
||||
restore_last_hud_and_role()
|
||||
qdel(src)
|
||||
|
||||
/**
|
||||
* Re-sets the antag hud and `special_role` of the owner to that of the previous antag datum they had before this one was added.
|
||||
*
|
||||
* For example, if the owner has a traitor datum and a vampire datum, both at index 1 and 2 respectively,
|
||||
* After the vampire datum gets removed, it sets the owner's antag hud/role to whatever is set for traitor datum.
|
||||
*/
|
||||
/datum/antagonist/proc/restore_last_hud_and_role()
|
||||
if(!LAZYLEN(owner.antag_datums))
|
||||
// If they only had 1 antag datum, no need to restore anything. `remove_innate_effects()` will handle the removal of their hud.
|
||||
owner.special_role = null
|
||||
return FALSE
|
||||
var/datum/antagonist/A = owner.antag_datums[LAZYLEN(owner.antag_datums)]
|
||||
ASSERT(A)
|
||||
A.add_antag_hud(owner.current) // Restore the hud of the previous antagonist datum.
|
||||
owner.special_role = A.special_role
|
||||
|
||||
/**
|
||||
* Checks if the person trying to recieve this datum is role banned from it.
|
||||
*/
|
||||
/datum/antagonist/proc/is_banned(mob/M)
|
||||
if(!M)
|
||||
return FALSE
|
||||
. = (jobban_isbanned(M, ROLE_SYNDICATE) || (job_rank && jobban_isbanned(M, job_rank)))
|
||||
return (jobban_isbanned(M, ROLE_SYNDICATE) || (job_rank && jobban_isbanned(M, job_rank)))
|
||||
|
||||
/**
|
||||
* Attempts to replace the role banned antag with a ghost player.
|
||||
*/
|
||||
/datum/antagonist/proc/replace_banned_player()
|
||||
set waitfor = FALSE
|
||||
|
||||
var/list/mob/dead/observer/candidates = SSghost_spawns.poll_candidates("Do you want to play as a [name]?", job_rank, TRUE, 5 SECONDS)
|
||||
if(length(candidates))
|
||||
var/mob/dead/observer/C = pick(candidates)
|
||||
to_chat(owner, "Your mob has been taken over by a ghost! Appeal your job ban if you want to avoid this in the future!")
|
||||
message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(owner.current)]) to replace a jobbaned player.")
|
||||
owner.current.ghostize(0)
|
||||
owner.current.key = C.key
|
||||
|
||||
/datum/antagonist/proc/on_removal()
|
||||
remove_innate_effects()
|
||||
if(owner)
|
||||
LAZYREMOVE(owner.antag_datums, src)
|
||||
if(!silent && owner.current)
|
||||
farewell()
|
||||
owner.objectives -= objectives
|
||||
var/datum/team/team = get_team()
|
||||
if(team)
|
||||
team.remove_member(owner)
|
||||
qdel(src)
|
||||
var/list/mob/dead/observer/candidates = SSghost_spawns.poll_candidates("Do you want to play as a [name]?", job_rank, TRUE, 10 SECONDS)
|
||||
if(!length(candidates))
|
||||
return FALSE
|
||||
var/mob/dead/observer/C = pick(candidates)
|
||||
to_chat(owner, "Your mob has been taken over by a ghost! Appeal your job ban if you want to avoid this in the future!")
|
||||
message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(owner.current)]) to replace a jobbaned player.")
|
||||
owner.current.ghostize(FALSE)
|
||||
owner.current.key = C.key
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Displays a message and their objectives to the antag mob after the datum is added to them, i.e. "Greetings you are a traitor! etc.
|
||||
*
|
||||
* Called in `on_gain()` if silent it set to FALSE.
|
||||
*/
|
||||
/datum/antagonist/proc/greet()
|
||||
return
|
||||
to_chat(owner.current, "<span class='userdanger'>You are a [special_role]!</span>")
|
||||
|
||||
/**
|
||||
* Displays a message to the antag mob while the datum is being deleted, i.e. "Your powers are gone and you're no longer a vampire!"
|
||||
*
|
||||
* Called in `on_removal()` if silent is set to FALSE.
|
||||
*/
|
||||
/datum/antagonist/proc/farewell()
|
||||
to_chat(owner.current,"<span class='userdanger'>You are no longer a [special_role]! </span>")
|
||||
|
||||
/**
|
||||
* Creates a new antagonist team.
|
||||
*/
|
||||
/datum/antagonist/proc/create_team(datum/team/team)
|
||||
return
|
||||
|
||||
|
||||
//Returns the team antagonist belongs to if any.
|
||||
/**
|
||||
* Returns the team the antagonist belongs to, if any.
|
||||
*/
|
||||
/datum/antagonist/proc/get_team()
|
||||
return
|
||||
|
||||
/**
|
||||
* Give the antag any final information or items.
|
||||
*/
|
||||
/datum/antagonist/proc/finalize_antag()
|
||||
return
|
||||
|
||||
//Individual roundend report
|
||||
/datum/antagonist/proc/roundend_report()
|
||||
var/list/report = list()
|
||||
|
||||
@@ -4,52 +4,86 @@
|
||||
name = "Mindslave"
|
||||
roundend_category = "mindslaves"
|
||||
job_rank = SPECIAL_ROLE_TRAITOR
|
||||
var/special_role = SPECIAL_ROLE_TRAITOR
|
||||
special_role = SPECIAL_ROLE_TRAITOR
|
||||
antag_hud_type = ANTAG_HUD_TRAITOR
|
||||
antag_hud_name = "mindslave" // This isn't named "hudmindslave" because `add_serve_hud()` adds "hud" to the beginning.
|
||||
clown_gain_text = "Your syndicate training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself."
|
||||
clown_removal_text = "You lose your syndicate training and return to your own clumsy, clownish self."
|
||||
/// A reference to the mind who minslaved us.
|
||||
var/datum/mind/master
|
||||
/// Custom greeting text if you don't want to use the basic greeting. Specify this when making a new mindslave datum with `New()`.
|
||||
var/greet_text
|
||||
|
||||
/datum/antagonist/mindslave/New(datum/mind/_master, _greet_text)
|
||||
if(!_master)
|
||||
stack_trace("[type] created without a \"_master\" argument.")
|
||||
qdel(src)
|
||||
return
|
||||
master = _master
|
||||
greet_text = _greet_text
|
||||
return ..()
|
||||
|
||||
/datum/antagonist/mindslave/on_gain()
|
||||
owner.special_role = special_role
|
||||
// Will print the most recent objective which is probably going the mindslave objective
|
||||
to_chat(owner.current, "<b>New Objective:</b> [owner.objectives[owner.objectives.len].explanation_text]")
|
||||
update_mindslave_icons_added()
|
||||
SSticker.mode.implanted[owner] = master
|
||||
|
||||
var/datum/mindslaves/slaved = master.som
|
||||
if(!slaved) // If the master didn't already have this, we need to make a new mindslaves datum.
|
||||
slaved = new
|
||||
slaved.masters += master
|
||||
master.som = slaved
|
||||
|
||||
// Update our master's HUD to give him the "M" icon.
|
||||
// Basically a copy and paste of what's in [/datum/antagonist/proc/add_antag_hud] in case the master doesn't have a traitor datum.
|
||||
var/datum/atom_hud/antag/hud = GLOB.huds[ANTAG_HUD_TRAITOR]
|
||||
hud.join_hud(master.current)
|
||||
set_antag_hud(master.current, "hudmaster")
|
||||
slaved.add_serv_hud(master, "master")
|
||||
|
||||
// Add an obey and protect objective.
|
||||
var/datum/objective/protect/serve_objective = new
|
||||
serve_objective.target = master
|
||||
serve_objective.owner = owner
|
||||
var/role = master.assigned_role ? master.assigned_role : master.special_role
|
||||
serve_objective.explanation_text = "Obey every order from and protect [master.current.real_name], the [role]."
|
||||
objectives += serve_objective
|
||||
return ..()
|
||||
|
||||
/datum/antagonist/mindslave/on_removal()
|
||||
if(owner.som)
|
||||
var/datum/mindslaves/slaved = owner.som
|
||||
slaved.serv -= owner
|
||||
slaved.leave_serv_hud(owner)
|
||||
antag_memory = ""
|
||||
owner.special_role = null
|
||||
update_mindslave_icons_removed()
|
||||
..()
|
||||
master = null
|
||||
return ..()
|
||||
|
||||
/datum/antagonist/mindslave/apply_innate_effects()
|
||||
/datum/antagonist/mindslave/greet()
|
||||
var/mob/living/carbon/human/mindslave = owner.current
|
||||
// Show them the custom greeting text if it exists.
|
||||
if(greet_text)
|
||||
to_chat(mindslave, "<span class='biggerdanger'>[greet_text]</span>")
|
||||
else // Default greeting text if nothing is given.
|
||||
to_chat(mindslave, "<span class='biggerdanger'><B>You are now completely loyal to [master.current.name]!</B> \
|
||||
You must lay down your life to protect [master.current.p_them()] and assist in [master.current.p_their()] goals at any cost.</span>")
|
||||
|
||||
/datum/antagonist/mindslave/farewell()
|
||||
to_chat(owner.current, "<span class='biggerdanger'>You are no longer a mindslave of [master.current]!</span>")
|
||||
|
||||
/datum/antagonist/mindslave/add_antag_hud(mob/living/antag_mob)
|
||||
. = ..()
|
||||
if(owner.assigned_role == "Clown")
|
||||
var/mob/living/carbon/human/slave_mob = owner.current
|
||||
if(slave_mob && istype(slave_mob))
|
||||
to_chat(slave_mob, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
|
||||
slave_mob.dna.SetSEState(GLOB.clumsyblock, FALSE)
|
||||
singlemutcheck(slave_mob, GLOB.clumsyblock, MUTCHK_FORCED)
|
||||
// Make the mindslave hud icon show to the mindslave.
|
||||
var/datum/mindslaves/slaved = master.som
|
||||
owner.som = slaved
|
||||
slaved.serv += owner
|
||||
slaved.add_serv_hud(owner, antag_hud_name)
|
||||
|
||||
/datum/antagonist/mindslave/remove_innate_effects()
|
||||
/datum/antagonist/mindslave/remove_antag_hud(mob/living/antag_mob)
|
||||
. = ..()
|
||||
if(owner.assigned_role == "Clown")
|
||||
var/mob/living/carbon/human/slave_mob = owner.current
|
||||
if(slave_mob && istype(slave_mob))
|
||||
slave_mob.dna.SetSEState(GLOB.clumsyblock, TRUE)
|
||||
singlemutcheck(slave_mob, GLOB.clumsyblock, MUTCHK_FORCED)
|
||||
// Remove the mindslave antag hud from the mindslave.
|
||||
var/datum/mindslaves/slaved = owner.som
|
||||
slaved.serv -= owner
|
||||
slaved.leave_serv_hud(owner)
|
||||
owner.som = null
|
||||
|
||||
/datum/antagonist/mindslave/proc/add_objective(datum/objective/O)
|
||||
owner.objectives += O
|
||||
|
||||
/datum/antagonist/mindslave/proc/remove_objective(datum/objective/O)
|
||||
owner.objectives -= O
|
||||
|
||||
/datum/antagonist/mindslave/proc/update_mindslave_icons_added()
|
||||
var/datum/atom_hud/antag/traitorhud = GLOB.huds[ANTAG_HUD_TRAITOR]
|
||||
traitorhud.join_hud(owner.current, null)
|
||||
set_antag_hud(owner.current, "hudmindslave")
|
||||
|
||||
/datum/antagonist/mindslave/proc/update_mindslave_icons_removed()
|
||||
var/datum/atom_hud/antag/traitorhud = GLOB.huds[ANTAG_HUD_TRAITOR]
|
||||
traitorhud.leave_hud(owner.current, null)
|
||||
// Helper proc that determines if a mob is a mindslave.
|
||||
/proc/ismindslave(mob/living/carbon/human/H)
|
||||
return istype(H) && H.mind.has_antag_datum(/datum/antagonist/mindslave, FALSE)
|
||||
|
||||
@@ -1,40 +1,33 @@
|
||||
#define TRAITOR_HUMAN "human"
|
||||
#define TRAITOR_AI "AI"
|
||||
|
||||
// For "Actual traitors"
|
||||
// Syndicate Traitors.
|
||||
/datum/antagonist/traitor
|
||||
name = "Traitor"
|
||||
roundend_category = "traitors"
|
||||
job_rank = ROLE_TRAITOR
|
||||
var/special_role = SPECIAL_ROLE_TRAITOR
|
||||
var/give_objectives = TRUE
|
||||
var/should_give_codewords = TRUE
|
||||
var/should_equip = TRUE
|
||||
var/traitor_kind = TRAITOR_HUMAN
|
||||
var/list/assigned_targets = list() // This includes assassinate as well as steal objectives. prevents duplicate objectives
|
||||
special_role = SPECIAL_ROLE_TRAITOR
|
||||
give_objectives = TRUE
|
||||
antag_hud_name = "hudsyndicate"
|
||||
antag_hud_type = ANTAG_HUD_TRAITOR
|
||||
clown_gain_text = "Your syndicate training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself."
|
||||
clown_removal_text = "You lose your syndicate training and return to your own clumsy, clownish self."
|
||||
wiki_page_name = "Traitor"
|
||||
/// Should the traitor get codewords?
|
||||
var/give_codewords = TRUE
|
||||
/// Should we give the traitor their uplink?
|
||||
var/give_uplink = TRUE
|
||||
|
||||
/datum/antagonist/traitor/on_gain()
|
||||
if(owner.current && isAI(owner.current))
|
||||
traitor_kind = TRAITOR_AI
|
||||
|
||||
var/datum/mindslaves/slaved = new()
|
||||
slaved.masters += owner
|
||||
owner.som = slaved //we MIGHT want to mindslave someone
|
||||
SSticker.mode.traitors += owner
|
||||
owner.special_role = special_role
|
||||
|
||||
if(give_objectives)
|
||||
forge_traitor_objectives()
|
||||
if(!silent)
|
||||
greet()
|
||||
apply_innate_effects()
|
||||
update_traitor_icons_added()
|
||||
finalize_traitor()
|
||||
// Create this in case the traitor wants to mindslaves someone.
|
||||
if(!owner.som)
|
||||
owner.som = new /datum/mindslaves
|
||||
|
||||
owner.som.masters += owner
|
||||
SSticker.mode.traitors |= owner
|
||||
return ..()
|
||||
|
||||
/datum/antagonist/traitor/on_removal()
|
||||
//Remove malf powers.
|
||||
if(traitor_kind == TRAITOR_AI && owner.current && isAI(owner.current))
|
||||
// Remove all associated malf AI abilities.
|
||||
if(isAI(owner.current))
|
||||
var/mob/living/silicon/ai/A = owner.current
|
||||
A.clear_zeroth_law()
|
||||
A.common_radio.channels.Remove("Syndicate") // De-traitored AIs can still state laws over the syndicate channel without this
|
||||
@@ -43,245 +36,106 @@
|
||||
A.remove_malf_abilities()
|
||||
QDEL_NULL(A.malf_picker)
|
||||
|
||||
// Leave the mindslave hud.
|
||||
if(owner.som)
|
||||
var/datum/mindslaves/slaved = owner.som
|
||||
slaved.masters -= owner
|
||||
slaved.serv -= owner
|
||||
owner.som = null
|
||||
slaved.leave_serv_hud(owner)
|
||||
owner.som = null
|
||||
|
||||
owner.current.client.chatOutput?.clear_syndicate_codes()
|
||||
assigned_targets.Cut()
|
||||
SSticker.mode.traitors -= owner
|
||||
owner.special_role = null
|
||||
remove_innate_effects()
|
||||
update_traitor_icons_removed()
|
||||
return ..()
|
||||
|
||||
if(!silent && owner.current)
|
||||
antag_memory = ""
|
||||
to_chat(owner.current,"<span class='userdanger'> You are no longer a [special_role]! </span>")
|
||||
..()
|
||||
|
||||
|
||||
/datum/antagonist/traitor/apply_innate_effects()
|
||||
. = ..()
|
||||
if(owner.assigned_role == "Clown")
|
||||
var/mob/living/carbon/human/traitor_mob = owner.current
|
||||
if(traitor_mob && istype(traitor_mob))
|
||||
to_chat(traitor_mob, "<span class='warning'>Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.</span>")
|
||||
traitor_mob.dna.SetSEState(GLOB.clumsyblock, FALSE)
|
||||
singlemutcheck(traitor_mob, GLOB.clumsyblock, MUTCHK_FORCED)
|
||||
var/datum/action/innate/toggle_clumsy/A = new
|
||||
A.Grant(traitor_mob)
|
||||
|
||||
|
||||
/datum/antagonist/traitor/remove_innate_effects()
|
||||
. = ..()
|
||||
if(owner.assigned_role == "Clown")
|
||||
var/mob/living/carbon/human/traitor_mob = owner.current
|
||||
if(traitor_mob && istype(traitor_mob))
|
||||
to_chat(traitor_mob, "<span class='warning'>You lose your syndicate training and return to your own clumsy, clownish self.</span>")
|
||||
traitor_mob.dna.SetSEState(GLOB.clumsyblock, TRUE)
|
||||
singlemutcheck(traitor_mob, GLOB.clumsyblock, MUTCHK_FORCED)
|
||||
for(var/datum/action/innate/A in traitor_mob.actions)
|
||||
if(istype(A, /datum/action/innate/toggle_clumsy))
|
||||
A.Remove(traitor_mob)
|
||||
|
||||
// Adding/removing objectives in the owner's mind until we can datumize all antags. Then we can use the /datum/antagonist/objectives var to handle them
|
||||
// Change "owner.objectives" to "objectives" once objectives are handled in antag datums instead of the mind
|
||||
/datum/antagonist/traitor/proc/add_objective(datum/objective/O)
|
||||
owner.objectives += O
|
||||
|
||||
/datum/antagonist/traitor/proc/remove_objective(datum/objective/O)
|
||||
owner.objectives -= O
|
||||
|
||||
|
||||
/datum/antagonist/traitor/proc/forge_traitor_objectives()
|
||||
switch(traitor_kind)
|
||||
if(TRAITOR_AI)
|
||||
forge_ai_objectives()
|
||||
else
|
||||
forge_human_objectives()
|
||||
/datum/antagonist/traitor/add_antag_hud(mob/living/antag_mob)
|
||||
var/is_contractor = LAZYACCESS(GLOB.contractors, owner)
|
||||
if(locate(/datum/objective/hijack) in owner.get_all_objectives())
|
||||
antag_hud_name = is_contractor ? "hudhijackcontractor" : "hudhijack"
|
||||
else
|
||||
antag_hud_name = is_contractor ? "hudcontractor" : "hudsyndicate"
|
||||
return ..()
|
||||
|
||||
/datum/antagonist/traitor/give_objectives()
|
||||
if(isAI(owner.current))
|
||||
forge_ai_objectives()
|
||||
else
|
||||
forge_human_objectives()
|
||||
|
||||
/**
|
||||
* Create and assign a full set of randomized human traitor objectives.
|
||||
*/
|
||||
/datum/antagonist/traitor/proc/forge_human_objectives()
|
||||
var/is_hijacker = prob(10)
|
||||
var/martyr_chance = prob(20)
|
||||
var/objective_count = is_hijacker //Hijacking counts towards number of objectives
|
||||
if(!SSticker.mode.exchange_blue && SSticker.mode.traitors.len >= 8) //Set up an exchange if there are enough traitors
|
||||
if(!SSticker.mode.exchange_red)
|
||||
SSticker.mode.exchange_red = owner
|
||||
else
|
||||
SSticker.mode.exchange_blue = owner
|
||||
assign_exchange_role(SSticker.mode.exchange_red)
|
||||
assign_exchange_role(SSticker.mode.exchange_blue)
|
||||
objective_count += 1 //Exchange counts towards number of objectives
|
||||
// Hijack objective.
|
||||
if(prob(10) && !(locate(/datum/objective/hijack) in owner.get_all_objectives()))
|
||||
add_objective(/datum/objective/hijack)
|
||||
return // Hijack should be their only objective (normally), so return.
|
||||
|
||||
// Will give normal steal/kill/etc. type objectives.
|
||||
for(var/i in 1 to GLOB.configuration.gamemode.traitor_objectives_amount)
|
||||
forge_single_human_objective()
|
||||
|
||||
var/objective_amount = GLOB.configuration.gamemode.traitor_objectives_amount
|
||||
// Die a glorious death objective.
|
||||
if(prob(20))
|
||||
var/martyr_compatibility = TRUE
|
||||
for(var/objective in owner.get_all_objectives())
|
||||
var/datum/objective/O = objective
|
||||
if(!O.martyr_compatible) // Check if our current objectives can co-exist with martyr.
|
||||
martyr_compatibility = FALSE
|
||||
break
|
||||
|
||||
if(is_hijacker && objective_count <= objective_amount) //Don't assign hijack if it would exceed the number of objectives set in config.traitor_objectives_amount
|
||||
if (!(locate(/datum/objective/hijack) in objectives))
|
||||
var/datum/objective/hijack/hijack_objective = new
|
||||
hijack_objective.owner = owner
|
||||
add_objective(hijack_objective)
|
||||
if(martyr_compatibility)
|
||||
add_objective(/datum/objective/die)
|
||||
return
|
||||
|
||||
for(var/i = objective_count, i < objective_amount)
|
||||
i += forge_single_objective()
|
||||
|
||||
var/martyr_compatibility = 1 //You can't succeed in stealing if you're dead.
|
||||
for(var/datum/objective/O in owner.objectives)
|
||||
if(!O.martyr_compatible)
|
||||
martyr_compatibility = 0
|
||||
break
|
||||
|
||||
if(martyr_compatibility && martyr_chance)
|
||||
var/datum/objective/die/martyr_objective = new
|
||||
martyr_objective.owner = owner
|
||||
add_objective(martyr_objective)
|
||||
return
|
||||
|
||||
if(!(locate(/datum/objective/escape) in objectives))
|
||||
var/datum/objective/escape/escape_objective = new
|
||||
escape_objective.owner = owner
|
||||
add_objective(escape_objective)
|
||||
return
|
||||
|
||||
// Give them an escape objective if they don't have one already.
|
||||
if(!(locate(/datum/objective/escape) in owner.get_all_objectives()))
|
||||
add_objective(/datum/objective/escape)
|
||||
|
||||
/**
|
||||
* Create and assign a full set of AI traitor objectives.
|
||||
*/
|
||||
/datum/antagonist/traitor/proc/forge_ai_objectives()
|
||||
var/objective_count = 0
|
||||
var/try_again = TRUE
|
||||
add_objective(/datum/objective/block)
|
||||
add_objective(/datum/objective/assassinate)
|
||||
add_objective(/datum/objective/survive)
|
||||
|
||||
objective_count += forge_single_objective()
|
||||
|
||||
for(var/i = objective_count, i < GLOB.configuration.gamemode.traitor_objectives_amount)
|
||||
var/datum/objective/assassinate/kill_objective = new
|
||||
kill_objective.owner = owner
|
||||
kill_objective.find_target()
|
||||
if("[kill_objective.target]" in assigned_targets) // In the rare case the game can't find a target for the AI thats not a duplicate
|
||||
if(try_again) // It will attempt to location another target ONCE
|
||||
try_again = FALSE // This code will really only come into play on lowpop rounds where getting duplicate targets is more common
|
||||
continue
|
||||
assigned_targets.Add("[kill_objective.target]")
|
||||
add_objective(kill_objective)
|
||||
i += 1
|
||||
var/datum/objective/survive/survive_objective = new
|
||||
survive_objective.owner = owner
|
||||
add_objective(survive_objective)
|
||||
|
||||
|
||||
/datum/antagonist/traitor/proc/forge_single_objective()
|
||||
switch(traitor_kind)
|
||||
if(TRAITOR_AI)
|
||||
return forge_single_AI_objective()
|
||||
else
|
||||
return forge_single_human_objective()
|
||||
|
||||
|
||||
/datum/antagonist/traitor/proc/forge_single_human_objective() // Returns how many objectives are added
|
||||
. = 1
|
||||
/**
|
||||
* Create and assign a single randomized human traitor objective.
|
||||
*/
|
||||
/datum/antagonist/traitor/proc/forge_single_human_objective()
|
||||
if(prob(50))
|
||||
var/list/active_ais = active_ais()
|
||||
if(active_ais.len && prob(100/GLOB.player_list.len))
|
||||
var/datum/objective/destroy/destroy_objective = new
|
||||
destroy_objective.owner = owner
|
||||
destroy_objective.find_target()
|
||||
if("[destroy_objective]" in assigned_targets) // Is this target already in their list of assigned targets? If so, don't add this objective and return
|
||||
return 0
|
||||
else if(destroy_objective.target) // Is the target a real one and not null? If so, add it to our list of targets to avoid duplicate targets
|
||||
assigned_targets.Add("[destroy_objective.target]") // This logic is applied to all traitor objectives including steal objectives
|
||||
add_objective(destroy_objective)
|
||||
|
||||
if(length(active_ais()) && prob(100 / length(GLOB.player_list)))
|
||||
add_objective(/datum/objective/destroy)
|
||||
else if(prob(5))
|
||||
var/datum/objective/debrain/debrain_objective = new
|
||||
debrain_objective.owner = owner
|
||||
debrain_objective.find_target()
|
||||
if("[debrain_objective]" in assigned_targets)
|
||||
return 0
|
||||
else if(debrain_objective.target)
|
||||
assigned_targets.Add("[debrain_objective.target]")
|
||||
add_objective(debrain_objective)
|
||||
|
||||
add_objective(/datum/objective/debrain)
|
||||
else if(prob(30))
|
||||
var/datum/objective/maroon/maroon_objective = new
|
||||
maroon_objective.owner = owner
|
||||
maroon_objective.find_target()
|
||||
if("[maroon_objective]" in assigned_targets)
|
||||
return 0
|
||||
else if(maroon_objective.target)
|
||||
assigned_targets.Add("[maroon_objective.target]")
|
||||
add_objective(maroon_objective)
|
||||
|
||||
add_objective(/datum/objective/maroon)
|
||||
else
|
||||
var/datum/objective/assassinate/kill_objective = new
|
||||
kill_objective.owner = owner
|
||||
kill_objective.find_target()
|
||||
if("[kill_objective.target]" in assigned_targets)
|
||||
return 0
|
||||
else if(kill_objective.target)
|
||||
assigned_targets.Add("[kill_objective.target]")
|
||||
add_objective(kill_objective)
|
||||
|
||||
add_objective(/datum/objective/assassinate)
|
||||
else
|
||||
var/datum/objective/steal/steal_objective = new
|
||||
steal_objective.owner = owner
|
||||
steal_objective.find_target()
|
||||
if("[steal_objective.steal_target]" in assigned_targets)
|
||||
return 0
|
||||
else if(steal_objective.steal_target)
|
||||
assigned_targets.Add("[steal_objective.steal_target]")
|
||||
add_objective(steal_objective)
|
||||
add_objective(/datum/objective/steal)
|
||||
|
||||
|
||||
/datum/antagonist/traitor/proc/forge_single_AI_objective()
|
||||
. = 1
|
||||
var/datum/objective/block/block_objective = new
|
||||
block_objective.owner = owner
|
||||
add_objective(block_objective)
|
||||
|
||||
|
||||
/datum/antagonist/traitor/greet()
|
||||
to_chat(owner.current, "<B><font size=3 color=red>You are a [owner.special_role]!</font></B>")
|
||||
if(!LAZYLEN(owner.objectives)) // Remove "owner" when objectives are handled in the datum
|
||||
to_chat(owner.current, "<span>You don't have any objectives right now.</span>")
|
||||
else
|
||||
owner.announce_objectives()
|
||||
if(should_give_codewords)
|
||||
/**
|
||||
* Give human traitors their uplink, and AI traitors their law 0. Play the traitor an alert sound.
|
||||
*/
|
||||
/datum/antagonist/traitor/finalize_antag()
|
||||
if(give_codewords)
|
||||
give_codewords()
|
||||
to_chat(owner.current, "<span class='motd'>For more information, check the wiki page: ([GLOB.configuration.url.wiki_url]/index.php/Traitor)</span>")
|
||||
|
||||
|
||||
/datum/antagonist/traitor/proc/update_traitor_icons_added(datum/mind/traitor_mind)
|
||||
var/is_contractor = LAZYACCESS(GLOB.contractors, traitor_mind)
|
||||
if(locate(/datum/objective/hijack) in owner.objectives)
|
||||
var/datum/atom_hud/antag/hijackhud = GLOB.huds[ANTAG_HUD_TRAITOR]
|
||||
hijackhud.join_hud(owner.current, null)
|
||||
set_antag_hud(owner.current, is_contractor ? "hudhijackcontractor" : "hudhijack")
|
||||
if(isAI(owner.current))
|
||||
add_law_zero()
|
||||
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/malf.ogg', 100, FALSE, pressure_affected = FALSE, use_reverb = FALSE)
|
||||
var/mob/living/silicon/ai/A = owner.current
|
||||
A.show_laws()
|
||||
else
|
||||
var/datum/atom_hud/antag/traitorhud = GLOB.huds[ANTAG_HUD_TRAITOR]
|
||||
traitorhud.join_hud(owner.current, null)
|
||||
set_antag_hud(owner.current, is_contractor ? "hudcontractor" : "hudsyndicate")
|
||||
|
||||
|
||||
/datum/antagonist/traitor/proc/update_traitor_icons_removed(datum/mind/traitor_mind)
|
||||
var/datum/atom_hud/antag/traitorhud = GLOB.huds[ANTAG_HUD_TRAITOR]
|
||||
traitorhud.leave_hud(owner.current, null)
|
||||
set_antag_hud(owner.current, null)
|
||||
|
||||
|
||||
/datum/antagonist/traitor/proc/finalize_traitor()
|
||||
switch(traitor_kind)
|
||||
if(TRAITOR_AI)
|
||||
add_law_zero()
|
||||
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/malf.ogg', 100, FALSE, pressure_affected = FALSE, use_reverb = FALSE)
|
||||
var/mob/living/silicon/ai/A = owner.current
|
||||
A.show_laws()
|
||||
if(TRAITOR_HUMAN)
|
||||
if(should_equip)
|
||||
equip_traitor()
|
||||
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/tatoralert.ogg', 100, FALSE, pressure_affected = FALSE, use_reverb = FALSE)
|
||||
|
||||
if(give_uplink)
|
||||
give_uplink()
|
||||
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/tatoralert.ogg', 100, FALSE, pressure_affected = FALSE, use_reverb = FALSE)
|
||||
|
||||
/**
|
||||
* Notify the traitor of their codewords and write them to `antag_memory` (notes).
|
||||
*/
|
||||
/datum/antagonist/traitor/proc/give_codewords()
|
||||
if(!owner.current)
|
||||
return
|
||||
@@ -302,109 +156,71 @@
|
||||
|
||||
traitor_mob.client.chatOutput?.notify_syndicate_codes()
|
||||
|
||||
/**
|
||||
* Gives traitor AIs, and their connected cyborgs, a law 0. Additionally gives the AI their choose modules action button.
|
||||
*/
|
||||
/datum/antagonist/traitor/proc/add_law_zero()
|
||||
var/mob/living/silicon/ai/killer = owner.current
|
||||
if(!killer || !istype(killer))
|
||||
return
|
||||
var/law = "Accomplish your objectives at all costs."
|
||||
var/law_borg = "Accomplish your AI's objectives at all costs."
|
||||
killer.set_zeroth_law(law, law_borg)
|
||||
killer.set_zeroth_law("Accomplish your objectives at all costs.", "Accomplish your AI's objectives at all costs.")
|
||||
killer.set_syndie_radio()
|
||||
to_chat(killer, "Your radio has been upgraded! Use :t to speak on an encrypted channel with Syndicate Agents!")
|
||||
killer.add_malf_picker()
|
||||
|
||||
/**
|
||||
* Gives a traitor human their uplink, and uplink code.
|
||||
*/
|
||||
/datum/antagonist/traitor/proc/give_uplink()
|
||||
if(isAI(owner.current))
|
||||
return FALSE
|
||||
|
||||
/datum/antagonist/traitor/proc/equip_traitor()
|
||||
var/mob/living/carbon/human/traitor_mob = owner.current
|
||||
|
||||
if(traitor_kind == TRAITOR_HUMAN)
|
||||
var/mob/living/carbon/human/traitor_mob = owner.current
|
||||
// Try to find a PDA first. If they don't have one, try to find a radio/headset.
|
||||
var/obj/item/R = locate(/obj/item/pda) in traitor_mob.contents
|
||||
if(!R)
|
||||
R = locate(/obj/item/radio) in traitor_mob.contents
|
||||
|
||||
// find a radio! toolbox(es), backpack, belt, headset
|
||||
var/obj/item/R = locate(/obj/item/pda) in traitor_mob.contents //Hide the uplink in a PDA if available, otherwise radio
|
||||
if(!R)
|
||||
R = locate(/obj/item/radio) in traitor_mob.contents
|
||||
if(!R)
|
||||
to_chat(traitor_mob, "<span class='warning'>Unfortunately, the Syndicate wasn't able to give you an uplink.</span>")
|
||||
return FALSE // They had no PDA or radio for whatever reason.
|
||||
|
||||
if(!R)
|
||||
to_chat(traitor_mob, "Unfortunately, the Syndicate wasn't able to get you a radio.")
|
||||
. = 0
|
||||
else
|
||||
if(istype(R, /obj/item/radio))
|
||||
// generate list of radio freqs
|
||||
var/obj/item/radio/target_radio = R
|
||||
var/freq = PUBLIC_LOW_FREQ
|
||||
var/list/freqlist = list()
|
||||
while(freq <= PUBLIC_HIGH_FREQ)
|
||||
if(freq < 1451 || freq > 1459)
|
||||
freqlist += freq
|
||||
freq += 2
|
||||
if((freq % 2) == 0)
|
||||
freq += 1
|
||||
freq = freqlist[rand(1, freqlist.len)]
|
||||
if(istype(R, /obj/item/radio))
|
||||
// generate list of radio freqs
|
||||
var/obj/item/radio/target_radio = R
|
||||
var/freq = PUBLIC_LOW_FREQ
|
||||
var/list/freqlist = list()
|
||||
while(freq <= PUBLIC_HIGH_FREQ)
|
||||
if(freq < 1451 || freq > 1459)
|
||||
freqlist += freq
|
||||
freq += 2
|
||||
if((freq % 2) == 0)
|
||||
freq += 1
|
||||
freq = pick(freqlist)
|
||||
|
||||
var/obj/item/uplink/hidden/T = new(R)
|
||||
target_radio.hidden_uplink = T
|
||||
T.uplink_owner = "[traitor_mob.key]"
|
||||
target_radio.traitor_frequency = freq
|
||||
to_chat(traitor_mob, "The Syndicate have cunningly disguised a Syndicate Uplink as your [R.name]. Simply dial the frequency [format_frequency(freq)] to unlock its hidden features.")
|
||||
traitor_mob.mind.store_memory("<B>Radio Freq:</B> [format_frequency(freq)] ([R.name]).")
|
||||
else if(istype(R, /obj/item/pda))
|
||||
// generate a passcode if the uplink is hidden in a PDA
|
||||
var/pda_pass = "[rand(100,999)] [pick("Alpha","Bravo","Delta","Omega")]"
|
||||
var/obj/item/uplink/hidden/T = new(R)
|
||||
target_radio.hidden_uplink = T
|
||||
T.uplink_owner = "[traitor_mob.key]"
|
||||
target_radio.traitor_frequency = freq
|
||||
to_chat(traitor_mob, "<span class='notice'>The Syndicate have cunningly disguised a Syndicate Uplink as your [R.name]. Simply dial the frequency [format_frequency(freq)] to unlock its hidden features.</span>")
|
||||
antag_memory += "<B>Radio Freq:</B> [format_frequency(freq)] ([R.name])."
|
||||
return TRUE
|
||||
|
||||
var/obj/item/uplink/hidden/T = new(R)
|
||||
R.hidden_uplink = T
|
||||
T.uplink_owner = "[traitor_mob.key]"
|
||||
var/obj/item/pda/P = R
|
||||
P.lock_code = pda_pass
|
||||
else if(istype(R, /obj/item/pda))
|
||||
// generate a passcode if the uplink is hidden in a PDA
|
||||
var/pda_pass = "[rand(100,999)] [pick("Alpha","Bravo","Delta","Omega")]"
|
||||
|
||||
to_chat(traitor_mob, "The Syndicate have cunningly disguised a Syndicate Uplink as your [R.name]. Simply enter the code \"[pda_pass]\" into the ringtone select to unlock its hidden features.")
|
||||
antag_memory += ("<B>Uplink Passcode:</B> [pda_pass] ([R.name].")
|
||||
return 1
|
||||
|
||||
|
||||
/datum/antagonist/traitor/proc/assign_exchange_role(datum/mind/owner)
|
||||
//set faction
|
||||
var/faction = "red"
|
||||
if(owner == SSticker.mode.exchange_blue)
|
||||
faction = "blue"
|
||||
|
||||
//Assign objectives
|
||||
var/datum/objective/steal/exchange/exchange_objective = new
|
||||
exchange_objective.set_faction(faction,((faction == "red") ? SSticker.mode.exchange_blue : SSticker.mode.exchange_red))
|
||||
exchange_objective.owner = owner
|
||||
owner.objectives += exchange_objective
|
||||
|
||||
if(prob(20))
|
||||
var/datum/objective/steal/exchange/backstab/backstab_objective = new
|
||||
backstab_objective.set_faction(faction)
|
||||
backstab_objective.owner = owner
|
||||
owner.objectives += backstab_objective
|
||||
|
||||
//Spawn and equip documents
|
||||
var/mob/living/carbon/human/mob = owner.current
|
||||
|
||||
var/obj/item/folder/syndicate/folder
|
||||
if(owner == SSticker.mode.exchange_red)
|
||||
folder = new/obj/item/folder/syndicate/red(mob.locs)
|
||||
else
|
||||
folder = new/obj/item/folder/syndicate/blue(mob.locs)
|
||||
|
||||
var/list/slots = list (
|
||||
"backpack" = slot_in_backpack,
|
||||
"left pocket" = slot_l_store,
|
||||
"right pocket" = slot_r_store,
|
||||
"left hand" = slot_l_hand,
|
||||
"right hand" = slot_r_hand,
|
||||
)
|
||||
|
||||
var/where = "At your feet"
|
||||
var/equipped_slot = mob.equip_in_one_of_slots(folder, slots)
|
||||
if(equipped_slot)
|
||||
where = "In your [equipped_slot]"
|
||||
to_chat(mob, "<BR><BR><span class='info'>[where] is a folder containing <b>secret documents</b> that another Syndicate group wants. We have set up a meeting with one of their agents on station to make an exchange. Exercise extreme caution as they cannot be trusted and may be hostile.</span><BR>")
|
||||
mob.update_icons()
|
||||
var/obj/item/uplink/hidden/T = new(R)
|
||||
R.hidden_uplink = T
|
||||
T.uplink_owner = "[traitor_mob.key]"
|
||||
var/obj/item/pda/P = R
|
||||
P.lock_code = pda_pass
|
||||
|
||||
to_chat(traitor_mob, "<span class='notice'>The Syndicate have cunningly disguised a Syndicate Uplink as your [R.name]. Simply enter the code \"[pda_pass]\" into the ringtone select to unlock its hidden features.</span>")
|
||||
antag_memory += "<B>Uplink Passcode:</B> [pda_pass] ([R.name]."
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
// Curently unused. Look at `/datum/game_mode/proc/auto_declare_completion_traitor()` instead.
|
||||
/datum/antagonist/traitor/roundend_report_footer()
|
||||
var/phrases = jointext(GLOB.syndicate_code_phrase, ", ")
|
||||
var/responses = jointext(GLOB.syndicate_code_response, ", ")
|
||||
|
||||
@@ -51,12 +51,6 @@
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/proc/ismindslave(A) //Checks to see if the person contains a mindslave implant, then checks that the implant is actually inside of them
|
||||
for(var/obj/item/implant/traitor/T in A)
|
||||
if(T && T.implanted)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/proc/isLivingSSD(mob/M)
|
||||
return istype(M) && M.player_logged && M.stat != DEAD
|
||||
|
||||
|
||||
Reference in New Issue
Block a user