/* Note from Carnie: The way datum/mind stuff works has been changed a lot. Minds now represent IC characters rather than following a client around constantly. Guidelines for using minds properly: - Never mind.transfer_to(ghost). The var/current and var/original of a mind must always be of type mob/living! ghost.mind is however used as a reference to the ghost's corpse - When creating a new mob for an existing IC character (e.g. cloning a dead guy or borging a brain of a human) the existing mind of the old mob should be transfered to the new mob like so: mind.transfer_to(new_mob) - You must not assign key= or ckey= after transfer_to() since the transfer_to transfers the client for you. By setting key or ckey explicitly after transfering the mind with transfer_to you will cause bugs like DCing the player. - IMPORTANT NOTE 2, if you want a player to become a ghost, use mob.ghostize() It does all the hard work for you. - When creating a new mob which will be a new IC character (e.g. putting a shade in a construct or randomly selecting a ghost to become a xeno during an event). Simply assign the key or ckey like you've always done. new_mob.key = key The Login proc will handle making a new mob for that mobtype (including setting up stuff like mind.name). Simple! However if you want that mind to have any special properties like being a traitor etc you will have to do that yourself. */ /datum/mind var/key var/name //replaces mob/var/original_name var/mob/living/current /// The original mob's UID. Used for example to see if a silicon with antag status is actually malf. Or just an antag put in a borg var/original_mob_UID /// The original mob's name. Used in Dchat messages var/original_mob_name var/active = FALSE var/memory var/assigned_role //assigned role is what job you're assigned to when you join the station. var/playtime_role //if set, overrides your assigned_role for the purpose of playtime awards. Set by IDcomputer when your ID is changed. var/special_role //special roles are typically reserved for antags or roles like ERT. If you want to avoid a character being automatically announced by the AI, on arrival (becuase they're an off station character or something); ensure that special_role and assigned_role are equal. var/offstation_role = FALSE //set to true for ERT, deathsquad, abductors, etc, that can go from and to CC at will and shouldn't be antag targets var/list/restricted_roles = list() var/list/spell_list = list() // Wizard mode & "Give Spell" badmin button. var/datum/martial_art/martial_art var/list/known_martial_arts = list() var/role_alt_title var/datum/job/assigned_job var/datum/objective_holder/objective_holder ///a list of objectives that a player with this job could complete for space credit rewards var/list/job_objectives = list() var/list/datum/objective/special_verbs = list() var/list/targets = list() /// Tracks if this mind has been a rev or not var/has_been_rev = FALSE var/miming = 0 // Mime's vow of silence /// A list of all the antagonist datums that the player is (does not include undatumized antags) var/list/antag_datums /// A lazy list of all teams the player is part of but doesnt have an antag role for, (i.e. a custom admin team) var/list/teams var/antag_hud_icon_state = null //this mind's ANTAG_HUD should have this icon_state var/datum/atom_hud/antag/antag_hud = null //this mind's antag HUD var/datum/mindslaves/som //stands for slave or master...hush.. var/isblessed = FALSE // is this person blessed by a chaplain? var/num_blessed = 0 // for prayers var/suicided = FALSE //put this here for easier tracking ingame var/datum/money_account/initial_account //zealot_master is a reference to the mob that converted them into a zealot (for ease of investigation and such) var/mob/living/carbon/human/zealot_master = null var/list/learned_recipes //List of learned recipe TYPES. /// List of people who we've received kudos from. var/list/kudos_received_from = list() /datum/mind/New(new_key) key = new_key objective_holder = new(src) /datum/mind/Destroy() SSticker.minds -= src remove_all_antag_datums() qdel(objective_holder) current = null kudos_received_from.Cut() return ..() /datum/mind/proc/set_original_mob(mob/original) original_mob_name = original.real_name original_mob_UID = original.UID() /datum/mind/proc/is_original_mob(mob/M) return original_mob_UID == M.UID() // Do not use for admin related things as this can hide the mob's ckey /datum/mind/proc/get_display_key() // Lets try find a client so we can check their prefs var/client/C = null var/cannonical_key = ckey(key) if(current?.client) // Active client C = current.client else if(cannonical_key in GLOB.directory) // Do a directory lookup on the last ckey this mind had // If theyre online we can grab them still and check prefs C = GLOB.directory[cannonical_key] // Ok we found a client, be it their active or their last // Now we see if we need to respect their privacy var/out_ckey if(C) if(C.prefs.toggles2 & PREFTOGGLE_2_ANON) out_ckey = "(Anon)" else out_ckey = C.ckey else // No client. Just mark as DC'd. out_ckey = "(Disconnected)" return out_ckey /datum/mind/proc/transfer_to(mob/living/new_character) var/datum/atom_hud/antag/hud_to_transfer = antag_hud //we need this because leave_hud() will clear this list var/mob/living/old_current = current if(!istype(new_character)) stack_trace("transfer_to(): Some idiot has tried to transfer_to() a non mob/living mob.") if(current) //remove ourself from our old body's mind variable current.mind = null if(isliving(current)) current.med_hud_set_status() leave_all_huds() //leave all the huds in the old body, so it won't get huds if somebody else enters it SStgui.on_transfer(current, new_character) new_character.job = current.job //transfer our job over to the new body if(new_character.mind) //remove any mind currently in our new body's mind variable new_character.mind.current = null current = new_character //link ourself to our new body new_character.mind = src //and link our new body to ourself for(var/a in antag_datums) //Makes sure all antag datums effects are applied in the new body var/datum/antagonist/A = a A.on_body_transfer(old_current, current) transfer_antag_huds(hud_to_transfer) //inherit the antag HUD transfer_actions(new_character) if(martial_art) for(var/datum/martial_art/MA in known_martial_arts) if(MA.temporary) MA.remove(current) else MA.remove(current) MA.teach(current) if(active) new_character.key = key //now transfer the key to link the client to our new body SEND_SIGNAL(src, COMSIG_MIND_TRANSER_TO, new_character) SEND_SIGNAL(new_character, COMSIG_BODY_TRANSFER_TO) if(ishuman(new_character)) var/mob/living/carbon/human/H = new_character if(H.mind in SSticker.mode.syndicates) SSticker.mode.update_synd_icons_added() if(H.mind in SSticker.mode.cult) SSticker.mode.update_cult_icons_added(H.mind) // Adds the cult antag hud SSticker.mode.add_cult_actions(H.mind) // And all the actions if(SSticker.mode.cult_risen) SSticker.mode.rise(H) if(SSticker.mode.cult_ascendant) SSticker.mode.ascend(H) /datum/mind/proc/store_memory(new_text) memory += "[new_text]
" /datum/mind/proc/wipe_memory() memory = null /datum/mind/proc/show_memory(mob/recipient, window = 1) if(!recipient) recipient = current var/list/output = list() output.Add("[current.real_name]'s Memories:
") output.Add(memory) for(var/datum/antagonist/A in antag_datums) output.Add(A.antag_memory) if(has_objectives()) output.Add("
Objectives:") output.Add(gen_objective_text()) if(LAZYLEN(job_objectives)) output.Add("
Job Objectives:") output = output.Join("
") if(window) recipient << browse(output, "window=memory") else to_chat(recipient, "[output]") /datum/mind/proc/gen_objective_text(admin = FALSE) if(!has_objectives()) return "No Objectives.
" var/list/text = list() var/obj_count = 1 // If they don't have any objectives, "" will be returned. for(var/datum/objective/objective in get_all_objectives()) text.Add("Objective #[obj_count++]: [objective.explanation_text][admin ? get_admin_objective_edit(objective) : ""]") return text.Join("
") /datum/mind/proc/get_admin_objective_edit(datum/objective/objective) return " Edit \ Delete \ \ Toggle Completion" /** * A quicker version of get_all_objectives() but only for seeing if they have any objectives at all */ /datum/mind/proc/has_objectives(include_team = TRUE) if(objective_holder.has_objectives()) return TRUE for(var/datum/antagonist/A as anything in antag_datums) if(A.has_antag_objectives(include_team)) // this checks teams also return TRUE // For custom non-antag role teams if(include_team && LAZYLEN(teams)) for(var/datum/team/team as anything in teams) if(team.objective_holder.has_objectives()) return TRUE return FALSE /** * Gets every objective this mind owns, including all of those from any antag datums they have, and returns them as a list. */ /datum/mind/proc/get_all_objectives(include_team = TRUE) var/list/all_objectives = list() all_objectives += objective_holder.get_objectives() // Get their personal objectives for(var/datum/antagonist/A as anything in antag_datums) all_objectives += A.objective_holder.get_objectives() // Add all antag datum objectives. if(include_team) var/datum/team/team = A.get_team() if(team) // have to make asure a team exists here, team?. does not work below because it will add the null to the list all_objectives += team.objective_holder.get_objectives() // Get all of their teams' objectives // For custom non-antag role teams if(include_team && LAZYLEN(teams)) for(var/datum/team/team as anything in teams) all_objectives += team.objective_holder.get_objectives() return all_objectives /** * Add an objective to the mind */ /datum/mind/proc/add_mind_objective(datum/objective/O, _explanation_text, mob/target_override) if(ispath(O)) O = new O() if(O.owner) stack_trace("[O], [O.type] was assigned as an objective to [src] (mind), but already had an owner: [O.owner] (mind). Overriding.") O.owner = src return objective_holder.add_objective(O, _explanation_text, target_override) /** * Completely remove the given objective from the mind, and include antagdatums/teams if remove_from_everything is true */ /datum/mind/proc/remove_mind_objective(datum/objective/O, remove_from_everything) . = objective_holder.remove_objective(O) if(!remove_from_everything) return for(var/datum/antagonist/A as anything in antag_datums) A.objective_holder.remove_objective(O) // Add all antag datum objectives. var/datum/team/team = A.get_team() team?.objective_holder.remove_objective(O) // Get all of their teams' objectives /datum/mind/proc/_memory_edit_header(gamemode, list/alt) . = gamemode if(SSticker.mode.config_tag == gamemode || (LAZYLEN(alt) && (SSticker.mode.config_tag in alt))) . = uppertext(.) . = "[.]: " /datum/mind/proc/_memory_edit_role_enabled(role) . = "|Disabled in Prefs" if(current && current.client && (role in current.client.prefs.be_special)) . = "|Enabled in Prefs" /datum/mind/proc/memory_edit_implant(mob/living/carbon/human/H) if(ismindshielded(H)) . = "Mindshield Bio-chip:Remove|Implanted
" else . = "Mindshield Bio-chip:No Bio-chip|Bio-chip [H.p_them()]!
" /datum/mind/proc/memory_edit_revolution(mob/living/carbon/human/H) . = _memory_edit_header("revolution") var/datum/antagonist/rev = has_antag_datum(/datum/antagonist/rev) if(ismindshielded(H)) . += "NO|headrev|rev" else if(istype(rev, /datum/antagonist/rev/head)) . += "no|HEADREV|rev" . += "
Flash: give" var/list/L = current.get_contents() var/obj/item/flash/flash = locate() in L if(flash) if(!flash.broken) . += "|take." else . += "|take|repair." else . += "." . += " Reequip (gives flash/cham sec hud)." if(!rev.has_antag_objectives()) // if theres anything missing here, we want it to runtime. There should never be a rev without a rev team . += "
Objectives are empty! Unless theres no command, this is likely a bug, please report it! Set to kill all heads." else if(rev) . += "no|headrev|REV" else . += "NO|headrev|rev" . += _memory_edit_role_enabled(ROLE_REV) /datum/mind/proc/memory_edit_cult(mob/living/carbon/human/H) . = _memory_edit_header("cult") if(src in SSticker.mode.cult) . += "no|CULTIST" . += "
Give dagger|runedmetal." else . += "NO|cultist" . += _memory_edit_role_enabled(ROLE_CULTIST) /datum/mind/proc/memory_edit_wizard(mob/living/carbon/human/H) . = _memory_edit_header("wizard") if(src in SSticker.mode.wizards) . += "WIZARD|no" . += "
To lair, undress, dress up, let choose name." if(!objective_holder.has_objectives()) . += "
Objectives are empty! Randomize!" else . += "wizard|NO" . += _memory_edit_role_enabled(ROLE_WIZARD) /datum/mind/proc/memory_edit_changeling(mob/living/carbon/human/H) . = _memory_edit_header("changeling", list("traitorchan")) var/datum/antagonist/changeling/cling = has_antag_datum(/datum/antagonist/changeling) if(cling) . += "CHANGELING|no" if(!cling.has_antag_objectives()) . += "
Objectives are empty! Randomize!" if(length(cling.absorbed_dna)) var/datum/dna/DNA = cling.absorbed_dna[1] if(current.real_name != DNA.real_name) . += "
Transform to initial appearance." else . += "changeling|NO" . += _memory_edit_role_enabled(ROLE_CHANGELING) /datum/mind/proc/memory_edit_vampire(mob/living/carbon/human/H) . = _memory_edit_header("vampire", list("traitorvamp")) var/datum/antagonist/vampire/vamp = has_antag_datum(/datum/antagonist/vampire) if(vamp) . += "VAMPIRE|no" . += "
Usable blood: [vamp.bloodusable]" . += " | Total blood: [vamp.bloodtotal]" var/has_subclass = !QDELETED(vamp.subclass) . += "
Subclass: [has_subclass ? capitalize(vamp.subclass.name) : "None"]" if(has_subclass) . += " | Force full power: [vamp.subclass.full_power_override ? "Yes" : "No"]" if(!vamp.has_antag_objectives()) . += "
Objectives are empty! Randomize!" else . += "vampire|NO" . += _memory_edit_role_enabled(ROLE_VAMPIRE) /** Enthralled ***/ . += "
enthralled: " if(has_antag_datum(/datum/antagonist/mindslave/thrall)) . += "THRALL|no" else . += "thrall|NO" /datum/mind/proc/memory_edit_nuclear(mob/living/carbon/human/H) . = _memory_edit_header("nuclear") if(src in SSticker.mode.syndicates) . += "OPERATIVE|no" . += "
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) . += " Code is [code]. tell the code." else . += "operative|NO" . += _memory_edit_role_enabled(ROLE_OPERATIVE) /datum/mind/proc/memory_edit_abductor(mob/living/carbon/human/H) . = _memory_edit_header("abductor") if(src in SSticker.mode.abductors) . += "ABDUCTOR|no" . += "|undress|equip" else . += "abductor|NO" . += _memory_edit_role_enabled(ROLE_ABDUCTOR) /datum/mind/proc/memory_edit_eventmisc(mob/living/H) . = _memory_edit_header("event", list()) if(src in SSticker.mode.eventmiscs) . += "YES|no" else . += "Event Role|NO" /datum/mind/proc/memory_edit_traitor() . = _memory_edit_header("traitor", list("traitorchan", "traitorvamp")) if(has_antag_datum(/datum/antagonist/traitor)) . += "TRAITOR|no" var/datum/antagonist/traitor/T = has_antag_datum(/datum/antagonist/traitor) if(!T.has_antag_objectives()) . += "
Objectives are empty! Randomize!" else . += "traitor|NO" . += _memory_edit_role_enabled(ROLE_TRAITOR) // Contractor . += "
contractor: " var/datum/contractor_hub/H = LAZYACCESS(GLOB.contractors, src) if(H) . += "CONTRACTOR" // List all their contracts . += "
Contracts:" if(H.contracts) var/count = 1 for(var/co in H.contracts) var/datum/syndicate_contract/CO = co . += "
Contract #[count++]: " . += "[CO.contract.target?.name || "Invalid target!"]|" . += "locations|" . += "more|" switch(CO.status) if(CONTRACT_STATUS_INVALID) . += "INVALID" if(CONTRACT_STATUS_INACTIVE) . += "inactive" if(CONTRACT_STATUS_ACTIVE) . += "ACTIVE|" . += "interrupt|" . += "fail" if(CONTRACT_STATUS_COMPLETED) . += "COMPLETED" if(CONTRACT_STATUS_FAILED) . += "FAILED" . += "
" . += "Add Contract
" . += "Claimable TC: [H.reward_tc_available]
" . += "Available Rep: [H.rep]
" else . += "
" . += "Has not logged in to contractor uplink" else . += "NO" // Mindslave . += "
mindslaved: " if(has_antag_datum(/datum/antagonist/mindslave, FALSE)) . += "MINDSLAVE|no" else . += "mindslave|NO" /datum/mind/proc/memory_edit_silicon() . = "Silicon: " var/mob/living/silicon/robot/robot = current if(istype(robot) && robot.emagged) . += "
Cyborg: Is emagged! Unemag!
0th law: [robot.laws.zeroth_law]" 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++ . += "
[n_e_robots] of [ai.connected_robots.len] slaved cyborgs are emagged. Unemag" /datum/mind/proc/memory_edit_uplink() . = "" if(ishuman(current) && ((has_antag_datum(/datum/antagonist/traitor)) || \ (src in SSticker.mode.syndicates))) . = "Uplink: give" var/obj/item/uplink/hidden/suplink = find_syndicate_uplink() var/crystals if(suplink) crystals = suplink.uses if(suplink) . += "|take" if(usr.client.holder.rights & (R_SERVER|R_EVENT)) . += ", [crystals] crystals" else . += ", [crystals] crystals" . += "." //hiel grammar // ^ whoever left this comment is literally a grammar nazi. stalin better. in russia grammar correct you. /datum/mind/proc/edit_memory() if(!SSticker || !SSticker.mode) alert("Not before round-start!", "Alert") return var/list/out = list("[name][(current && (current.real_name != name))?" (as [current.real_name])" : ""]") out.Add("Mind currently owned by key: [key] [active ? "(synced)" : "(not synced)"]") out.Add("Assigned role: [assigned_role]. Edit") out.Add("Factions and special roles:") var/list/sections = list( "implant", "revolution", "cult", "wizard", "changeling", "vampire", // "traitorvamp", "nuclear", "traitor", // "traitorchan", ) var/mob/living/carbon/human/H = current if(ishuman(current)) /** Impanted**/ sections["implant"] = memory_edit_implant(H) /** REVOLUTION ***/ sections["revolution"] = memory_edit_revolution(H) /** WIZARD ***/ sections["wizard"] = memory_edit_wizard(H) /** CHANGELING ***/ sections["changeling"] = memory_edit_changeling(H) /** VAMPIRE ***/ sections["vampire"] = memory_edit_vampire(H) /** NUCLEAR ***/ sections["nuclear"] = memory_edit_nuclear(H) /** Abductors **/ sections["abductor"] = memory_edit_abductor(H) sections["eventmisc"] = memory_edit_eventmisc(H) /** TRAITOR ***/ sections["traitor"] = memory_edit_traitor() if(!issilicon(current)) /** CULT ***/ sections["cult"] = memory_edit_cult(H) /** SILICON ***/ if(issilicon(current)) sections["silicon"] = memory_edit_silicon() /* This prioritizes antags relevant to the current round to make them appear at the top of the panel. Traitorchan and traitorvamp are snowflaked in because they have multiple sections. */ if(SSticker.mode.config_tag == "traitorchan") if(sections["traitor"]) out.Add(sections["traitor"]) if(sections["changeling"]) out.Add(sections["changeling"]) sections -= "traitor" sections -= "changeling" // Elif technically unnecessary but it makes the following else look better else if(SSticker.mode.config_tag == "traitorvamp") if(sections["traitor"]) out.Add(sections["traitor"]) if(sections["vampire"]) out.Add(sections["vampire"]) sections -= "traitor" sections -= "vampire" else if(sections[SSticker.mode.config_tag]) out.Add(sections[SSticker.mode.config_tag]) sections -= SSticker.mode.config_tag for(var/i in sections) if(sections[i]) out.Add(sections[i]) out.Add(memory_edit_uplink()) out.Add("Memory:") out.Add(memory) out.Add("Edit memory
") out.Add("Objectives:") out.Add(gen_objective_text(admin = TRUE)) out.Add("Add objective
") out.Add("Announce objectives
") usr << browse(out.Join("
"), "window=edit_memory[src];size=500x500") /datum/mind/Topic(href, href_list) if(!check_rights(R_ADMIN)) return if(href_list["role_edit"]) var/new_role = input("Select new role", "Assigned role", assigned_role) as null|anything in GLOB.joblist if(!new_role) return assigned_role = new_role log_admin("[key_name(usr)] has changed [key_name(current)]'s assigned role to [assigned_role]") message_admins("[key_name_admin(usr)] has changed [key_name_admin(current)]'s assigned role to [assigned_role]") else if(href_list["memory_edit"]) var/messageinput = input("Write new memory", "Memory", memory) as null|message if(isnull(messageinput)) return var/new_memo = copytext(messageinput, 1,MAX_MESSAGE_LEN) var/confirmed = alert(usr, "Are you sure you want to edit their memory? It will wipe out their original memory!", "Edit Memory", "Yes", "No") if(confirmed == "Yes") // Because it is too easy to accidentally wipe someone's memory memory = new_memo log_admin("[key_name(usr)] has edited [key_name(current)]'s memory") message_admins("[key_name_admin(usr)] has edited [key_name_admin(current)]'s memory") else if(href_list["obj_edit"] || href_list["obj_add"]) var/datum/objective/objective var/def_value if(href_list["obj_edit"]) objective = locate(href_list["obj_edit"]) if(!objective) return //Text strings are easy to manipulate. Revised for simplicity. var/temp_obj_type = "[objective.type]"//Convert path into a text string. def_value = copytext(temp_obj_type, 18)//Convert last part of path into an objective keyword. if(!def_value)//If it's a custom objective, it will be an empty string. def_value = "custom" var/new_obj_type = input("Select objective type:", "Objective type", def_value) as null|anything in list( "assassinate", "assassinateonce", "blood", "debrain", "protect", "prevent", "hijack", "escape", "survive", "steal", "nuclear", "absorb", "destroy", "maroon", "identity theft", "custom") if(!new_obj_type) return var/datum/objective/new_objective = null switch(new_obj_type) if("assassinate", "assassinateonce", "protect","debrain", "maroon") var/list/possible_targets = list() var/list/possible_targets_random = list() for(var/datum/mind/possible_target in SSticker.minds) if((possible_target != src) && ishuman(possible_target.current)) possible_targets += possible_target.current // Allows for admins to pick off station roles if(!is_invalid_target(possible_target)) possible_targets_random += possible_target.current // For random picking, only valid targets var/mob/def_target = null var/objective_list[] = list(/datum/objective/assassinate, /datum/objective/assassinateonce, /datum/objective/protect, /datum/objective/debrain) if(objective&&(objective.type in objective_list) && objective:target) def_target = objective.target.current possible_targets = sortAtom(possible_targets) var/new_target if(length(possible_targets)) if(alert(usr, "Do you want to pick the objective yourself? No will randomise it", "Pick objective", "Yes", "No") == "Yes") possible_targets += "Free objective" new_target = input("Select target:", "Objective target", def_target) as null|anything in possible_targets else if(!length(possible_targets_random)) to_chat(usr, "No random target found. Pick one manually.") return new_target = pick(possible_targets_random) if(!new_target) return else to_chat(usr, "No possible target found. Defaulting to a Free objective.") new_target = "Free objective" var/objective_path = text2path("/datum/objective/[new_obj_type]") if(new_target == "Free objective") new_objective = new objective_path new_objective:target = null new_objective.update_explanation_text() else new_objective = new objective_path new_objective:target = new_target:mind new_objective.update_explanation_text() if("destroy") var/list/possible_targets = active_ais(1) if(possible_targets.len) var/mob/new_target = input("Select target:", "Objective target") as null|anything in possible_targets new_objective = new /datum/objective/destroy new_objective.target = new_target.mind new_objective.update_explanation_text() else to_chat(usr, "No active AIs with minds") if("prevent") new_objective = /datum/objective/block // we can place paths here because they will be created as needed in the objective holder if("hijack") new_objective = /datum/objective/hijack if("escape") new_objective = /datum/objective/escape if("survive") new_objective = /datum/objective/survive if("nuclear") new_objective = /datum/objective/nuclear if("steal") if(!istype(objective, /datum/objective/steal)) new_objective = new /datum/objective/steal else new_objective = objective var/datum/objective/steal/steal = new_objective if(!steal.select_target()) return if("absorb", "blood") var/def_num if(objective&&objective.type==text2path("/datum/objective/[new_obj_type]")) def_num = objective.target_amount var/target_number = input("Input target number:", "Objective", def_num) as num|null if(isnull(target_number))//Ordinarily, you wouldn't need isnull. In this case, the value may already exist. return switch(new_obj_type) if("absorb") new_objective = new /datum/objective/absorb if("blood") new_objective = new /datum/objective/blood new_objective.target_amount = target_number new_objective.update_explanation_text() if("identity theft") var/list/possible_targets = list() for(var/datum/mind/possible_target in SSticker.minds) if((possible_target != src) && ishuman(possible_target.current)) possible_targets += possible_target possible_targets = sortAtom(possible_targets) possible_targets += "Free objective" var/new_target = input("Select target:", "Objective target") as null|anything in possible_targets if(!new_target) return var/datum/mind/targ = new_target if(!istype(targ)) CRASH("Invalid target for identity theft objective, cancelling") new_objective = new /datum/objective/escape/escape_with_identity new_objective.target = new_target new_objective.update_explanation_text() var/datum/objective/escape/escape_with_identity/O = new_objective O.target_real_name = new_objective.target.current.real_name if("custom") var/expl = sanitize(copytext(input("Custom objective:", "Objective", objective ? objective.explanation_text : "") as text|null,1,MAX_MESSAGE_LEN)) if(!expl) return new_objective = new /datum/objective new_objective.explanation_text = expl if(!new_objective) return if(objective) objective.holder.replace_objective(objective, new_objective) // replace it in its old holder else add_mind_objective(new_objective) log_admin("[key_name(usr)] has updated [key_name(current)]'s objectives: [new_objective]") message_admins("[key_name_admin(usr)] has updated [key_name_admin(current)]'s objectives: [new_objective]") else if(href_list["obj_delete"]) var/datum/objective/objective = locate(href_list["obj_delete"]) if(!istype(objective)) return log_admin("[key_name(usr)] has removed one of [key_name(current)]'s objectives: [objective]") message_admins("[key_name_admin(usr)] has removed one of [key_name_admin(current)]'s objectives: [objective]") remove_mind_objective(objective, TRUE) else if(href_list["obj_completed"]) var/datum/objective/objective = locate(href_list["obj_completed"]) if(!istype(objective)) return objective.completed = !objective.completed log_admin("[key_name(usr)] has toggled the completion of one of [key_name(current)]'s objectives") message_admins("[key_name_admin(usr)] has toggled the completion of one of [key_name_admin(current)]'s objectives") else if(href_list["implant"]) var/mob/living/carbon/human/H = current switch(href_list["implant"]) if("remove") for(var/obj/item/bio_chip/mindshield/I in H.contents) if(I && I.implanted) qdel(I) to_chat(H, "Your mindshield bio-chip has been deactivated.") log_admin("[key_name(usr)] has deactivated [key_name(current)]'s mindshield bio-chip") message_admins("[key_name_admin(usr)] has deactivated [key_name_admin(current)]'s mindshield bio-chip") if("add") var/obj/item/bio_chip/mindshield/L = new/obj/item/bio_chip/mindshield(H) L.implant(H) log_admin("[key_name(usr)] has given [key_name(current)] a mindshield bio-chip") message_admins("[key_name_admin(usr)] has given [key_name_admin(current)] a mindshield bio-chip") to_chat(H, "You somehow have become the recipient of a mindshield transplant, and it just activated!") var/datum/antagonist/rev/has_rev = has_antag_datum(/datum/antagonist/rev) if(has_rev) has_rev.silent = TRUE // we have some custom text, lets make the removal silent remove_antag_datum(/datum/antagonist/rev) to_chat(H, "The nanobots in the mindshield implant remove all thoughts about being a revolutionary. Get back to work!") else if(href_list["revolution"]) switch(href_list["revolution"]) if("clear") var/datum/antagonist/rev/has_rev = has_antag_datum(/datum/antagonist/rev) if(has_rev) remove_antag_datum(/datum/antagonist/rev) log_admin("[key_name(usr)] has de-rev'd [key_name(current)]") message_admins("[key_name_admin(usr)] has de-rev'd [key_name_admin(current)]") if("rev") var/datum/antagonist/rev/head/is_headrev = has_antag_datum(/datum/antagonist/rev/head) if(is_headrev) is_headrev.demote() log_admin("[key_name(usr)] has demoted [key_name(current)] from headrev to rev") message_admins("[key_name(usr)] has demoted [key_name(current)] from headrev to rev") edit_memory() // so it updates... return if(has_antag_datum(/datum/antagonist/rev)) return add_antag_datum(/datum/antagonist/rev) log_admin("[key_name(usr)] has rev'd [key_name(current)]") message_admins("[key_name_admin(usr)] has rev'd [key_name_admin(current)]") current.create_log(MISC_LOG, "[current] was made into a revolutionary by [key_name_admin(usr)]") if("headrev") if(has_antag_datum(/datum/antagonist/rev/head)) return var/datum/antagonist/rev/has_rev = has_antag_datum(/datum/antagonist/rev) if(has_rev) has_rev.promote() log_admin("[key_name(usr)] has promoted [key_name(current)] from rev to headrev (auto-equipped flash/hud)") message_admins("[key_name(usr)] has promoted [key_name(current)] from rev to headrev (auto-equipped flash/hud)") edit_memory() // so it updates... return var/datum/antagonist/rev/head/head_rev = new() head_rev.should_equip = FALSE add_antag_datum(head_rev) log_admin("[key_name(usr)] has head-rev'd [key_name(current)]") message_admins("[key_name_admin(usr)] has head-rev'd [key_name_admin(current)]") if("autoobjectives") var/datum/team/revolution/the_rev_team = SSticker.mode.get_rev_team() the_rev_team.update_team_objectives() log_admin("[key_name(usr)] has updated revolutionary objectives for [key_name(current)]") message_admins("[key_name_admin(usr)] has updated revolutionary objectives for [key_name_admin(current)]") if("flash") var/datum/antagonist/rev/head/headrev = has_antag_datum(/datum/antagonist/rev/head) if(!headrev.equip_revolutionary(TRUE, FALSE)) to_chat(usr, "Spawning flash failed!") log_admin("[key_name(usr)] has given [key_name(current)] a flash") message_admins("[key_name_admin(usr)] has given [key_name_admin(current)] a flash") if("takeflash") var/list/L = current.get_contents() var/obj/item/flash/flash = locate() in L if(!flash) to_chat(usr, "Deleting flash failed!") qdel(flash) log_admin("[key_name(usr)] has taken [key_name(current)]'s flash") message_admins("[key_name_admin(usr)] has taken [key_name_admin(current)]'s flash") if("repairflash") var/list/L = current.get_contents() var/obj/item/flash/flash = locate() in L if(!flash) to_chat(usr, "Repairing flash failed!") else flash.broken = FALSE log_admin("[key_name(usr)] has repaired [key_name(current)]'s flash") message_admins("[key_name_admin(usr)] has repaired [key_name_admin(current)]'s flash") if("reequip") var/list/L = current.get_contents() var/obj/item/flash/flash = locate() in L qdel(flash) take_uplink() var/datum/antagonist/rev/head/headrev = has_antag_datum(/datum/antagonist/rev/head) if(!headrev.equip_revolutionary()) to_chat(usr, "Reequipping revolutionary went wrong!") return log_admin("[key_name(usr)] has equipped [key_name(current)] as a revolutionary") message_admins("[key_name_admin(usr)] has equipped [key_name_admin(current)] as a revolutionary") else if(href_list["cult"]) switch(href_list["cult"]) if("clear") if(src in SSticker.mode.cult) SSticker.mode.remove_cultist(src) special_role = null log_admin("[key_name(usr)] has de-culted [key_name(current)]") message_admins("[key_name_admin(usr)] has de-culted [key_name_admin(current)]") if("cultist") if(!(src in SSticker.mode.cult)) to_chat(current, CULT_GREETING) SSticker.mode.add_cultist(src) to_chat(current, "Assist your new compatriots in their dark dealings. Their goal is yours, and yours is theirs. You serve [SSticker.cultdat.entity_title2] above all else. Bring It back.") log_and_message_admins("[key_name(usr)] has culted [key_name(current)]") if("dagger") var/mob/living/carbon/human/H = current if(!SSticker.mode.cult_give_item(/obj/item/melee/cultblade/dagger, H)) to_chat(usr, "Spawning dagger failed!") log_and_message_admins("[key_name(usr)] has equipped [key_name(current)] with a cult dagger") if("runedmetal") var/mob/living/carbon/human/H = current if(!SSticker.mode.cult_give_item(/obj/item/stack/sheet/runed_metal/ten, H)) to_chat(usr, "Spawning runed metal failed!") log_and_message_admins("[key_name(usr)] has equipped [key_name(current)] with 10 runed metal sheets") else if(href_list["wizard"]) switch(href_list["wizard"]) if("clear") if(src in SSticker.mode.wizards) SSticker.mode.wizards -= src special_role = null current.spellremove(current) current.faction = list("Station") SSticker.mode.update_wiz_icons_removed(src) to_chat(current, "You have been brainwashed! You are no longer a wizard!") log_admin("[key_name(usr)] has de-wizarded [key_name(current)]") message_admins("[key_name_admin(usr)] has de-wizarded [key_name_admin(current)]") if("wizard") if(!(src in SSticker.mode.wizards)) SSticker.mode.wizards += src special_role = SPECIAL_ROLE_WIZARD //ticker.mode.learn_basic_spells(current) SSticker.mode.update_wiz_icons_added(src) SEND_SOUND(current, sound('sound/ambience/antag/ragesmages.ogg')) to_chat(current, "You are a Space Wizard!") current.faction = list("wizard") log_admin("[key_name(usr)] has wizarded [key_name(current)]") message_admins("[key_name_admin(usr)] has wizarded [key_name_admin(current)]") current.create_log(MISC_LOG, "[current] was made into a wizard by [key_name_admin(usr)]") if("lair") current.forceMove(pick(GLOB.wizardstart)) log_admin("[key_name(usr)] has moved [key_name(current)] to the wizard's lair") message_admins("[key_name_admin(usr)] has moved [key_name_admin(current)] to the wizard's lair") if("dressup") SSticker.mode.equip_wizard(current) log_admin("[key_name(usr)] has equipped [key_name(current)] as a wizard") message_admins("[key_name_admin(usr)] has equipped [key_name_admin(current)] as a wizard") if("name") INVOKE_ASYNC(SSticker.mode, TYPE_PROC_REF(/datum/game_mode/wizard, name_wizard), current) log_admin("[key_name(usr)] has allowed wizard [key_name(current)] to name themselves") message_admins("[key_name_admin(usr)] has allowed wizard [key_name_admin(current)] to name themselves") if("autoobjectives") SSticker.mode.forge_wizard_objectives(src) to_chat(usr, "The objectives for wizard [key] have been generated. You can edit them and announce manually.") log_admin("[key_name(usr)] has automatically forged wizard objectives for [key_name(current)]") message_admins("[key_name_admin(usr)] has automatically forged wizard objectives for [key_name_admin(current)]") else if(href_list["changeling"]) switch(href_list["changeling"]) if("clear") if(ischangeling(current)) remove_antag_datum(/datum/antagonist/changeling) log_admin("[key_name(usr)] has de-changelinged [key_name(current)]") message_admins("[key_name_admin(usr)] has de-changelinged [key_name_admin(current)]") if("changeling") if(!ischangeling(current)) add_antag_datum(/datum/antagonist/changeling) to_chat(current, "Your powers have awoken. A flash of memory returns to us... we are a changeling!") log_admin("[key_name(usr)] has changelinged [key_name(current)]") message_admins("[key_name_admin(usr)] has changelinged [key_name_admin(current)]") if("autoobjectives") var/datum/antagonist/changeling/cling = has_antag_datum(/datum/antagonist/changeling) cling.give_objectives() to_chat(usr, "The objectives for changeling [key] have been generated. You can edit them and announce manually.") log_admin("[key_name(usr)] has automatically forged objectives for [key_name(current)]") message_admins("[key_name_admin(usr)] has automatically forged objectives for [key_name_admin(current)]") if("initialdna") var/datum/antagonist/changeling/cling = has_antag_datum(/datum/antagonist/changeling) if(!cling || !length(cling.absorbed_dna)) to_chat(usr, "Resetting DNA failed!") else current.dna = cling.absorbed_dna[1] current.real_name = current.dna.real_name current.UpdateAppearance() domutcheck(current) log_admin("[key_name(usr)] has reset [key_name(current)]'s DNA") message_admins("[key_name_admin(usr)] has reset [key_name_admin(current)]'s DNA") else if(href_list["vampire"]) switch(href_list["vampire"]) if("clear") if(has_antag_datum(/datum/antagonist/vampire)) remove_antag_datum(/datum/antagonist/vampire) to_chat(current, "You grow weak and lose your powers! You are no longer a vampire and are stuck in your current form!") log_admin("[key_name(usr)] has de-vampired [key_name(current)]") message_admins("[key_name_admin(usr)] has de-vampired [key_name_admin(current)]") if("vampire") if(!has_antag_datum(/datum/antagonist/vampire)) add_antag_datum(/datum/antagonist/vampire) to_chat(current, "Your powers have awoken. Your lust for blood grows... You are a Vampire!") log_admin("[key_name(usr)] has vampired [key_name(current)]") message_admins("[key_name_admin(usr)] has vampired [key_name_admin(current)]") if("edit_usable_blood") var/new_usable = input(usr, "Select a new value:", "Modify usable blood") as null|num if(isnull(new_usable) || new_usable < 0) return var/datum/antagonist/vampire/vamp = has_antag_datum(/datum/antagonist/vampire) vamp.bloodusable = new_usable current.update_action_buttons_icon() log_admin("[key_name(usr)] has set [key_name(current)]'s usable blood to [new_usable].") message_admins("[key_name_admin(usr)] has set [key_name_admin(current)]'s usable blood to [new_usable].") if("edit_total_blood") var/new_total = input(usr, "Select a new value:", "Modify total blood") as null|num if(isnull(new_total) || new_total < 0) return var/datum/antagonist/vampire/vamp = has_antag_datum(/datum/antagonist/vampire) if(new_total < vamp.bloodtotal) if(alert(usr, "Note that reducing the vampire's total blood may remove some active powers. Continue?", "Confirm New Total", "Yes", "No") == "No") return vamp.remove_all_powers() vamp.bloodtotal = new_total vamp.check_vampire_upgrade() log_admin("[key_name(usr)] has set [key_name(current)]'s total blood to [new_total].") message_admins("[key_name_admin(usr)] has set [key_name_admin(current)]'s total blood to [new_total].") if("change_subclass") var/list/subclass_selection = list() for(var/subtype in subtypesof(/datum/vampire_subclass)) var/datum/vampire_subclass/subclass = subtype subclass_selection[capitalize(initial(subclass.name))] = subtype subclass_selection["Let them choose (remove current subclass)"] = NONE var/new_subclass_name = input(usr, "Choose a new subclass:", "Change Vampire Subclass") as null|anything in subclass_selection if(!new_subclass_name) return var/datum/antagonist/vampire/vamp = has_antag_datum(/datum/antagonist/vampire) var/subclass_type = subclass_selection[new_subclass_name] if(subclass_type == NONE) vamp.clear_subclass() log_admin("[key_name(usr)] has removed [key_name(current)]'s vampire subclass.") message_admins("[key_name_admin(usr)] has removed [key_name_admin(current)]'s vampire subclass.") else vamp.upgrade_tiers -= /obj/effect/proc_holder/spell/vampire/self/specialize vamp.change_subclass(subclass_type) log_admin("[key_name(usr)] has removed [key_name(current)]'s vampire subclass.") message_admins("[key_name_admin(usr)] has removed [key_name_admin(current)]'s vampire subclass.") if("full_power_override") var/datum/antagonist/vampire/vamp = has_antag_datum(/datum/antagonist/vampire) if(vamp.subclass.full_power_override) vamp.subclass.full_power_override = FALSE for(var/power in vamp.powers) if(!is_type_in_list(power, vamp.subclass.fully_powered_abilities)) continue vamp.remove_ability(power) else vamp.subclass.full_power_override = TRUE vamp.check_full_power_upgrade() log_admin("[key_name(usr)] set [key_name(current)]'s vampire 'full_power_overide' to [vamp.subclass.full_power_override].") message_admins("[key_name_admin(usr)] set [key_name_admin(current)]'s vampire 'full_power_overide' to [vamp.subclass.full_power_override].") if("autoobjectives") var/datum/antagonist/vampire/V = has_antag_datum(/datum/antagonist/vampire) V.give_objectives() to_chat(usr, "The objectives for vampire [key] have been generated. You can edit them and announce manually.") log_admin("[key_name(usr)] has automatically forged objectives for [key_name(current)]") message_admins("[key_name_admin(usr)] has automatically forged objectives for [key_name_admin(current)]") else if(href_list["vampthrall"]) switch(href_list["vampthrall"]) if("clear") if(has_antag_datum(/datum/antagonist/mindslave/thrall)) remove_antag_datum(/datum/antagonist/mindslave/thrall) log_admin("[key_name(usr)] has de-vampthralled [key_name(current)]") message_admins("[key_name_admin(usr)] has de-vampthralled [key_name_admin(current)]") else if(href_list["nuclear"]) var/mob/living/carbon/human/H = current switch(href_list["nuclear"]) if("clear") if(src in SSticker.mode.syndicates) SSticker.mode.syndicates -= src SSticker.mode.update_synd_icons_removed(src) special_role = null objective_holder.clear(/datum/objective/nuclear) to_chat(current, "You have been brainwashed! You are no longer a syndicate operative!") log_admin("[key_name(usr)] has de-nuke op'd [key_name(current)]") message_admins("[key_name_admin(usr)] has de-nuke op'd [key_name_admin(current)]") if("nuclear") if(!(src in SSticker.mode.syndicates)) SSticker.mode.syndicates += src SSticker.mode.update_synd_icons_added(src) if(SSticker.mode.syndicates.len==1) SSticker.mode.prepare_syndicate_leader(src) else current.real_name = "[syndicate_name()] Operative #[SSticker.mode.syndicates.len-1]" special_role = SPECIAL_ROLE_NUKEOPS to_chat(current, "You are a [syndicate_name()] agent!") SSticker.mode.forge_syndicate_objectives(src) SSticker.mode.greet_syndicate(src, FALSE) // False to fix the agent message appearing twice log_admin("[key_name(usr)] has nuke op'd [key_name(current)]") message_admins("[key_name_admin(usr)] has nuke op'd [key_name_admin(current)]") if("lair") current.forceMove(get_turf(locate("landmark*Syndicate-Spawn"))) log_admin("[key_name(usr)] has moved [key_name(current)] to the nuclear operative spawn") message_admins("[key_name_admin(usr)] has moved [key_name_admin(current)] to the nuclear operative spawn") if("dressup") qdel(H.belt) qdel(H.back) qdel(H.l_ear) qdel(H.r_ear) qdel(H.gloves) qdel(H.head) qdel(H.shoes) qdel(H.wear_id) qdel(H.wear_pda) qdel(H.wear_suit) qdel(H.w_uniform) if(!SSticker.mode.equip_syndicate(current)) to_chat(usr, "Equipping a syndicate failed!") return SSticker.mode.update_syndicate_id(current.mind, SSticker.mode.syndicates.len == 1) log_admin("[key_name(usr)] has equipped [key_name(current)] as a nuclear operative") message_admins("[key_name_admin(usr)] has equipped [key_name_admin(current)] as a nuclear operative") 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]") log_admin("[key_name(usr)] has given [key_name(current)] the nuclear authorization code") message_admins("[key_name_admin(usr)] has given [key_name_admin(current)] the nuclear authorization code") else to_chat(usr, "No valid nuke found!") else if(href_list["eventmisc"]) switch(href_list["eventmisc"]) if("clear") if(src in SSticker.mode.eventmiscs) SSticker.mode.eventmiscs -= src SSticker.mode.update_eventmisc_icons_removed(src) special_role = null message_admins("[key_name_admin(usr)] has de-eventantag'ed [current].") log_admin("[key_name(usr)] has de-eventantag'ed [current].") if("eventmisc") SSticker.mode.eventmiscs += src special_role = SPECIAL_ROLE_EVENTMISC SSticker.mode.update_eventmisc_icons_added(src) message_admins("[key_name_admin(usr)] has eventantag'ed [current].") log_admin("[key_name(usr)] has eventantag'ed [current].") current.create_log(MISC_LOG, "[current] was made into an event antagonist by [key_name_admin(usr)]") else if(href_list["traitor"]) switch(href_list["traitor"]) if("clear") if(has_antag_datum(/datum/antagonist/traitor)) remove_antag_datum(/datum/antagonist/traitor) log_admin("[key_name(usr)] has de-traitored [key_name(current)]") message_admins("[key_name_admin(usr)] has de-traitored [key_name_admin(current)]") if("traitor") if(!(has_antag_datum(/datum/antagonist/traitor))) add_antag_datum(/datum/antagonist/traitor) log_admin("[key_name(usr)] has traitored [key_name(current)]") message_admins("[key_name_admin(usr)] has traitored [key_name_admin(current)]") if("autoobjectives") var/datum/antagonist/traitor/T = has_antag_datum(/datum/antagonist/traitor) T.give_objectives() to_chat(usr, "The objectives for traitor [key] have been generated. You can edit them and announce manually.") log_admin("[key_name(usr)] has automatically forged objectives for [key_name(current)]") message_admins("[key_name_admin(usr)] has automatically forged objectives for [key_name_admin(current)]") else if(href_list["contractor"]) var/datum/contractor_hub/H = LAZYACCESS(GLOB.contractors, src) switch(href_list["contractor"]) if("add") if(!H) return var/list/possible_targets = list() for(var/foo in SSticker.minds) var/datum/mind/possible_target = foo if(src == possible_target || !possible_target.current || !possible_target.key) continue possible_targets[possible_target.name] = possible_target var/choice = input(usr, "Select the contract target:", "Add Contract") as null|anything in possible_targets var/datum/mind/target = possible_targets[choice] if(!target || !target.current || !target.key) return var/datum/syndicate_contract/new_contract = new(H, src, list(), target) new_contract.reward_tc = list(0, 0, 0) H.contracts += new_contract for(var/difficulty in EXTRACTION_DIFFICULTY_EASY to EXTRACTION_DIFFICULTY_HARD) var/amount_tc = H.calculate_tc_reward(length(H.contracts), difficulty) new_contract.reward_tc[difficulty] = amount_tc SStgui.update_uis(H) log_admin("[key_name(usr)] has given a new contract to [key_name(current)] with [target.current] as the target") message_admins("[key_name_admin(usr)] has given a new contract to [key_name_admin(current)] with [target.current] as the target") if("tc") if(!H) return var/new_tc = input(usr, "Enter the new amount of TC:", "Set Claimable TC", H.reward_tc_available) as num|null new_tc = text2num(new_tc) if(isnull(new_tc) || new_tc < 0) return H.reward_tc_available = new_tc SStgui.update_uis(H) log_admin("[key_name(usr)] has set [key_name(current)]'s claimable TC to [new_tc]") message_admins("[key_name_admin(usr)] has set [key_name_admin(current)]'s claimable TC to [new_tc]") if("rep") if(!H) return var/new_rep = input(usr, "Enter the new amount of Rep:", "Set Available Rep", H.rep) as num|null new_rep = text2num(new_rep) if(isnull(new_rep) || new_rep < 0) return H.rep = new_rep SStgui.update_uis(H) log_admin("[key_name(usr)] has set [key_name(current)]'s contractor Rep to [new_rep]") message_admins("[key_name_admin(usr)] has set [key_name_admin(current)]'s contractor Rep to [new_rep]") // Contract specific actions if("target") if(!H) return var/datum/syndicate_contract/CO = locateUID(href_list["cuid"]) if(!istype(CO)) return var/list/possible_targets = list() for(var/foo in SSticker.minds) var/datum/mind/possible_target = foo if(src == possible_target || !possible_target.current || !possible_target.key) continue possible_targets[possible_target.name] = possible_target var/choice = input(usr, "Select the new contract target:", "Set Contract Target") as null|anything in possible_targets var/datum/mind/target = possible_targets[choice] if(!target || !target.current || !target.key) return // Update var/datum/data/record/R = find_record("name", target.name, GLOB.data_core.general) var/name = R?.fields["name"] || target.name || "Unknown" var/rank = R?.fields["rank"] || target.assigned_role || "Unknown" CO.contract.target = target CO.target_name = "[name], the [rank]" if(R?.fields["photo"]) var/icon/temp = new('icons/turf/floors.dmi', pick("floor", "wood", "darkfull", "stairs")) temp.Blend(R.fields["photo"], ICON_OVERLAY) CO.target_photo = temp // Notify SStgui.update_uis(H) log_admin("[key_name(usr)] has set [key_name(current)]'s contract target to [target.current]") message_admins("[key_name_admin(usr)] has set [key_name_admin(current)]'s contract target to [target.current]") if("locations") if(!H) return var/datum/syndicate_contract/CO = locateUID(href_list["cuid"]) if(!istype(CO)) return var/list/difficulty_choices = list() for(var/diff in EXTRACTION_DIFFICULTY_EASY to EXTRACTION_DIFFICULTY_HARD) var/area/A = CO.contract.candidate_zones[diff] difficulty_choices["[A.name] ([CO.reward_tc[diff]] TC)"] = diff var/choice_diff = input(usr, "Select the location to change:", "Set Contract Location") as null|anything in difficulty_choices var/difficulty = difficulty_choices[choice_diff] if(!difficulty) return var/list/area_choices = list() for(var/a in return_sorted_areas()) var/area/A = a if(A.outdoors || !is_station_level(A.z)) continue area_choices += A var/new_area = input(usr, "Select the new location:", "Set Contract Location", CO.contract.candidate_zones[difficulty]) in area_choices if(!new_area) return var/new_reward = input(usr, "Enter the new amount of rewarded TC:", "Set Contract Location", CO.reward_tc[difficulty]) as num|null new_reward = text2num(new_reward) if(isnull(new_reward) || new_reward < 0) return CO.contract.candidate_zones[difficulty] = new_area CO.reward_tc[difficulty] = new_reward SStgui.update_uis(H) log_admin("[key_name(usr)] has set [key_name(current)]'s contract location to [new_area] with [new_reward] TC as reward") message_admins("[key_name_admin(usr)] has set [key_name_admin(current)]'s contract location to [new_area] with [new_reward] TC as reward") if("other") if(!H) return var/datum/syndicate_contract/CO = locateUID(href_list["cuid"]) if(!istype(CO)) return var/choice = input(usr, "Select an action to take:", "Other Contract Actions") in list("Edit Fluff Message", "Edit Prison Time", "Edit Credits Reward", "Delete Contract", "Cancel") if(!choice) return switch(choice) if("Edit Fluff Message") var/new_message = input(usr, "Enter the new fluff message:", "Edit Fluff Message", CO.fluff_message) as message|null if(!new_message) return CO.fluff_message = new_message log_admin("[key_name(usr)] has edited [key_name(current)]'s contract fluff message") message_admins("[key_name_admin(usr)] has edited [key_name_admin(current)]'s contract fluff message") if("Edit Prison Time") var/new_time = input(usr, "Enter the new prison time in seconds:", "Edit Prison Time", CO.prison_time / 10) as num|null if(!new_time || new_time < 0) return CO.prison_time = new_time SECONDS log_admin("[key_name(usr)] has edited [key_name(current)]'s contract prison time to [new_time] seconds") message_admins("[key_name_admin(usr)] has edited [key_name_admin(current)]'s contract prison time to [new_time] seconds") if("Edit Credits Reward") var/new_creds = input(usr, "Enter the new credits reward:", "Edit Credits Reward", CO.reward_credits) as num|null if(!new_creds || new_creds < 0) return CO.reward_credits = new_creds log_admin("[key_name(usr)] has edited [key_name(current)]'s contract reward credits to [new_creds]") message_admins("[key_name_admin(usr)] has edited [key_name_admin(current)]'s contract reward credits to [new_creds]") if("Delete Contract") if(CO.status == CONTRACT_STATUS_ACTIVE) CO.fail("Contract interrupted forcibly.") H.contracts -= CO log_admin("[key_name(usr)] has deleted [key_name(current)]'s contract") message_admins("[key_name_admin(usr)] has deleted [key_name_admin(current)]'s contract") else return SStgui.update_uis(H) if("interrupt") if(!H) return var/datum/syndicate_contract/CO = locateUID(href_list["cuid"]) if(!istype(CO) || CO.status != CONTRACT_STATUS_ACTIVE) return H.current_contract = null CO.contract.extraction_zone = null CO.status = CONTRACT_STATUS_INACTIVE CO.clean_up() log_admin("[key_name(usr)] has interrupted [key_name(current)]'s contract") message_admins("[key_name_admin(usr)] has interrupted [key_name_admin(current)]'s contract") if("fail") if(!H) return var/datum/syndicate_contract/CO = locateUID(href_list["cuid"]) if(!istype(CO) || CO.status != CONTRACT_STATUS_ACTIVE) return var/fail_reason = sanitize(input(usr, "Enter the fail reason:", "Fail Contract") as text|null) if(!fail_reason || CO.status != CONTRACT_STATUS_ACTIVE) return CO.fail(fail_reason) SStgui.update_uis(H) log_admin("[key_name(usr)] has failed [key_name(current)]'s contract with reason: [fail_reason]") message_admins("[key_name_admin(usr)] has failed [key_name_admin(current)]'s contract with reason: [fail_reason]") else if(href_list["mindslave"]) switch(href_list["mindslave"]) if("clear") if(has_antag_datum(/datum/antagonist/mindslave, FALSE)) var/mob/living/carbon/human/H = current for(var/i in H.contents) if(istype(i, /obj/item/bio_chip/traitor)) qdel(i) break remove_antag_datum(/datum/antagonist/mindslave) log_admin("[key_name(usr)] has de-mindslaved [key_name(current)]") message_admins("[key_name_admin(usr)] has de-mindslaved [key_name_admin(current)]") else if(href_list["abductor"]) switch(href_list["abductor"]) if("clear") to_chat(usr, "Not implemented yet. Sorry!") //ticker.mode.update_abductor_icons_removed(src) if("abductor") if(!ishuman(current)) to_chat(usr, "This only works on humans!") return make_Abductor() log_admin("[key_name(usr)] turned [current] into abductor.") SSticker.mode.update_abductor_icons_added(src) current.create_log(MISC_LOG, "[current] was made into an abductor by [key_name_admin(usr)]") 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["silicon"]) switch(href_list["silicon"]) if("unemag") var/mob/living/silicon/robot/R = current if(!istype(R)) return R.unemag() log_admin("[key_name(usr)] has un-emagged [key_name(current)]") message_admins("[key_name_admin(usr)] has un-emagged [key_name_admin(current)]") if("unemagcyborgs") if(!isAI(current)) return var/mob/living/silicon/ai/ai = current for(var/mob/living/silicon/robot/R in ai.connected_robots) R.unemag() log_admin("[key_name(usr)] has unemagged [key_name(ai)]'s cyborgs") message_admins("[key_name_admin(usr)] has unemagged [key_name_admin(ai)]'s cyborgs") else if(href_list["common"]) switch(href_list["common"]) if("undress") for(var/obj/item/I in current) current.unEquip(I, TRUE) log_admin("[key_name(usr)] has unequipped [key_name(current)]") message_admins("[key_name_admin(usr)] has unequipped [key_name_admin(current)]") if("takeuplink") take_uplink() var/datum/antagonist/traitor/T = has_antag_datum(/datum/antagonist/traitor) T.antag_memory = "" //Remove any antag memory they may have had (uplink codes, code phrases) log_admin("[key_name(usr)] has taken [key_name(current)]'s uplink") message_admins("[key_name_admin(usr)] has taken [key_name_admin(current)]'s uplink") if("crystals") if(usr.client.holder.rights & (R_SERVER|R_EVENT)) var/obj/item/uplink/hidden/suplink = find_syndicate_uplink() var/crystals if(suplink) crystals = suplink.uses crystals = input("Amount of telecrystals for [key]","Syndicate uplink", crystals) as null|num if(!isnull(crystals)) if(suplink) suplink.uses = crystals log_admin("[key_name(usr)] has set [key_name(current)]'s telecrystals to [crystals]") message_admins("[key_name_admin(usr)] has set [key_name_admin(current)]'s telecrystals to [crystals]") if("uplink") if(has_antag_datum(/datum/antagonist/traitor)) var/datum/antagonist/traitor/T = has_antag_datum(/datum/antagonist/traitor) if(!T.give_uplink()) to_chat(usr, "Equipping a syndicate failed!") return log_admin("[key_name(usr)] has given [key_name(current)] an uplink") message_admins("[key_name_admin(usr)] has given [key_name_admin(current)] an uplink") else if(href_list["obj_announce"]) var/list/messages = prepare_announce_objectives() to_chat(current, chat_box_red(messages.Join("
"))) SEND_SOUND(current, sound('sound/ambience/alarm4.ogg')) log_admin("[key_name(usr)] has announced [key_name(current)]'s objectives") message_admins("[key_name_admin(usr)] has announced [key_name_admin(current)]'s objectives") edit_memory() /** * Create and/or add the `datum_type_or_instance` antag datum to the src mind. * * Arguments: * * datum_type - an antag datum typepath or instance * * datum/team/team - the antag team that the src mind should join, if any */ /datum/mind/proc/add_antag_datum(datum_type_or_instance, datum/team/team = null) var/datum/antagonist/A if(!ispath(datum_type_or_instance)) A = datum_type_or_instance if(!istype(A)) return else A = new datum_type_or_instance() 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() if(antag_team) antag_team.add_member(src) ASSERT(A.owner && A.owner.current) A.on_gain() return A /** * Remove the specified `datum_type` antag datum from the src mind. * * Arguments: * * datum_type - an antag datum typepath */ /datum/mind/proc/remove_antag_datum(datum_type, check_subtypes = TRUE) var/datum/antagonist/A = has_antag_datum(datum_type, check_subtypes) qdel(A) /** * Removes all antag datums from the src mind. * * Use this over doing `QDEL_LIST_CONTENTS(antag_datums)`. */ /datum/mind/proc/remove_all_antag_datums(handle_target_cryo = FALSE) // This is not `QDEL_LIST_CONTENTS(antag_datums)`because it's possible for the `antag_datums` list to be set to null during deletion of an antag datum. // Then `QDEL_LIST` would runtime because it would be doing `null.Cut()`. for(var/datum/antagonist/A as anything in antag_datums) if(handle_target_cryo) A.on_cryo() qdel(A) antag_datums?.Cut() antag_datums = null /// This proc sets the hijack speed for a mob. If greater than zero, they can hijack. Outputs in seconds. /datum/mind/proc/get_hijack_speed() var/hijack_speed = 0 if(special_role) hijack_speed = 15 SECONDS if(locate(/datum/objective/hijack) in get_all_objectives()) hijack_speed = 10 SECONDS return hijack_speed /** * Returns an antag datum instance if the src mind has the specified `datum_type`. Returns `null` otherwise. * * Arguments: * * datum_type - an antag datum typepath * * check_subtypes - TRUE if this proc will consider subtypes of `datum_type` as valid. FALSE if only the exact same type should be considered. */ /datum/mind/proc/has_antag_datum(datum_type, check_subtypes = TRUE) for(var/datum/antagonist/A as anything in antag_datums) if(check_subtypes && istype(A, datum_type)) return A else if(A.type == datum_type) return A /datum/mind/proc/prepare_announce_objectives(title = TRUE) if(!current) return var/list/text = list() if(title) text.Add("Your current objectives:") text.Add(gen_objective_text()) return text /datum/mind/proc/find_syndicate_uplink() var/list/L = current.get_contents() for(var/obj/item/I in L) if(I.hidden_uplink) return I.hidden_uplink return null /datum/mind/proc/take_uplink() var/obj/item/uplink/hidden/H = find_syndicate_uplink() if(H) qdel(H) /datum/mind/proc/make_Traitor() if(!has_antag_datum(/datum/antagonist/traitor)) add_antag_datum(/datum/antagonist/traitor) /datum/mind/proc/make_Nuke() if(!(src in SSticker.mode.syndicates)) SSticker.mode.syndicates += src SSticker.mode.update_synd_icons_added(src) if(SSticker.mode.syndicates.len==1) SSticker.mode.prepare_syndicate_leader(src) else current.real_name = "[syndicate_name()] Operative #[SSticker.mode.syndicates.len-1]" special_role = SPECIAL_ROLE_NUKEOPS assigned_role = SPECIAL_ROLE_NUKEOPS to_chat(current, "You are a [syndicate_name()] agent!") SSticker.mode.forge_syndicate_objectives(src) SSticker.mode.greet_syndicate(src, FALSE) // False to fix the agent message appearing twice current.loc = get_turf(locate("landmark*Syndicate-Spawn")) var/mob/living/carbon/human/H = current qdel(H.belt) qdel(H.back) qdel(H.l_ear) qdel(H.r_ear) qdel(H.gloves) qdel(H.head) qdel(H.shoes) qdel(H.wear_id) qdel(H.wear_pda) qdel(H.wear_suit) qdel(H.w_uniform) SSticker.mode.equip_syndicate(current) /datum/mind/proc/make_vampire() if(!has_antag_datum(/datum/antagonist/vampire)) add_antag_datum(/datum/antagonist/vampire) /datum/mind/proc/make_Overmind() if(!(src in SSticker.mode.blob_overminds)) SSticker.mode.blob_overminds += src special_role = SPECIAL_ROLE_BLOB_OVERMIND /datum/mind/proc/make_Wizard() if(!(src in SSticker.mode.wizards)) SSticker.mode.wizards += src special_role = SPECIAL_ROLE_WIZARD assigned_role = SPECIAL_ROLE_WIZARD //ticker.mode.learn_basic_spells(current) if(!GLOB.wizardstart.len) current.loc = pick(GLOB.latejoin) to_chat(current, "HOT INSERTION, GO GO GO") else current.loc = pick(GLOB.wizardstart) SSticker.mode.equip_wizard(current) for(var/obj/item/spellbook/S in current.contents) S.op = 0 INVOKE_ASYNC(SSticker.mode, TYPE_PROC_REF(/datum/game_mode/wizard, name_wizard), current) SSticker.mode.forge_wizard_objectives(src) SSticker.mode.greet_wizard(src) SSticker.mode.update_wiz_icons_added(src) /datum/mind/proc/make_Abductor() var/role = alert("Abductor Role ?","Role","Agent","Scientist") var/team = input("Abductor Team ?","Team ?") in list(1,2,3,4) var/teleport = alert("Teleport to ship ?","Teleport","Yes","No") if(!role || !team || !teleport) return if(!ishuman(current)) return SSticker.mode.abductors |= src add_mind_objective(/datum/objective/stay_hidden) add_mind_objective(/datum/objective/experiment) var/mob/living/carbon/human/H = current H.set_species(/datum/species/abductor) var/datum/species/abductor/S = H.dna.species if(role == "Scientist") S.scientist = TRUE S.team = team var/list/obj/effect/landmark/abductor/agent_landmarks = new var/list/obj/effect/landmark/abductor/scientist_landmarks = new agent_landmarks.len = 4 scientist_landmarks.len = 4 for(var/obj/effect/landmark/abductor/A in GLOB.landmarks_list) if(istype(A, /obj/effect/landmark/abductor/agent)) agent_landmarks[text2num(A.team)] = A else if(istype(A, /obj/effect/landmark/abductor/scientist)) scientist_landmarks[text2num(A.team)] = A var/obj/effect/landmark/L if(teleport == "Yes") switch(role) if("Agent") L = agent_landmarks[team] if("Scientist") L = agent_landmarks[team] H.forceMove(L.loc) SEND_SOUND(H, sound('sound/ambience/antag/abductors.ogg')) H.create_log(MISC_LOG, "[H] was made into an abductor") /datum/mind/proc/AddSpell(obj/effect/proc_holder/spell/S) spell_list += S S.action.Grant(current) /datum/mind/proc/RemoveSpell(obj/effect/proc_holder/spell/spell) //To remove a specific spell from a mind if(!spell) return for(var/obj/effect/proc_holder/spell/S in spell_list) if(istype(S, spell)) qdel(S) spell_list -= S /datum/mind/proc/transfer_actions(mob/living/new_character) if(current && current.actions) for(var/datum/action/A in current.actions) A.Grant(new_character) transfer_mindbound_actions(new_character) /datum/mind/proc/transfer_mindbound_actions(mob/living/new_character) for(var/X in spell_list) var/obj/effect/proc_holder/spell/S = X if(!S.on_mind_transfer(new_character)) current.RemoveSpell(S) continue S.action.Grant(new_character) /datum/mind/proc/get_ghost(even_if_they_cant_reenter) for(var/mob/dead/observer/G in GLOB.dead_mob_list) if(G.mind == src) if(G.can_reenter_corpse || even_if_they_cant_reenter) return G break /datum/mind/proc/grab_ghost(force) var/mob/dead/observer/G = get_ghost(even_if_they_cant_reenter = force) . = G if(G) G.reenter_corpse() /datum/mind/proc/make_zealot(mob/living/carbon/human/missionary, convert_duration = 10 MINUTES, team_color = "red") zealot_master = missionary // Give the new zealot their mindslave datum with a custom greeting. var/greeting = "You're now a loyal zealot of [missionary.name]! You now must lay down your life to protect [missionary.p_them()] and assist in [missionary.p_their()] goals at any cost." add_antag_datum(new /datum/antagonist/mindslave(missionary.mind, greeting)) var/obj/item/clothing/under/jumpsuit = null if(ishuman(current)) //only bother with the jumpsuit stuff if we are a human type, since we won't have the slot otherwise var/mob/living/carbon/human/H = current if(H.w_uniform) jumpsuit = H.w_uniform jumpsuit.color = team_color H.update_inv_w_uniform() add_attack_logs(missionary, current, "Converted to a zealot for [convert_duration/600] minutes") addtimer(CALLBACK(src, PROC_REF(remove_zealot), jumpsuit), convert_duration) //deconverts after the timer expires return TRUE /datum/mind/proc/remove_zealot(obj/item/clothing/under/jumpsuit = null) if(!zealot_master) //if they aren't a zealot, we can't remove their zealot status, obviously. don't bother with the rest so we don't confuse them with the messages return remove_antag_datum(/datum/antagonist/mindslave) add_attack_logs(zealot_master, current, "Lost control of zealot") zealot_master = null if(jumpsuit) jumpsuit.color = initial(jumpsuit.color) //reset the jumpsuit no matter where our mind is if(ishuman(current)) //but only try updating us if we are still a human type since it is a human proc var/mob/living/carbon/human/H = current H.update_inv_w_uniform() to_chat(current, "You seem to have forgotten the events of the past 10 minutes or so, and your head aches a bit as if someone beat it savagely with a stick.") to_chat(current, "This means you don't remember who you were working for or what you were doing.") //Initialisation procs /mob/proc/mind_initialize() if(mind) mind.key = key else mind = new /datum/mind(key) if(SSticker) SSticker.minds += mind else error("mind_initialize(): No ticker ready yet! Please inform Carn") if(!mind.name) mind.name = real_name mind.current = src //HUMAN /mob/living/carbon/human/mind_initialize() ..() if(!mind.assigned_role) mind.assigned_role = "Assistant" //defualt /mob/proc/sync_mind() mind_initialize() //updates the mind (or creates and initializes one if one doesn't exist) mind.active = TRUE //indicates that the mind is currently synced with a client //slime /mob/living/simple_animal/slime/mind_initialize() ..() mind.assigned_role = "slime" //XENO /mob/living/carbon/alien/mind_initialize() ..() mind.assigned_role = "Alien" //XENO HUMANOID /mob/living/carbon/alien/humanoid/queen/mind_initialize() ..() mind.special_role = SPECIAL_ROLE_XENOMORPH_QUEEN /mob/living/carbon/alien/humanoid/hunter/mind_initialize() ..() mind.special_role = SPECIAL_ROLE_XENOMORPH_HUNTER /mob/living/carbon/alien/humanoid/drone/mind_initialize() ..() mind.special_role = SPECIAL_ROLE_XENOMORPH_DRONE /mob/living/carbon/alien/humanoid/sentinel/mind_initialize() ..() mind.special_role = SPECIAL_ROLE_XENOMORPH_SENTINEL //XENO LARVA /mob/living/carbon/alien/larva/mind_initialize() ..() mind.special_role = SPECIAL_ROLE_XENOMORPH_LARVA //AI /mob/living/silicon/ai/mind_initialize() ..() mind.assigned_role = "AI" //BORG /mob/living/silicon/robot/mind_initialize() ..() mind.assigned_role = "Cyborg" //PAI /mob/living/silicon/pai/mind_initialize() ..() mind.assigned_role = "pAI" mind.special_role = null //BLOB /mob/camera/overmind/mind_initialize() ..() mind.special_role = SPECIAL_ROLE_BLOB //Animals /mob/living/simple_animal/mind_initialize() ..() mind.assigned_role = "Animal" /mob/living/simple_animal/pet/dog/corgi/mind_initialize() ..() mind.assigned_role = "Corgi" /mob/living/simple_animal/shade/mind_initialize() ..() mind.assigned_role = "Shade" /mob/living/simple_animal/hostile/construct/builder/mind_initialize() ..() mind.assigned_role = "Artificer" mind.special_role = SPECIAL_ROLE_CULTIST /mob/living/simple_animal/hostile/construct/wraith/mind_initialize() ..() mind.assigned_role = "Wraith" mind.special_role = SPECIAL_ROLE_CULTIST /mob/living/simple_animal/hostile/construct/armoured/mind_initialize() ..() mind.assigned_role = "Juggernaut" mind.special_role = SPECIAL_ROLE_CULTIST