mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-12 18:51:53 +00:00
cl ShizCalev tweak: Added some examine messages to disembodied heads indicating if it's missing eyes, or if it's brain is nonfunctional. tweak: Added some examine messages to cyborg parts to indicate their current construction status. tweak: You can now remove the power cell and cut the wiring out of a cyborg chest during construction. /cl Small indicator to help alleviate some minor wastes of time (such as folks bringing suicider's heads to the roboticist instead of the chef.) Added some missing destroy handling, fixed vars not being set and unset properly, cleaned up some duplicate code in human/examine handling for departed souls.
722 lines
24 KiB
Plaintext
722 lines
24 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 transferring 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 mind 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
|
|
var/active = 0
|
|
|
|
var/memory
|
|
|
|
var/assigned_role
|
|
var/special_role
|
|
var/list/restricted_roles = list()
|
|
|
|
var/list/spell_list = list() // Wizard mode & "Give Spell" badmin button.
|
|
|
|
var/linglink
|
|
var/datum/martial_art/martial_art
|
|
var/static/default_martial_art = new/datum/martial_art
|
|
var/miming = 0 // Mime's vow of silence
|
|
var/list/antag_datums
|
|
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/damnation_type = 0
|
|
var/datum/mind/soulOwner //who owns the soul. Under normal circumstances, this will point to src
|
|
var/hasSoul = TRUE // If false, renders the character unable to sell their soul.
|
|
var/isholy = FALSE //is this person a chaplain or admin role allowed to use bibles
|
|
|
|
var/mob/living/enslaved_to //If this mind's master is another mob (i.e. adamantine golems)
|
|
var/datum/language_holder/language_holder
|
|
var/unconvertable = FALSE
|
|
var/late_joiner = FALSE
|
|
|
|
var/force_escaped = FALSE // Set by Into The Sunset command of the shuttle manipulator
|
|
|
|
/datum/mind/New(var/key)
|
|
src.key = key
|
|
soulOwner = src
|
|
martial_art = default_martial_art
|
|
|
|
/datum/mind/Destroy()
|
|
SSticker.minds -= src
|
|
if(islist(antag_datums))
|
|
for(var/i in antag_datums)
|
|
var/datum/antagonist/antag_datum = i
|
|
if(antag_datum.delete_on_mind_deletion)
|
|
qdel(i)
|
|
antag_datums = null
|
|
return ..()
|
|
|
|
/datum/mind/proc/get_language_holder()
|
|
if(!language_holder)
|
|
var/datum/language_holder/L = current.get_language_holder(shadow=FALSE)
|
|
language_holder = L.copy(src)
|
|
|
|
return language_holder
|
|
|
|
/datum/mind/proc/transfer_to(mob/new_character, var/force_key_move = 0)
|
|
if(current) // remove ourself from our old body's mind variable
|
|
current.mind = null
|
|
SStgui.on_transfer(current, new_character)
|
|
|
|
if(!language_holder)
|
|
var/datum/language_holder/mob_holder = new_character.get_language_holder(shadow = FALSE)
|
|
language_holder = mob_holder.copy(src)
|
|
|
|
if(key)
|
|
if(new_character.key != key) //if we're transferring into a body with a key associated which is not ours
|
|
new_character.ghostize(1) //we'll need to ghostize so that key isn't mobless.
|
|
else
|
|
key = new_character.key
|
|
|
|
if(new_character.mind) //disassociate any mind currently in our new body's mind variable
|
|
new_character.mind.current = null
|
|
|
|
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(current)
|
|
current.transfer_observers_to(new_character) //transfer anyone observing the old character to the new one
|
|
current = new_character //associate ourself with our new body
|
|
new_character.mind = src //and associate our new body with 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)
|
|
if(iscarbon(new_character))
|
|
var/mob/living/carbon/C = new_character
|
|
C.last_mind = src
|
|
transfer_antag_huds(hud_to_transfer) //inherit the antag HUD
|
|
transfer_actions(new_character)
|
|
transfer_martial_arts(new_character)
|
|
if(active || force_key_move)
|
|
new_character.key = key //now transfer the key to link the client to our new body
|
|
|
|
/datum/mind/proc/store_memory(new_text)
|
|
memory += "[new_text]<BR>"
|
|
|
|
/datum/mind/proc/wipe_memory()
|
|
memory = null
|
|
|
|
// Datum antag mind procs
|
|
/datum/mind/proc/add_antag_datum(datum_type_or_instance, team)
|
|
if(!datum_type_or_instance)
|
|
return
|
|
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()
|
|
//Choose snowflake variation if antagonist handles it
|
|
var/datum/antagonist/S = A.specialization(src)
|
|
if(S && S != A)
|
|
qdel(A)
|
|
A = S
|
|
if(!A.can_be_owned(src))
|
|
qdel(A)
|
|
return
|
|
A.owner = src
|
|
LAZYADD(antag_datums, A)
|
|
A.create_team(team)
|
|
var/datum/team/antag_team = A.get_team()
|
|
if(antag_team)
|
|
antag_team.add_member(src)
|
|
A.on_gain()
|
|
return A
|
|
|
|
/datum/mind/proc/remove_antag_datum(datum_type)
|
|
if(!datum_type)
|
|
return
|
|
var/datum/antagonist/A = has_antag_datum(datum_type)
|
|
if(A)
|
|
A.on_removal()
|
|
return TRUE
|
|
|
|
|
|
/datum/mind/proc/remove_all_antag_datums() //For the Lazy amongst us.
|
|
for(var/a in antag_datums)
|
|
var/datum/antagonist/A = a
|
|
A.on_removal()
|
|
|
|
/datum/mind/proc/has_antag_datum(datum_type, check_subtypes = TRUE)
|
|
if(!datum_type)
|
|
return
|
|
. = FALSE
|
|
for(var/a in antag_datums)
|
|
var/datum/antagonist/A = a
|
|
if(check_subtypes && istype(A, datum_type))
|
|
return A
|
|
else if(A.type == datum_type)
|
|
return A
|
|
|
|
/*
|
|
Removes antag type's references from a mind.
|
|
objectives, uplinks, powers etc are all handled.
|
|
*/
|
|
|
|
/datum/mind/proc/remove_changeling()
|
|
var/datum/antagonist/changeling/C = has_antag_datum(/datum/antagonist/changeling)
|
|
if(C)
|
|
remove_antag_datum(/datum/antagonist/changeling)
|
|
special_role = null
|
|
|
|
/datum/mind/proc/remove_traitor()
|
|
remove_antag_datum(/datum/antagonist/traitor)
|
|
|
|
/datum/mind/proc/remove_brother()
|
|
if(src in SSticker.mode.brothers)
|
|
remove_antag_datum(/datum/antagonist/brother)
|
|
SSticker.mode.update_brother_icons_removed(src)
|
|
|
|
/datum/mind/proc/remove_nukeop()
|
|
var/datum/antagonist/nukeop/nuke = has_antag_datum(/datum/antagonist/nukeop,TRUE)
|
|
if(nuke)
|
|
remove_antag_datum(nuke.type)
|
|
special_role = null
|
|
|
|
/datum/mind/proc/remove_wizard()
|
|
remove_antag_datum(/datum/antagonist/wizard)
|
|
special_role = null
|
|
|
|
/datum/mind/proc/remove_cultist()
|
|
if(src in SSticker.mode.cult)
|
|
SSticker.mode.remove_cultist(src, 0, 0)
|
|
special_role = null
|
|
remove_antag_equip()
|
|
|
|
/datum/mind/proc/remove_rev()
|
|
var/datum/antagonist/rev/rev = has_antag_datum(/datum/antagonist/rev)
|
|
if(rev)
|
|
remove_antag_datum(rev.type)
|
|
special_role = null
|
|
|
|
|
|
/datum/mind/proc/remove_antag_equip()
|
|
var/list/Mob_Contents = current.get_contents()
|
|
for(var/obj/item/I in Mob_Contents)
|
|
var/datum/component/uplink/O = I.GetComponent(/datum/component/uplink) //Todo make this reset signal
|
|
if(O)
|
|
O.unlock_code = null
|
|
|
|
/datum/mind/proc/remove_all_antag() //For the Lazy amongst us.
|
|
remove_changeling()
|
|
remove_traitor()
|
|
remove_nukeop()
|
|
remove_wizard()
|
|
remove_cultist()
|
|
remove_rev()
|
|
SSticker.mode.update_cult_icons_removed(src)
|
|
|
|
/datum/mind/proc/equip_traitor(employer = "The Syndicate", silent = FALSE, datum/antagonist/uplink_owner)
|
|
if(!current)
|
|
return
|
|
var/mob/living/carbon/human/traitor_mob = current
|
|
if (!istype(traitor_mob))
|
|
return
|
|
|
|
var/list/all_contents = traitor_mob.GetAllContents()
|
|
var/obj/item/pda/PDA = locate() in all_contents
|
|
var/obj/item/radio/R = locate() in all_contents
|
|
var/obj/item/pen/P
|
|
|
|
if (PDA) // Prioritize PDA pen, otherwise the pocket protector pens will be chosen, which causes numerous ahelps about missing uplink
|
|
P = locate() in PDA
|
|
if (!P) // If we couldn't find a pen in the PDA, or we didn't even have a PDA, do it the old way
|
|
P = locate() in all_contents
|
|
if(!P) // I do not have a pen.
|
|
var/obj/item/pen/inowhaveapen
|
|
if(istype(traitor_mob.back,/obj/item/storage)) //ok buddy you better have a backpack!
|
|
inowhaveapen = new /obj/item/pen(traitor_mob.back)
|
|
else
|
|
inowhaveapen = new /obj/item/pen(traitor_mob.loc)
|
|
traitor_mob.put_in_hands(inowhaveapen) // I hope you don't have arms and your traitor pen gets stolen for all this trouble you've caused.
|
|
P = inowhaveapen
|
|
|
|
var/obj/item/uplink_loc
|
|
|
|
if(traitor_mob.client && traitor_mob.client.prefs)
|
|
switch(traitor_mob.client.prefs.uplink_spawn_loc)
|
|
if(UPLINK_PDA)
|
|
uplink_loc = PDA
|
|
if(!uplink_loc)
|
|
uplink_loc = R
|
|
if(!uplink_loc)
|
|
uplink_loc = P
|
|
if(UPLINK_RADIO)
|
|
uplink_loc = R
|
|
if(!uplink_loc)
|
|
uplink_loc = PDA
|
|
if(!uplink_loc)
|
|
uplink_loc = P
|
|
if(UPLINK_PEN)
|
|
uplink_loc = P
|
|
if(!uplink_loc)
|
|
uplink_loc = PDA
|
|
if(!uplink_loc)
|
|
uplink_loc = R
|
|
|
|
if (!uplink_loc)
|
|
if(!silent)
|
|
to_chat(traitor_mob, "Unfortunately, [employer] wasn't able to get you an Uplink.")
|
|
. = 0
|
|
else
|
|
. = uplink_loc
|
|
var/datum/component/uplink/U = uplink_loc.AddComponent(/datum/component/uplink, traitor_mob.key)
|
|
if(!U)
|
|
CRASH("Uplink creation failed.")
|
|
U.setup_unlock_code()
|
|
if(!silent)
|
|
if(uplink_loc == R)
|
|
to_chat(traitor_mob, "[employer] has cunningly disguised a Syndicate Uplink as your [R.name]. Simply dial the frequency [format_frequency(U.unlock_code)] to unlock its hidden features.")
|
|
else if(uplink_loc == PDA)
|
|
to_chat(traitor_mob, "[employer] has cunningly disguised a Syndicate Uplink as your [PDA.name]. Simply enter the code \"[U.unlock_code]\" into the ringtone select to unlock its hidden features.")
|
|
else if(uplink_loc == P)
|
|
to_chat(traitor_mob, "[employer] has cunningly disguised a Syndicate Uplink as your [P.name]. Simply twist the top of the pen [U.unlock_code] from its starting position to unlock its hidden features.")
|
|
|
|
if(uplink_owner)
|
|
uplink_owner.antag_memory += U.unlock_note + "<br>"
|
|
else
|
|
traitor_mob.mind.store_memory(U.unlock_note)
|
|
|
|
//Link a new mobs mind to the creator of said mob. They will join any team they are currently on, and will only switch teams when their creator does.
|
|
|
|
/datum/mind/proc/enslave_mind_to_creator(mob/living/creator)
|
|
if(iscultist(creator))
|
|
SSticker.mode.add_cultist(src)
|
|
|
|
else if(is_revolutionary(creator))
|
|
var/datum/antagonist/rev/converter = creator.mind.has_antag_datum(/datum/antagonist/rev,TRUE)
|
|
converter.add_revolutionary(src,FALSE)
|
|
|
|
else if(is_servant_of_ratvar(creator))
|
|
add_servant_of_ratvar(current)
|
|
|
|
else if(is_nuclear_operative(creator))
|
|
var/datum/antagonist/nukeop/converter = creator.mind.has_antag_datum(/datum/antagonist/nukeop,TRUE)
|
|
var/datum/antagonist/nukeop/N = new()
|
|
N.send_to_spawnpoint = FALSE
|
|
N.nukeop_outfit = null
|
|
add_antag_datum(N,converter.nuke_team)
|
|
|
|
|
|
enslaved_to = creator
|
|
|
|
current.faction |= creator.faction
|
|
creator.faction |= current.faction
|
|
|
|
if(creator.mind.special_role)
|
|
message_admins("[ADMIN_LOOKUPFLW(current)] has been created by [ADMIN_LOOKUPFLW(creator)], an antagonist.")
|
|
to_chat(current, "<span class='userdanger'>Despite your creators current allegiances, your true master remains [creator.real_name]. If their loyalties change, so do yours. This will never change unless your creator's body is destroyed.</span>")
|
|
|
|
/datum/mind/proc/show_memory(mob/recipient, window=1)
|
|
if(!recipient)
|
|
recipient = current
|
|
var/output = "<B>[current.real_name]'s Memories:</B><br>"
|
|
output += memory
|
|
|
|
|
|
var/list/all_objectives = list()
|
|
for(var/datum/antagonist/A in antag_datums)
|
|
output += A.antag_memory
|
|
all_objectives |= A.objectives
|
|
|
|
if(all_objectives.len)
|
|
output += "<B>Objectives:</B>"
|
|
var/obj_count = 1
|
|
for(var/datum/objective/objective in all_objectives)
|
|
output += "<br><B>Objective #[obj_count++]</B>: [objective.explanation_text]"
|
|
var/list/datum/mind/other_owners = objective.get_owners() - src
|
|
if(other_owners.len)
|
|
output += "<ul>"
|
|
for(var/datum/mind/M in other_owners)
|
|
output += "<li>Conspirator: [M.name]</li>"
|
|
output += "</ul>"
|
|
|
|
if(window)
|
|
recipient << browse(output,"window=memory")
|
|
else if(all_objectives.len || memory)
|
|
to_chat(recipient, "<i>[output]</i>")
|
|
|
|
/datum/mind/Topic(href, href_list)
|
|
if(!check_rights(R_ADMIN))
|
|
return
|
|
|
|
var/self_antagging = usr == current
|
|
|
|
if(href_list["add_antag"])
|
|
add_antag_wrapper(text2path(href_list["add_antag"]),usr)
|
|
if(href_list["remove_antag"])
|
|
var/datum/antagonist/A = locate(href_list["remove_antag"]) in antag_datums
|
|
if(!istype(A))
|
|
to_chat(usr,"<span class='warning'>Invalid antagonist ref to be removed.</span>")
|
|
return
|
|
A.admin_remove(usr)
|
|
|
|
if (href_list["role_edit"])
|
|
var/new_role = input("Select new role", "Assigned role", assigned_role) as null|anything in get_all_jobs()
|
|
if (!new_role)
|
|
return
|
|
assigned_role = new_role
|
|
|
|
else if (href_list["memory_edit"])
|
|
var/new_memo = copytext(sanitize(input("Write new memory", "Memory", memory) as null|message),1,MAX_MESSAGE_LEN)
|
|
if (isnull(new_memo))
|
|
return
|
|
memory = new_memo
|
|
|
|
else if (href_list["obj_edit"] || href_list["obj_add"])
|
|
var/objective_pos //Edited objectives need to keep same order in antag objective list
|
|
var/def_value
|
|
var/datum/antagonist/target_antag
|
|
var/datum/objective/old_objective //The old objective we're replacing/editing
|
|
var/datum/objective/new_objective //New objective we're be adding
|
|
|
|
if(href_list["obj_edit"])
|
|
for(var/datum/antagonist/A in antag_datums)
|
|
old_objective = locate(href_list["obj_edit"]) in A.objectives
|
|
if(old_objective)
|
|
target_antag = A
|
|
objective_pos = A.objectives.Find(old_objective)
|
|
break
|
|
if(!old_objective)
|
|
to_chat(usr,"Invalid objective.")
|
|
return
|
|
else
|
|
if(href_list["target_antag"])
|
|
var/datum/antagonist/X = locate(href_list["target_antag"]) in antag_datums
|
|
if(X)
|
|
target_antag = X
|
|
if(!target_antag)
|
|
switch(antag_datums.len)
|
|
if(0)
|
|
target_antag = add_antag_datum(/datum/antagonist/custom)
|
|
if(1)
|
|
target_antag = antag_datums[1]
|
|
else
|
|
var/datum/antagonist/target = input("Which antagonist gets the objective:", "Antagonist", "(new custom antag)") as null|anything in antag_datums + "(new custom antag)"
|
|
if (QDELETED(target))
|
|
return
|
|
else if(target == "(new custom antag)")
|
|
target_antag = add_antag_datum(/datum/antagonist/custom)
|
|
else
|
|
target_antag = target
|
|
|
|
if(!GLOB.admin_objective_list)
|
|
generate_admin_objective_list()
|
|
|
|
if(old_objective)
|
|
if(old_objective.name in GLOB.admin_objective_list)
|
|
def_value = old_objective.name
|
|
|
|
var/selected_type = input("Select objective type:", "Objective type", def_value) as null|anything in GLOB.admin_objective_list
|
|
selected_type = GLOB.admin_objective_list[selected_type]
|
|
if (!selected_type)
|
|
return
|
|
|
|
if(!old_objective)
|
|
//Add new one
|
|
new_objective = new selected_type
|
|
new_objective.owner = src
|
|
new_objective.admin_edit(usr)
|
|
target_antag.objectives += new_objective
|
|
message_admins("[key_name_admin(usr)] added a new objective for [current]: [new_objective.explanation_text]")
|
|
log_admin("[key_name(usr)] added a new objective for [current]: [new_objective.explanation_text]")
|
|
else
|
|
if(old_objective.type == selected_type)
|
|
//Edit the old
|
|
old_objective.admin_edit(usr)
|
|
new_objective = old_objective
|
|
else
|
|
//Replace the old
|
|
new_objective = new selected_type
|
|
new_objective.owner = src
|
|
new_objective.admin_edit(usr)
|
|
target_antag.objectives -= old_objective
|
|
target_antag.objectives.Insert(objective_pos, new_objective)
|
|
message_admins("[key_name_admin(usr)] edited [current]'s objective to [new_objective.explanation_text]")
|
|
log_admin("[key_name(usr)] edited [current]'s objective to [new_objective.explanation_text]")
|
|
|
|
else if (href_list["obj_delete"])
|
|
var/datum/objective/objective
|
|
for(var/datum/antagonist/A in antag_datums)
|
|
objective = locate(href_list["obj_delete"]) in A.objectives
|
|
if(istype(objective))
|
|
A.objectives -= objective
|
|
break
|
|
if(!objective)
|
|
to_chat(usr,"Invalid objective.")
|
|
return
|
|
//qdel(objective) Needs cleaning objective destroys
|
|
message_admins("[key_name_admin(usr)] removed an objective for [current]: [objective.explanation_text]")
|
|
log_admin("[key_name(usr)] removed an objective for [current]: [objective.explanation_text]")
|
|
|
|
else if(href_list["obj_completed"])
|
|
var/datum/objective/objective
|
|
for(var/datum/antagonist/A in antag_datums)
|
|
objective = locate(href_list["obj_completed"]) in A.objectives
|
|
if(istype(objective))
|
|
objective = objective
|
|
break
|
|
if(!objective)
|
|
to_chat(usr,"Invalid objective.")
|
|
return
|
|
objective.completed = !objective.completed
|
|
log_admin("[key_name(usr)] toggled the win state for [current]'s objective: [objective.explanation_text]")
|
|
|
|
else if (href_list["silicon"])
|
|
switch(href_list["silicon"])
|
|
if("unemag")
|
|
var/mob/living/silicon/robot/R = current
|
|
if (istype(R))
|
|
R.SetEmagged(0)
|
|
message_admins("[key_name_admin(usr)] has unemag'ed [R].")
|
|
log_admin("[key_name(usr)] has unemag'ed [R].")
|
|
|
|
if("unemagcyborgs")
|
|
if(isAI(current))
|
|
var/mob/living/silicon/ai/ai = current
|
|
for (var/mob/living/silicon/robot/R in ai.connected_robots)
|
|
R.SetEmagged(0)
|
|
message_admins("[key_name_admin(usr)] has unemag'ed [ai]'s Cyborgs.")
|
|
log_admin("[key_name(usr)] has unemag'ed [ai]'s Cyborgs.")
|
|
|
|
else if (href_list["common"])
|
|
switch(href_list["common"])
|
|
if("undress")
|
|
for(var/obj/item/W in current)
|
|
current.dropItemToGround(W, TRUE) //The 1 forces all items to drop, since this is an admin undress.
|
|
if("takeuplink")
|
|
take_uplink()
|
|
memory = null//Remove any memory they may have had.
|
|
log_admin("[key_name(usr)] removed [current]'s uplink.")
|
|
if("crystals")
|
|
if(check_rights(R_FUN, 0))
|
|
var/datum/component/uplink/U = find_syndicate_uplink()
|
|
if(U)
|
|
var/crystals = input("Amount of telecrystals for [key]","Syndicate uplink", U.telecrystals) as null | num
|
|
if(!isnull(crystals))
|
|
U.telecrystals = crystals
|
|
message_admins("[key_name_admin(usr)] changed [current]'s telecrystal count to [crystals].")
|
|
log_admin("[key_name(usr)] changed [current]'s telecrystal count to [crystals].")
|
|
if("uplink")
|
|
if(!equip_traitor())
|
|
to_chat(usr, "<span class='danger'>Equipping a syndicate failed!</span>")
|
|
log_admin("[key_name(usr)] tried and failed to give [current] an uplink.")
|
|
else
|
|
log_admin("[key_name(usr)] gave [current] an uplink.")
|
|
|
|
else if (href_list["obj_announce"])
|
|
announce_objectives()
|
|
|
|
//Something in here might have changed your mob
|
|
if(self_antagging && (!usr || !usr.client) && current.client)
|
|
usr = current
|
|
traitor_panel()
|
|
|
|
|
|
/datum/mind/proc/get_all_objectives()
|
|
var/list/all_objectives = list()
|
|
for(var/datum/antagonist/A in antag_datums)
|
|
all_objectives |= A.objectives
|
|
return all_objectives
|
|
|
|
/datum/mind/proc/announce_objectives()
|
|
var/obj_count = 1
|
|
to_chat(current, "<span class='notice'>Your current objectives:</span>")
|
|
for(var/objective in get_all_objectives())
|
|
var/datum/objective/O = objective
|
|
to_chat(current, "<B>Objective #[obj_count]</B>: [O.explanation_text]")
|
|
obj_count++
|
|
|
|
/datum/mind/proc/find_syndicate_uplink()
|
|
var/list/L = current.GetAllContents()
|
|
for (var/i in L)
|
|
var/atom/movable/I = i
|
|
. = I.GetComponent(/datum/component/uplink)
|
|
if(.)
|
|
break
|
|
|
|
/datum/mind/proc/take_uplink()
|
|
qdel(find_syndicate_uplink())
|
|
|
|
/datum/mind/proc/make_Traitor()
|
|
if(!(has_antag_datum(/datum/antagonist/traitor)))
|
|
add_antag_datum(/datum/antagonist/traitor)
|
|
|
|
/datum/mind/proc/make_Changeling()
|
|
var/datum/antagonist/changeling/C = has_antag_datum(/datum/antagonist/changeling)
|
|
if(!C)
|
|
C = add_antag_datum(/datum/antagonist/changeling)
|
|
special_role = ROLE_CHANGELING
|
|
return C
|
|
|
|
/datum/mind/proc/make_Wizard()
|
|
if(!has_antag_datum(/datum/antagonist/wizard))
|
|
special_role = ROLE_WIZARD
|
|
assigned_role = ROLE_WIZARD
|
|
add_antag_datum(/datum/antagonist/wizard)
|
|
|
|
|
|
/datum/mind/proc/make_Cultist()
|
|
if(!has_antag_datum(/datum/antagonist/cult,TRUE))
|
|
SSticker.mode.add_cultist(src,FALSE,equip=TRUE)
|
|
special_role = ROLE_CULTIST
|
|
to_chat(current, "<font color=\"purple\"><b><i>You catch a glimpse of the Realm of Nar'Sie, The Geometer of Blood. You now see how flimsy your world is, you see that it should be open to the knowledge of Nar'Sie.</b></i></font>")
|
|
to_chat(current, "<font color=\"purple\"><b><i>Assist your new brethren in their dark dealings. Their goal is yours, and yours is theirs. You serve the Dark One above all else. Bring It back.</b></i></font>")
|
|
|
|
/datum/mind/proc/make_Rev()
|
|
var/datum/antagonist/rev/head/head = new()
|
|
head.give_flash = TRUE
|
|
head.give_hud = TRUE
|
|
add_antag_datum(head)
|
|
special_role = ROLE_REV_HEAD
|
|
|
|
/datum/mind/proc/AddSpell(obj/effect/proc_holder/spell/S)
|
|
spell_list += S
|
|
S.action.Grant(current)
|
|
|
|
/datum/mind/proc/owns_soul()
|
|
return soulOwner == src
|
|
|
|
//To remove a specific spell from a mind
|
|
/datum/mind/proc/RemoveSpell(obj/effect/proc_holder/spell/spell)
|
|
if(!spell)
|
|
return
|
|
for(var/X in spell_list)
|
|
var/obj/effect/proc_holder/spell/S = X
|
|
if(istype(S, spell))
|
|
spell_list -= S
|
|
qdel(S)
|
|
|
|
/datum/mind/proc/RemoveAllSpells()
|
|
for(var/obj/effect/proc_holder/S in spell_list)
|
|
RemoveSpell(S)
|
|
|
|
/datum/mind/proc/transfer_martial_arts(mob/living/new_character)
|
|
if(!ishuman(new_character))
|
|
return
|
|
if(martial_art)
|
|
if(martial_art.base) //Is the martial art temporary?
|
|
martial_art.remove(new_character)
|
|
else
|
|
martial_art.teach(new_character)
|
|
|
|
/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
|
|
S.action.Grant(new_character)
|
|
|
|
/datum/mind/proc/disrupt_spells(delay, list/exceptions = New())
|
|
for(var/X in spell_list)
|
|
var/obj/effect/proc_holder/spell/S = X
|
|
for(var/type in exceptions)
|
|
if(istype(S, type))
|
|
continue
|
|
S.charge_counter = delay
|
|
S.updateButtonIcon()
|
|
INVOKE_ASYNC(S, /obj/effect/proc_holder/spell.proc/start_recharge)
|
|
|
|
/datum/mind/proc/get_ghost(even_if_they_cant_reenter, ghosts_with_clients)
|
|
for(var/mob/dead/observer/G in (ghosts_with_clients ? GLOB.player_list : 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/has_objective(objective_type)
|
|
for(var/datum/antagonist/A in antag_datums)
|
|
for(var/O in A.objectives)
|
|
if(istype(O,objective_type))
|
|
return TRUE
|
|
|
|
/mob/proc/sync_mind()
|
|
mind_initialize() //updates the mind (or creates and initializes one if one doesn't exist)
|
|
mind.active = 1 //indicates that the mind is currently synced with a client
|
|
|
|
/mob/dead/new_player/sync_mind()
|
|
return
|
|
|
|
/mob/dead/observer/sync_mind()
|
|
return
|
|
|
|
//Initialisation procs
|
|
/mob/proc/mind_initialize()
|
|
if(mind)
|
|
mind.key = key
|
|
|
|
else
|
|
mind = new /datum/mind(key)
|
|
SSticker.minds += mind
|
|
if(!mind.name)
|
|
mind.name = real_name
|
|
mind.current = src
|
|
|
|
/mob/living/carbon/mind_initialize()
|
|
..()
|
|
last_mind = mind
|
|
|
|
//HUMAN
|
|
/mob/living/carbon/human/mind_initialize()
|
|
..()
|
|
if(!mind.assigned_role)
|
|
mind.assigned_role = "Unassigned" //default
|
|
|
|
//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 = ROLE_PAI
|
|
mind.special_role = ""
|