Files
Paradise/code/datums/mind.dm
Qwertytoforty c398e4a617 Adds 2 cybernetic implants, makes emag_act return TRUE (#23876)
* Adds 2 cybernetic implants, makes emag_act return TRUE

* the rest of the fucking owl

* yeah that would do it

* remove this

* Apply suggestions from code review

Co-authored-by: Henri215 <77684085+Henri215@users.noreply.github.com>

* request changes, scaling burn damage, 3 tile range, lowers tech level

* Apply suggestions from code review

Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com>

* Update code/game/objects/structures/crates_lockers/crates.dm

Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com>

* Update scanners.dm

* Apply suggestions from code review

Co-authored-by: DGamerL <108773801+DGamerL@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com>

* Lewcs good to them?

* Apply suggestions from code review

Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com>

* fuck me

* there are no message admins in ba-sing

---------

Co-authored-by: Henri215 <77684085+Henri215@users.noreply.github.com>
Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com>
Co-authored-by: DGamerL <108773801+DGamerL@users.noreply.github.com>
Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com>
2024-02-08 12:52:11 +00:00

1892 lines
77 KiB
Plaintext

/* 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]<br>"
/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("<B>[current.real_name]'s Memories:</B><HR>")
output.Add(memory)
for(var/datum/antagonist/A in antag_datums)
output.Add(A.antag_memory)
if(has_objectives())
output.Add("<HR><B>Objectives:</B>")
output.Add(gen_objective_text())
if(LAZYLEN(job_objectives))
output.Add("<HR><B>Job Objectives:</B><UL>")
var/obj_count = 1
for(var/datum/job_objective/objective in job_objectives)
output.Add("<LI><B>Task #[obj_count]</B>: [objective.description]</LI>")
obj_count++
output.Add("</UL>")
output = output.Join("<br>")
if(window)
recipient << browse(output, "window=memory")
else
to_chat(recipient, "<i>[output]</i>")
/datum/mind/proc/gen_objective_text(admin = FALSE)
if(!has_objectives())
return "<b>No Objectives.</b><br>"
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("<b>Objective #[obj_count++]</b>: [objective.explanation_text][admin ? get_admin_objective_edit(objective) : ""]")
return text.Join("<br>")
/datum/mind/proc/get_admin_objective_edit(datum/objective/objective)
return " <a href='?src=[UID()];obj_edit=\ref[objective]'>Edit</a> \
<a href='?src=[UID()];obj_delete=\ref[objective]'>Delete</a> \
<a href='?src=[UID()];obj_completed=\ref[objective]'>\
<font color=[objective.completed ? "green" : "red"]>Toggle Completion</font></a>"
/**
* 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(.)
. = "<i><b>[.]</b></i>: "
/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:<a href='?src=[UID()];implant=remove'>Remove</a>|<b><font color='green'>Implanted</font></b></br>"
else
. = "Mindshield Bio-chip:<b>No Bio-chip</b>|<a href='?src=[UID()];implant=add'>Bio-chip [H.p_them()]!</a></br>"
/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))
. += "<b>NO</b>|headrev|rev"
else if(istype(rev, /datum/antagonist/rev/head))
. += "<a href='?src=[UID()];revolution=clear'>no</a>|<b><font color='red'>HEADREV</font></b>|<a href='?src=[UID()];revolution=rev'>rev</a>"
. += "<br>Flash: <a href='?src=[UID()];revolution=flash'>give</a>"
var/list/L = current.get_contents()
var/obj/item/flash/flash = locate() in L
if(flash)
if(!flash.broken)
. += "|<a href='?src=[UID()];revolution=takeflash'>take</a>."
else
. += "|<a href='?src=[UID()];revolution=takeflash'>take</a>|<a href='?src=[UID()];revolution=repairflash'>repair</a>."
else
. += "."
. += " <a href='?src=[UID()];revolution=reequip'>Reequip</a> (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
. += "<br>Objectives are empty! Unless theres no command, this is likely a bug, please report it! <a href='?src=[UID()];revolution=autoobjectives'>Set to kill all heads</a>."
else if(rev)
. += "<a href='?src=[UID()];revolution=clear'>no</a>|<a href='?src=[UID()];revolution=headrev'>headrev</a>|<b><font color='red'>REV</font></b>"
else
. += "<b>NO</b>|<a href='?src=[UID()];revolution=headrev'>headrev</a>|<a href='?src=[UID()];revolution=rev'>rev</a>"
. += _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)
. += "<a href='?src=[UID()];cult=clear'>no</a>|<b><font color='red'>CULTIST</font></b>"
. += "<br>Give <a href='?src=[UID()];cult=dagger'>dagger</a>|<a href='?src=[UID()];cult=runedmetal'>runedmetal</a>."
else
. += "<b>NO</b>|<a href='?src=[UID()];cult=cultist'>cultist</a>"
. += _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)
. += "<b><font color='red'>WIZARD</font></b>|<a href='?src=[UID()];wizard=clear'>no</a>"
. += "<br><a href='?src=[UID()];wizard=lair'>To lair</a>, <a href='?src=[UID()];common=undress'>undress</a>, <a href='?src=[UID()];wizard=dressup'>dress up</a>, <a href='?src=[UID()];wizard=name'>let choose name</a>."
if(!objective_holder.has_objectives())
. += "<br>Objectives are empty! <a href='?src=[UID()];wizard=autoobjectives'>Randomize!</a>"
else
. += "<a href='?src=[UID()];wizard=wizard'>wizard</a>|<b>NO</b>"
. += _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)
. += "<b><font color='red'>CHANGELING</font></b>|<a href='?src=[UID()];changeling=clear'>no</a>"
if(!cling.has_antag_objectives())
. += "<br>Objectives are empty! <a href='?src=[UID()];changeling=autoobjectives'>Randomize!</a>"
if(length(cling.absorbed_dna))
var/datum/dna/DNA = cling.absorbed_dna[1]
if(current.real_name != DNA.real_name)
. += "<br><a href='?src=[UID()];changeling=initialdna'>Transform to initial appearance.</a>"
else
. += "<a href='?src=[UID()];changeling=changeling'>changeling</a>|<b>NO</b>"
. += _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)
. += "<b><font color='red'>VAMPIRE</font></b>|<a href='?src=[UID()];vampire=clear'>no</a>"
. += "<br>Usable blood: <a href='?src=[UID()];vampire=edit_usable_blood'>[vamp.bloodusable]</a>"
. += " | Total blood: <a href='?src=[UID()];vampire=edit_total_blood'>[vamp.bloodtotal]</a>"
var/has_subclass = !QDELETED(vamp.subclass)
. += "<br>Subclass: <a href='?src=[UID()];vampire=change_subclass'>[has_subclass ? capitalize(vamp.subclass.name) : "None"]</a>"
if(has_subclass)
. += " | Force full power: <a href='?src=[UID()];vampire=full_power_override'>[vamp.subclass.full_power_override ? "Yes" : "No"]</a>"
if(!vamp.has_antag_objectives())
. += "<br>Objectives are empty! <a href='?src=[UID()];vampire=autoobjectives'>Randomize!</a>"
else
. += "<a href='?src=[UID()];vampire=vampire'>vampire</a>|<b>NO</b>"
. += _memory_edit_role_enabled(ROLE_VAMPIRE)
/** Enthralled ***/
. += "<br><b><i>enthralled</i></b>: "
if(has_antag_datum(/datum/antagonist/mindslave/thrall))
. += "<b><font color='red'>THRALL</font></b>|<a href='?src=[UID()];vampthrall=clear'>no</a>"
else
. += "thrall|<b>NO</b>"
/datum/mind/proc/memory_edit_nuclear(mob/living/carbon/human/H)
. = _memory_edit_header("nuclear")
if(src in SSticker.mode.syndicates)
. += "<b><font color='red'>OPERATIVE</b></font>|<a href='?src=[UID()];nuclear=clear'>no</a>"
. += "<br><a href='?src=[UID()];nuclear=lair'>To shuttle</a>, <a href='?src=[UID()];common=undress'>undress</a>, <a href='?src=[UID()];nuclear=dressup'>dress up</a>."
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]. <a href='?src=[UID()];nuclear=tellcode'>tell the code.</a>"
else
. += "<a href='?src=[UID()];nuclear=nuclear'>operative</a>|<b>NO</b>"
. += _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)
. += "<b><font color='red'>ABDUCTOR</font></b>|<a href='?src=[UID()];abductor=clear'>no</a>"
. += "|<a href='?src=[UID()];common=undress'>undress</a>|<a href='?src=[UID()];abductor=equip'>equip</a>"
else
. += "<a href='?src=[UID()];abductor=abductor'>abductor</a>|<b>NO</b>"
. += _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)
. += "<b>YES</b>|<a href='?src=[UID()];eventmisc=clear'>no</a>"
else
. += "<a href='?src=[UID()];eventmisc=eventmisc'>Event Role</a>|<b>NO</b>"
/datum/mind/proc/memory_edit_traitor()
. = _memory_edit_header("traitor", list("traitorchan", "traitorvamp"))
if(has_antag_datum(/datum/antagonist/traitor))
. += "<b><font color='red'>TRAITOR</font></b>|<a href='?src=[UID()];traitor=clear'>no</a>"
var/datum/antagonist/traitor/T = has_antag_datum(/datum/antagonist/traitor)
if(!T.has_antag_objectives())
. += "<br>Objectives are empty! <a href='?src=[UID()];traitor=autoobjectives'>Randomize!</a>"
else
. += "<a href='?src=[UID()];traitor=traitor'>traitor</a>|<b>NO</b>"
. += _memory_edit_role_enabled(ROLE_TRAITOR)
// Contractor
. += "<br><b><i>contractor</i></b>: "
var/datum/contractor_hub/H = LAZYACCESS(GLOB.contractors, src)
if(H)
. += "<b><font color='red'>CONTRACTOR</font></b>"
// List all their contracts
. += "<br><b>Contracts:</b>"
if(H.contracts)
var/count = 1
for(var/co in H.contracts)
var/datum/syndicate_contract/CO = co
. += "<br><B>Contract #[count++]</B>: "
. += "<a href='?src=[UID()];cuid=[CO.UID()];contractor=target'><b>[CO.contract.target?.name || "Invalid target!"]</b></a>|"
. += "<a href='?src=[UID()];cuid=[CO.UID()];contractor=locations'>locations</a>|"
. += "<a href='?src=[UID()];cuid=[CO.UID()];contractor=other'>more</a>|"
switch(CO.status)
if(CONTRACT_STATUS_INVALID)
. += "<b>INVALID</b>"
if(CONTRACT_STATUS_INACTIVE)
. += "inactive"
if(CONTRACT_STATUS_ACTIVE)
. += "<b><font color='orange'>ACTIVE</font></b>|"
. += "<a href='?src=[UID()];cuid=[CO.UID()];contractor=interrupt'>interrupt</a>|"
. += "<a href='?src=[UID()];cuid=[CO.UID()];contractor=fail'>fail</a>"
if(CONTRACT_STATUS_COMPLETED)
. += "<font color='green'>COMPLETED</font>"
if(CONTRACT_STATUS_FAILED)
. += "<font color='red'>FAILED</font>"
. += "<br>"
. += "<a href='?src=[UID()];contractor=add'>Add Contract</a><br>"
. += "Claimable TC: <a href='?src=[UID()];contractor=tc'>[H.reward_tc_available]</a><br>"
. += "Available Rep: <a href='?src=[UID()];contractor=rep'>[H.rep]</a><br>"
else
. += "<br>"
. += "<i>Has not logged in to contractor uplink</i>"
else
. += "<b>NO</b>"
// Mindslave
. += "<br><b><i>mindslaved</i></b>: "
if(has_antag_datum(/datum/antagonist/mindslave, FALSE))
. += "<b><font color='red'>MINDSLAVE</font></b>|<a href='?src=[UID()];mindslave=clear'>no</a>"
else
. += "mindslave|<b>NO</b>"
/datum/mind/proc/memory_edit_silicon()
. = "<i><b>Silicon</b></i>: "
var/mob/living/silicon/robot/robot = current
if(istype(robot) && robot.emagged)
. += "<br>Cyborg: <b><font color='red'>Is emagged!</font></b> <a href='?src=[UID()];silicon=unemag'>Unemag!</a><br>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++
. += "<br>[n_e_robots] of [ai.connected_robots.len] slaved cyborgs are emagged. <a href='?src=[UID()];silicon=unemagcyborgs'>Unemag</a>"
/datum/mind/proc/memory_edit_uplink()
. = ""
if(ishuman(current) && ((has_antag_datum(/datum/antagonist/traitor)) || \
(src in SSticker.mode.syndicates)))
. = "Uplink: <a href='?src=[UID()];common=uplink'>give</a>"
var/obj/item/uplink/hidden/suplink = find_syndicate_uplink()
var/crystals
if(suplink)
crystals = suplink.uses
if(suplink)
. += "|<a href='?src=[UID()];common=takeuplink'>take</a>"
if(usr.client.holder.rights & (R_SERVER|R_EVENT))
. += ", <a href='?src=[UID()];common=crystals'>[crystals]</a> 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("<B>[name]</B>[(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]. <a href='?src=[UID()];role_edit=1'>Edit</a>")
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("<b>Memory:</b>")
out.Add(memory)
out.Add("<a href='?src=[UID()];memory_edit=1'>Edit memory</a><br>")
out.Add("Objectives:")
out.Add(gen_objective_text(admin = TRUE))
out.Add("<a href='?src=[UID()];obj_add=1'>Add objective</a><br>")
out.Add("<a href='?src=[UID()];obj_announce=1'>Announce objectives</a><br>")
usr << browse(out.Join("<br>"), "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, "<span class='warning'>No random target found. Pick one manually.</span>")
return
new_target = pick(possible_targets_random)
if(!new_target)
return
else
to_chat(usr, "<span class='warning'>No possible target found. Defaulting to a Free objective.</span>")
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, "<span class='notice'><font size='3'><b>Your mindshield bio-chip has been deactivated.</b></font></span>")
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, "<span class='userdanger'>You somehow have become the recipient of a mindshield transplant, and it just activated!</span>")
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, "<span class='userdanger'>The nanobots in the mindshield implant remove all thoughts about being a revolutionary. Get back to work!</span>")
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, "<span class='warning'>Spawning flash failed!</span>")
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, "<span class='warning'>Deleting flash failed!</span>")
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, "<span class='warning'>Repairing flash failed!</span>")
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, "<span class='warning'>Reequipping revolutionary went wrong!</span>")
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, "<span class='cultitalic'>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.</span>")
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, "<span class='warning'>Spawning dagger failed!</span>")
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, "<span class='warning'>Spawning runed metal failed!</span>")
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, "<span class='warning'><FONT size = 3><B>You have been brainwashed! You are no longer a wizard!</B></FONT></span>")
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, "<span class='danger'>You are a Space Wizard!</span>")
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, "<span class='notice'>The objectives for wizard [key] have been generated. You can edit them and announce manually.</span>")
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, "<span class='biggerdanger'>Your powers have awoken. A flash of memory returns to us... we are a changeling!</span>")
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, "<span class='notice'>The objectives for changeling [key] have been generated. You can edit them and announce manually.</span>")
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, "<span class='warning'>Resetting DNA failed!</span>")
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, "<FONT color='red' size = 3><B>You grow weak and lose your powers! You are no longer a vampire and are stuck in your current form!</B></FONT>")
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, "<B><font color='red'>Your powers have awoken. Your lust for blood grows... You are a Vampire!</font></B>")
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, "<span class='notice'>The objectives for vampire [key] have been generated. You can edit them and announce manually.</span>")
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, "<span class='warning'><FONT size = 3><B>You have been brainwashed! You are no longer a syndicate operative!</B></FONT></span>")
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, "<span class='notice'>You are a [syndicate_name()] agent!</span>")
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, "<span class='warning'>Equipping a syndicate failed!</span>")
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("<B>Syndicate Nuclear Bomb Code</B>: [code]", 0, 0)
to_chat(current, "The nuclear authorization code is: <B>[code]</B>")
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, "<span class='warning'>No valid nuke found!</span>")
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, "<span class='notice'>The objectives for traitor [key] have been generated. You can edit them and announce manually.</span>")
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, "<span class='warning'>This only works on humans!</span>")
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, "<span class='warning'>This only works on humans!</span>")
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, "<span class='warning'>Equipping a syndicate failed!</span>")
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("<br>")))
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("<span class='notice'>Your current objectives:</span>")
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, "<span class='notice'>You are a [syndicate_name()] agent!</span>")
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]!</B> 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, "<span class='warning'><b>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.</b></span>")
to_chat(current, "<span class='warning'><b>This means you don't remember who you were working for or what you were doing.</b></span>")
//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