mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-23 21:18:37 +01:00
Base implementation of /datum/persistent_client (#89449)
## About The Pull Request Converts `/datum/player_details` into `/datum/persistent_client`. Persistent Clients persist across connections. The only time a mob's persistent client will change is if the ckey it's bound to logs into a different mob, or the mob is deleted (duh). Also adds PossessByPlayer() so that transfering mob control is cleaner and makes more immediate sense if you don't know byond-fu. ## Why It's Good For The Game Clients are an abstract representation of a connection that can be dropped at almost any moment so putting things that should be stable to access at any time onto an undying object is ideal. This allows for future expansions like abstracting away client.screen and managing everything cleanly.
This commit is contained in:
@@ -49,3 +49,6 @@
|
||||
/// A null statement to guard against EmptyBlock lint without necessitating the use of pass()
|
||||
/// Used to avoid proc-call overhead. But use sparingly. Probably pointless in most places.
|
||||
#define EMPTY_BLOCK_GUARD ;
|
||||
|
||||
/// Abstraction over using mob.client to just check if there's a connected player.
|
||||
#define HAS_CONNECTED_PLAYER(mob) (mob.client)
|
||||
|
||||
@@ -184,7 +184,7 @@
|
||||
|
||||
ghost_player.client.prefs.safe_transfer_prefs_to(new_character)
|
||||
new_character.dna.update_dna_identity()
|
||||
new_character.key = ghost_player.key
|
||||
new_character.PossessByPlayer(ghost_player.ckey)
|
||||
|
||||
return new_character
|
||||
|
||||
|
||||
@@ -18,11 +18,10 @@
|
||||
|
||||
// Cannot use the list as a map if the key is a number, so we stringify it (thank you BYOND)
|
||||
var/smessage_type = num2text(message_type, MAX_BITFLAG_DIGITS)
|
||||
var/datum/player_details/client_details = client?.player_details
|
||||
|
||||
if(!isnull(client_details))
|
||||
if(!islist(client_details.logging[smessage_type]))
|
||||
client_details.logging[smessage_type] = list()
|
||||
if(HAS_CONNECTED_PLAYER(src))
|
||||
if(!islist(persistent_client.logging[smessage_type]))
|
||||
persistent_client.logging[smessage_type] = list()
|
||||
|
||||
if(!islist(logging[smessage_type]))
|
||||
logging[smessage_type] = list()
|
||||
@@ -51,7 +50,7 @@
|
||||
|
||||
logging[smessage_type] += timestamped_message
|
||||
|
||||
if(client)
|
||||
client.player_details.logging[smessage_type] += timestamped_message
|
||||
if(HAS_CONNECTED_PLAYER(src))
|
||||
persistent_client.logging[smessage_type] += timestamped_message
|
||||
|
||||
..()
|
||||
|
||||
@@ -661,7 +661,7 @@ GLOBAL_LIST_INIT(achievements_unlocked, list())
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/give_show_report_button(client/C)
|
||||
var/datum/action/report/R = new
|
||||
C.player_details.player_actions += R
|
||||
C.persistent_client.player_actions += R
|
||||
R.Grant(C.mob)
|
||||
to_chat(C,span_infoplain("<a href='byond://?src=[REF(R)];report=1'>Show roundend report again</a>"))
|
||||
|
||||
|
||||
@@ -59,10 +59,9 @@ SUBSYSTEM_DEF(achievements)
|
||||
most_unlocked_achievement = instance
|
||||
qdel(query)
|
||||
|
||||
for(var/i in GLOB.clients)
|
||||
var/client/C = i
|
||||
if(!C.player_details.achievements.initialized)
|
||||
C.player_details.achievements.InitializeData()
|
||||
for(var/client/C in GLOB.clients)
|
||||
if(!C.persistent_client.achievements.initialized)
|
||||
C.persistent_client.achievements.InitializeData()
|
||||
|
||||
return SS_INIT_SUCCESS
|
||||
|
||||
@@ -71,11 +70,12 @@ SUBSYSTEM_DEF(achievements)
|
||||
|
||||
/datum/controller/subsystem/achievements/proc/save_achievements_to_db()
|
||||
var/list/cheevos_to_save = list()
|
||||
for(var/ckey in GLOB.player_details)
|
||||
var/datum/player_details/PD = GLOB.player_details[ckey]
|
||||
for(var/ckey in GLOB.persistent_clients_by_ckey)
|
||||
var/datum/persistent_client/PD = GLOB.persistent_clients_by_ckey[ckey]
|
||||
if(!PD || !PD.achievements)
|
||||
continue
|
||||
cheevos_to_save += PD.achievements.get_changed_data()
|
||||
|
||||
if(!length(cheevos_to_save))
|
||||
return
|
||||
SSdbcore.MassInsert(format_table_name("achievements"), cheevos_to_save, duplicate_key = TRUE)
|
||||
|
||||
@@ -86,9 +86,8 @@ SUBSYSTEM_DEF(blackbox)
|
||||
if (MS.rc_msgs.len)
|
||||
record_feedback("tally", "radio_usage", MS.rc_msgs.len, "request console")
|
||||
|
||||
for(var/player_key in GLOB.player_details)
|
||||
var/datum/player_details/PD = GLOB.player_details[player_key]
|
||||
record_feedback("tally", "client_byond_version", 1, PD.full_byond_version())
|
||||
for(var/datum/persistent_client/PC as anything in GLOB.persistent_clients)
|
||||
record_feedback("tally", "client_byond_version", 1, PC.full_byond_version())
|
||||
|
||||
/datum/controller/subsystem/blackbox/Shutdown()
|
||||
sealed = FALSE
|
||||
|
||||
@@ -538,7 +538,7 @@
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/xenomorph/generate_ruleset_body(mob/applicant)
|
||||
var/obj/vent = pick_n_take(vents)
|
||||
var/mob/living/carbon/alien/larva/new_xeno = new(vent.loc)
|
||||
new_xeno.key = applicant.key
|
||||
new_xeno.PossessByPlayer(applicant.ckey)
|
||||
new_xeno.move_into_vent(vent)
|
||||
message_admins("[ADMIN_LOOKUPFLW(new_xeno)] has been made into an alien by the midround ruleset.")
|
||||
log_dynamic("[key_name(new_xeno)] was spawned as an alien by the midround ruleset.")
|
||||
@@ -696,7 +696,7 @@
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/space_ninja/generate_ruleset_body(mob/applicant)
|
||||
var/mob/living/carbon/human/ninja = create_space_ninja(pick(spawn_locs))
|
||||
ninja.key = applicant.key
|
||||
ninja.PossessByPlayer(applicant.ckey)
|
||||
ninja.mind.add_antag_datum(/datum/antagonist/ninja)
|
||||
|
||||
message_admins("[ADMIN_LOOKUPFLW(ninja)] has been made into a Space Ninja by the midround ruleset.")
|
||||
@@ -769,7 +769,7 @@
|
||||
|
||||
/datum/dynamic_ruleset/midround/from_ghosts/revenant/generate_ruleset_body(mob/applicant)
|
||||
var/mob/living/basic/revenant/revenant = new(pick(spawn_locs))
|
||||
revenant.key = applicant.key
|
||||
revenant.PossessByPlayer(applicant.ckey)
|
||||
message_admins("[ADMIN_LOOKUPFLW(revenant)] has been made into a revenant by the midround ruleset.")
|
||||
log_game("[key_name(revenant)] was spawned as a revenant by the midround ruleset.")
|
||||
return revenant
|
||||
|
||||
@@ -240,7 +240,7 @@ SUBSYSTEM_DEF(vote)
|
||||
voting_action.name = "Vote: [current_vote.override_question || current_vote.name]"
|
||||
voting_action.Grant(new_voter.mob)
|
||||
|
||||
new_voter.player_details.player_actions += voting_action
|
||||
new_voter.persistent_client.player_actions += voting_action
|
||||
generated_actions += voting_action
|
||||
if(current_vote.vote_sound && new_voter.prefs.read_preference(/datum/preference/toggle/sound_announcements))
|
||||
SEND_SOUND(new_voter, sound(current_vote.vote_sound))
|
||||
@@ -472,12 +472,12 @@ SUBSYSTEM_DEF(vote)
|
||||
|
||||
// We also need to remove our action from the player actions when we're cleaning up.
|
||||
/datum/action/vote/Remove(mob/removed_from)
|
||||
if(removed_from.client)
|
||||
removed_from.client?.player_details.player_actions -= src
|
||||
if(removed_from.persistent_client)
|
||||
removed_from.persistent_client.player_actions -= src
|
||||
|
||||
else if(removed_from.ckey)
|
||||
var/datum/player_details/associated_details = GLOB.player_details[removed_from.ckey]
|
||||
associated_details?.player_actions -= src
|
||||
var/datum/persistent_client/persistent_client = GLOB.persistent_clients_by_ckey[removed_from.ckey]
|
||||
persistent_client?.player_actions -= src
|
||||
|
||||
return ..()
|
||||
|
||||
|
||||
@@ -131,4 +131,4 @@
|
||||
set name = "Check achievements"
|
||||
set desc = "See all of your achievements!"
|
||||
|
||||
player_details.achievements.ui_interact(usr)
|
||||
persistent_client.achievements.ui_interact(usr)
|
||||
|
||||
@@ -37,14 +37,16 @@
|
||||
|
||||
/datum/award/score/progress/fish/proc/validate_early_joiners(datum/source)
|
||||
for(var/client/client as anything in GLOB.clients)
|
||||
var/datum/achievement_data/holder = client.player_details.achievements
|
||||
var/datum/achievement_data/holder = client.persistent_client.achievements
|
||||
if(!holder?.initialized)
|
||||
continue
|
||||
|
||||
var/list/entries = holder.data[/datum/award/score/progress/fish]
|
||||
var/list_copied = FALSE
|
||||
for(var/fish_id in entries)
|
||||
if(SSfishing.catchable_fish[fish_id])
|
||||
continue
|
||||
|
||||
//make a new list, unbound from the cached awards data, so that the score can be updated at the end of the round.
|
||||
if(!list_copied)
|
||||
entries = entries.Copy()
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
friend.key = ghost.key
|
||||
friend.PossessByPlayer(ghost.ckey)
|
||||
friend.attach_to_owner(owner)
|
||||
friend.setup_appearance()
|
||||
friend_initialized = TRUE
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
stranger_backseat.key = ghost.key
|
||||
stranger_backseat.PossessByPlayer(ghost.ckey)
|
||||
stranger_backseat.log_message("became [key_name(owner)]'s split personality.", LOG_GAME)
|
||||
message_admins("[ADMIN_LOOKUPFLW(stranger_backseat)] became [ADMIN_LOOKUPFLW(owner)]'s split personality.")
|
||||
|
||||
@@ -222,7 +222,7 @@
|
||||
set waitfor = FALSE
|
||||
var/mob/chosen_one = SSpolling.poll_ghosts_for_target("Do you want to play as [span_danger("[owner.real_name]'s")] brainwashed mind?", poll_time = 7.5 SECONDS, checked_target = stranger_backseat, alert_pic = owner, role_name_text = "brainwashed mind")
|
||||
if(chosen_one)
|
||||
stranger_backseat.key = chosen_one.key
|
||||
stranger_backseat.PossessByPlayer(chosen_one.ckey)
|
||||
else
|
||||
qdel(src)
|
||||
|
||||
|
||||
@@ -145,7 +145,7 @@
|
||||
|
||||
harbinger.log_message("took control of [new_body].", LOG_GAME)
|
||||
// doesn't transfer mind because that transfers antag datum as well
|
||||
new_body.key = harbinger.key
|
||||
new_body.PossessByPlayer(harbinger.ckey)
|
||||
|
||||
// Already qdels due to below proc but just in case
|
||||
qdel(src)
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
aliver.death()
|
||||
aliver.visible_message(span_deadsay("[aliver.name]'s soul is struggling to return!"))
|
||||
else
|
||||
aliver.key = chosen_one.key
|
||||
aliver.PossessByPlayer(chosen_one.ckey)
|
||||
on_successful_revive?.Invoke(aliver)
|
||||
qdel(src)
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
if(affected_mob.mind)
|
||||
affected_mob.mind.transfer_to(new_mob)
|
||||
else
|
||||
new_mob.key = affected_mob.key
|
||||
new_mob.PossessByPlayer(affected_mob.ckey)
|
||||
if(transformed_antag_datum)
|
||||
new_mob.mind.add_antag_datum(transformed_antag_datum)
|
||||
new_mob.name = affected_mob.real_name
|
||||
@@ -89,14 +89,13 @@
|
||||
to_chat(affected_mob, span_userdanger("Your mob has been taken over by a ghost! Appeal your job ban if you want to avoid this in the future!"))
|
||||
message_admins("[key_name_admin(chosen_one)] has taken control of ([key_name_admin(affected_mob)]) to replace a jobbanned player.")
|
||||
affected_mob.ghostize(FALSE)
|
||||
affected_mob.key = chosen_one.key
|
||||
affected_mob.PossessByPlayer(chosen_one.ckey)
|
||||
else
|
||||
to_chat(new_mob, span_userdanger("Your mob has been claimed by death! Appeal your job ban if you want to avoid this in the future!"))
|
||||
new_mob.investigate_log("has been killed because there was no one to replace them as a job-banned player.", INVESTIGATE_DEATHS)
|
||||
new_mob.death()
|
||||
if (!QDELETED(new_mob))
|
||||
new_mob.ghostize(can_reenter_corpse = FALSE)
|
||||
new_mob.key = null
|
||||
|
||||
/datum/disease/transformation/jungle_flu
|
||||
name = "Jungle Flu"
|
||||
|
||||
@@ -205,7 +205,7 @@
|
||||
|
||||
RegisterSignal(new_character, COMSIG_LIVING_DEATH, PROC_REF(set_death_time))
|
||||
if(active || force_key_move)
|
||||
new_character.key = key //now transfer the key to link the client to our new body
|
||||
new_character.PossessByPlayer(key) //now transfer the key to link the client to our new body
|
||||
if(new_character.client)
|
||||
LAZYCLEARLIST(new_character.client.recent_examines)
|
||||
new_character.client.init_verbs() // re-initialize character specific verbs
|
||||
|
||||
@@ -183,7 +183,7 @@
|
||||
var/mob/living/basic/ghost/swarm/new_ghost = new(get_turf(src))
|
||||
ghosts_spawned += new_ghost
|
||||
new_ghost.ghostize(FALSE)
|
||||
new_ghost.key = candidate_ghost.key
|
||||
new_ghost.PossessByPlayer(candidate_ghost.key)
|
||||
var/policy = get_policy(ROLE_ANOMALY_GHOST)
|
||||
if(policy)
|
||||
to_chat(new_ghost, policy)
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
// Failed to find a player, or somehow detonated prematurely
|
||||
if(isnull(chosen_one))
|
||||
return
|
||||
pyro.key = chosen_one.key
|
||||
pyro.PossessByPlayer(chosen_one.key)
|
||||
pyro.mind.special_role = ROLE_PYROCLASTIC_SLIME
|
||||
pyro.mind.add_antag_datum(/datum/antagonist/pyro_slime)
|
||||
pyro.log_message("was made into a slime by pyroclastic anomaly", LOG_GAME)
|
||||
|
||||
@@ -432,7 +432,7 @@
|
||||
var/mob/chosen_one = SSpolling.poll_ghosts_for_target("Do you want to play as [span_danger("[user.real_name]'s")] [span_notice("Servant")]?", check_jobban = ROLE_WIZARD, role = ROLE_WIZARD, poll_time = 5 SECONDS, checked_target = human_servant, alert_pic = user, role_name_text = "dice servant")
|
||||
if(chosen_one)
|
||||
message_admins("[ADMIN_LOOKUPFLW(chosen_one)] was spawned as Dice Servant")
|
||||
human_servant.key = chosen_one.key
|
||||
human_servant.PossessByPlayer(chosen_one.key)
|
||||
|
||||
human_servant.equipOutfit(/datum/outfit/butler)
|
||||
var/datum/mind/servant_mind = new /datum/mind()
|
||||
|
||||
@@ -286,7 +286,7 @@ ADMIN_VERB(create_or_modify_area, R_DEBUG, "Create Or Modify Area", "Create of m
|
||||
log_admin("[key_name(usr)] stuffed [frommob.key] into [tomob.name].")
|
||||
BLACKBOX_LOG_ADMIN_VERB("Ghost Drag Control")
|
||||
|
||||
tomob.key = frommob.key
|
||||
tomob.PossessByPlayer(frommob.key)
|
||||
tomob.client?.init_verbs()
|
||||
qdel(frommob)
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
|
||||
message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(body)])")
|
||||
body.ghostize(FALSE)
|
||||
body.key = C.key
|
||||
body.PossessByPlayer(C.key)
|
||||
if (make_antag)
|
||||
body.mind.add_antag_datum(antag_type)
|
||||
continue
|
||||
|
||||
@@ -283,9 +283,8 @@
|
||||
M_rname_as_key = null
|
||||
|
||||
var/previous_names_string = ""
|
||||
var/datum/player_details/readable = GLOB.player_details[M.ckey]
|
||||
if(readable)
|
||||
previous_names_string = readable.get_played_names()
|
||||
if(M.persistent_client)
|
||||
previous_names_string = M.persistent_client.get_played_names()
|
||||
|
||||
//output for each mob
|
||||
dat += {"
|
||||
|
||||
@@ -62,11 +62,10 @@ ADMIN_VERB_ONLY_CONTEXT_MENU(show_player_panel, R_ADMIN, "Show Player Panel", mo
|
||||
|
||||
body += "<b>Mob type</b> = [player.type]<br><br>"
|
||||
|
||||
if(player.client)
|
||||
if(HAS_CONNECTED_PLAYER(player))
|
||||
body += "<b>Old names:</b> "
|
||||
var/datum/player_details/deets = GLOB.player_details[player.ckey]
|
||||
if(deets)
|
||||
body += deets.get_played_names()
|
||||
if(player.persistent_client)
|
||||
body += player.persistent_client.get_played_names()
|
||||
else
|
||||
body += "<i>None?!</i>"
|
||||
body += "<br><br>"
|
||||
@@ -196,7 +195,7 @@ ADMIN_VERB(respawn_character, R_ADMIN, "Respawn Character", "Respawn a player th
|
||||
var/mob/living/carbon/human/species/monkey/new_monkey = new
|
||||
SSjob.send_to_late_join(new_monkey)
|
||||
G_found.mind.transfer_to(new_monkey) //be careful when doing stuff like this! I've already checked the mind isn't in use
|
||||
new_monkey.key = G_found.key
|
||||
new_monkey.PossessByPlayer(G_found.key)
|
||||
to_chat(new_monkey, "You have been fully respawned. Enjoy the game.", confidential = TRUE)
|
||||
var/msg = span_adminnotice("[key_name_admin(user)] has respawned [new_monkey.key] as a filthy monkey.")
|
||||
message_admins(msg)
|
||||
@@ -231,7 +230,7 @@ ADMIN_VERB(respawn_character, R_ADMIN, "Respawn Character", "Respawn a player th
|
||||
if(is_unassigned_job(new_character.mind.assigned_role))
|
||||
new_character.mind.set_assigned_role(SSjob.get_job_type(SSjob.overflow_role))
|
||||
|
||||
new_character.key = G_found.key
|
||||
new_character.PossessByPlayer(G_found.key)
|
||||
|
||||
/*
|
||||
The code below functions with the assumption that the mob is already a traitor if they have a special role.
|
||||
|
||||
@@ -167,7 +167,9 @@ ADMIN_VERB(cmd_assume_direct_control, R_ADMIN, "Assume Direct Control", "Assume
|
||||
var/mob/adminmob = user.mob
|
||||
if(M.ckey)
|
||||
M.ghostize(FALSE)
|
||||
M.key = user.key
|
||||
|
||||
M.PossessByPlayer(user.key)
|
||||
|
||||
user.init_verbs()
|
||||
if(isobserver(adminmob))
|
||||
qdel(adminmob)
|
||||
|
||||
@@ -174,7 +174,7 @@
|
||||
var/chosen_outfit = usr.client?.prefs?.read_preference(/datum/preference/choiced/brief_outfit)
|
||||
usr.client.prefs.safe_transfer_prefs_to(admin_officer, is_antag = TRUE)
|
||||
admin_officer.equipOutfit(chosen_outfit)
|
||||
admin_officer.key = usr.key
|
||||
admin_officer.PossessByPlayer(usr.key)
|
||||
|
||||
else
|
||||
to_chat(usr, span_warning("Could not spawn you in as briefing officer as you are not a ghost!"))
|
||||
@@ -232,7 +232,7 @@
|
||||
else
|
||||
ert_operative = new /mob/living/carbon/human(spawnloc)
|
||||
chosen_candidate.client.prefs.safe_transfer_prefs_to(ert_operative, is_antag = TRUE)
|
||||
ert_operative.key = chosen_candidate.key
|
||||
ert_operative.PossessByPlayer(chosen_candidate.key)
|
||||
|
||||
if(ertemplate.enforce_human || !(ert_operative.dna.species.changesource_flags & ERT_SPAWN))
|
||||
ert_operative.set_species(/datum/species/human)
|
||||
|
||||
@@ -48,10 +48,9 @@
|
||||
dat += "<hr style='background:#000000; border:0; height:1px'>"
|
||||
|
||||
var/log_source = M.logging
|
||||
if(source == LOGSRC_CKEY && M.ckey)
|
||||
var/datum/player_details/details = GLOB.player_details[M.ckey]
|
||||
if(details) //we dont want to runtime if an admin aghosted
|
||||
log_source = details.logging
|
||||
if(source == LOGSRC_CKEY && M.persistent_client)
|
||||
log_source = M.persistent_client.logging
|
||||
|
||||
var/list/concatenated_logs = list()
|
||||
for(var/log_type in log_source)
|
||||
var/nlog_type = text2num(log_type)
|
||||
@@ -59,6 +58,7 @@
|
||||
var/list/all_the_entrys = log_source[log_type]
|
||||
for(var/entry in all_the_entrys)
|
||||
concatenated_logs += "<b>[entry]</b><br>[all_the_entrys[entry]]"
|
||||
|
||||
if(length(concatenated_logs))
|
||||
sortTim(concatenated_logs, cmp = GLOBAL_PROC_REF(cmp_text_dsc)) //Sort by timestamp.
|
||||
dat += "<font size=2px>"
|
||||
|
||||
@@ -639,7 +639,7 @@ ADMIN_VERB(secrets, R_NONE, "Secrets", "Abuse harder than you ever have before w
|
||||
chosen_candidate = pick(candidates)
|
||||
candidates -= chosen_candidate
|
||||
nerd = new /mob/living/basic/drone/classic(spawnpoint)
|
||||
nerd.key = chosen_candidate.key
|
||||
nerd.PossessByPlayer(chosen_candidate.key)
|
||||
nerd.log_message("has been selected as a Nanotrasen emergency response drone.", LOG_GAME)
|
||||
teamsize--
|
||||
|
||||
@@ -716,7 +716,7 @@ ADMIN_VERB(secrets, R_NONE, "Secrets", "Abuse harder than you ever have before w
|
||||
var/mob/chosen = players[1]
|
||||
if (chosen.client)
|
||||
chosen.client.prefs.safe_transfer_prefs_to(spawnedMob, is_antag = TRUE)
|
||||
spawnedMob.key = chosen.key
|
||||
spawnedMob.PossessByPlayer(chosen.key)
|
||||
players -= chosen
|
||||
if (ishuman(spawnedMob) && ispath(humanoutfit, /datum/outfit))
|
||||
var/mob/living/carbon/human/H = spawnedMob
|
||||
|
||||
@@ -306,7 +306,7 @@ GLOBAL_LIST_EMPTY(antagonists)
|
||||
message_admins("[key_name_admin(chosen_one)] has taken control of ([key_name_admin(owner)]) to replace antagonist banned player.")
|
||||
log_game("[key_name(chosen_one)] has taken control of ([key_name(owner)]) to replace antagonist banned player.")
|
||||
owner.current.ghostize(FALSE)
|
||||
owner.current.key = chosen_one.key
|
||||
owner.current.PossessByPlayer(chosen_one.key)
|
||||
else
|
||||
log_game("Couldn't find antagonist ban replacement for ([key_name(owner)]).")
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
new /obj/effect/particle_effect/fluid/smoke(T)
|
||||
var/mob/living/carbon/human/M = new/mob/living/carbon/human(T)
|
||||
C.prefs.safe_transfer_prefs_to(M, is_antag = TRUE)
|
||||
M.key = C.key
|
||||
M.PossessByPlayer(C.key)
|
||||
var/datum/mind/app_mind = M.mind
|
||||
|
||||
var/datum/antagonist/wizard/apprentice/app = new()
|
||||
@@ -247,7 +247,7 @@
|
||||
borg.mmi.brainmob.name = brainopsname
|
||||
borg.real_name = borg.name
|
||||
|
||||
borg.key = C.key
|
||||
borg.PossessByPlayer(C.key)
|
||||
|
||||
borg.mind.add_antag_datum(antag_datum, creator_op ? creator_op.get_team() : null)
|
||||
borg.mind.special_role = special_role_name
|
||||
@@ -290,7 +290,7 @@
|
||||
var/mob/living/basic/demon/spawned = new demon_type(T)
|
||||
new /obj/effect/dummy/phased_mob(T, spawned)
|
||||
|
||||
spawned.key = C.key
|
||||
spawned.PossessByPlayer(C.key)
|
||||
|
||||
/obj/item/antag_spawner/slaughter_demon/laughter
|
||||
name = "vial of tickles"
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
if(origin && (origin.current ? (origin.current.stat == DEAD) : origin.get_ghost()))
|
||||
origin.transfer_to(spawned_monkey)
|
||||
spawned_monkey.key = origin.key
|
||||
spawned_monkey.PossessByPlayer(origin.key)
|
||||
var/datum/antagonist/changeling/changeling_datum = origin.has_antag_datum(/datum/antagonist/changeling)
|
||||
if(!changeling_datum)
|
||||
changeling_datum = origin.add_antag_datum(/datum/antagonist/changeling/headslug)
|
||||
|
||||
@@ -371,7 +371,7 @@ Striking a noncultist, however, will tear their flesh."}
|
||||
|
||||
// Get the heretic's new body and antag datum.
|
||||
trapped_entity = trapped_mind?.current
|
||||
trapped_entity.key = trapped_mind?.key
|
||||
trapped_entity.PossessByPlayer(trapped_mind?.key)
|
||||
var/datum/antagonist/heretic/heretic_holder = GET_HERETIC(trapped_entity)
|
||||
if(!heretic_holder)
|
||||
stack_trace("[soul_to_bind] in but not a heretic on the heretic soul blade.")
|
||||
|
||||
@@ -771,7 +771,7 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0)
|
||||
to_chat(mob_to_revive.mind, "Your physical form has been taken over by another soul due to your inactivity! Ahelp if you wish to regain your form.")
|
||||
message_admins("[key_name_admin(chosen_one)] has taken control of ([key_name_admin(mob_to_revive)]) to replace an AFK player.")
|
||||
mob_to_revive.ghostize(FALSE)
|
||||
mob_to_revive.key = chosen_one.key
|
||||
mob_to_revive.PossessByPlayer(chosen_one.key)
|
||||
else
|
||||
fail_invoke()
|
||||
return
|
||||
@@ -1035,7 +1035,7 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0)
|
||||
old_mind = ghost_to_spawn.mind, \
|
||||
old_body = ghost_to_spawn.mind.current, \
|
||||
)
|
||||
new_human.key = ghost_to_spawn.key
|
||||
new_human.PossessByPlayer(ghost_to_spawn.key)
|
||||
var/datum/antagonist/cult/created_cultist = new_human.mind?.add_antag_datum(/datum/antagonist/cult)
|
||||
created_cultist?.silent = TRUE
|
||||
to_chat(new_human, span_cult_italic("<b>You are a servant of the Geometer. You have been made semi-corporeal by the cult of Nar'Sie, and you are to serve them at all costs.</b>"))
|
||||
|
||||
@@ -424,7 +424,7 @@
|
||||
summoned.move_resist = initial(summoned.move_resist)
|
||||
|
||||
summoned.ghostize(FALSE)
|
||||
summoned.key = chosen_one.key
|
||||
summoned.PossessByPlayer(chosen_one.key)
|
||||
|
||||
user.log_message("created a [summoned.name], controlled by [key_name(chosen_one)].", LOG_GAME)
|
||||
message_admins("[ADMIN_LOOKUPFLW(user)] created a [summoned.name], [ADMIN_LOOKUPFLW(summoned)].")
|
||||
|
||||
@@ -167,7 +167,7 @@
|
||||
return FALSE
|
||||
message_admins("[key_name_admin(chosen_one)] has taken control of ([key_name_admin(soon_to_be_ghoul)]) to replace an AFK player.")
|
||||
soon_to_be_ghoul.ghostize(FALSE)
|
||||
soon_to_be_ghoul.key = chosen_one.key
|
||||
soon_to_be_ghoul.PossessByPlayer(chosen_one.key)
|
||||
|
||||
selected_atoms -= soon_to_be_ghoul
|
||||
make_ghoul(user, soon_to_be_ghoul)
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
return FALSE
|
||||
var/monster_type = pick(monster_types)
|
||||
var/mob/living/monster = new monster_type(loc)
|
||||
monster.key = user.key
|
||||
monster.PossessByPlayer(user.key)
|
||||
monster.set_name()
|
||||
var/datum/antagonist/heretic_monster/woohoo_free_antag = new(src)
|
||||
monster.mind.add_antag_datum(woohoo_free_antag)
|
||||
|
||||
@@ -194,7 +194,7 @@
|
||||
|
||||
var/mob/living/carbon/human/nukie = new(spawn_loc)
|
||||
chosen_one.client.prefs.safe_transfer_prefs_to(nukie, is_antag = TRUE)
|
||||
nukie.key = chosen_one.key
|
||||
nukie.PossessByPlayer(chosen_one.key)
|
||||
|
||||
var/datum/antagonist/nukeop/antag_datum = new()
|
||||
antag_datum.send_to_spawnpoint = FALSE
|
||||
|
||||
@@ -265,7 +265,7 @@
|
||||
|
||||
if(!is_listed)
|
||||
ckey_list += user.ckey
|
||||
newcarp.key = user.key
|
||||
newcarp.PossessByPlayer(user.key)
|
||||
newcarp.set_name()
|
||||
var/datum/antagonist/space_carp/carp_antag = new(src)
|
||||
newcarp.mind.add_antag_datum(carp_antag)
|
||||
|
||||
@@ -392,7 +392,7 @@
|
||||
soulstone_spirit.AddComponent(/datum/component/soulstoned, src)
|
||||
soulstone_spirit.name = "Shade of [victim.real_name]"
|
||||
soulstone_spirit.real_name = "Shade of [victim.real_name]"
|
||||
soulstone_spirit.key = shade_controller.key
|
||||
soulstone_spirit.PossessByPlayer(shade_controller.key)
|
||||
soulstone_spirit.copy_languages(victim, LANGUAGE_MIND)//Copies the old mobs languages into the new mob holder.
|
||||
if(user)
|
||||
soulstone_spirit.copy_languages(user, LANGUAGE_MASTER)
|
||||
@@ -516,7 +516,7 @@
|
||||
seek_master.Grant(newstruct)
|
||||
|
||||
if (isnull(target.mind))
|
||||
newstruct.key = target.key
|
||||
newstruct.PossessByPlayer(target.key)
|
||||
else
|
||||
target.mind.transfer_to(newstruct, force_key_move = TRUE)
|
||||
var/atom/movable/screen/alert/bloodsense/sense_alert
|
||||
|
||||
@@ -198,7 +198,7 @@ GLOBAL_VAR(basketball_game)
|
||||
old_mind = player_client.mob.mind, \
|
||||
old_body = player_client.mob.mind.current, \
|
||||
)
|
||||
baller.key = player_key
|
||||
baller.PossessByPlayer(player_key)
|
||||
|
||||
SEND_SOUND(baller, sound('sound/items/whistle/whistle.ogg', volume=30))
|
||||
if(is_player_referee)
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
server_ref = WEAKREF(server)
|
||||
server.avatar_connection_refs.Add(WEAKREF(src))
|
||||
|
||||
avatar.key = old_body.key
|
||||
avatar.PossessByPlayer(old_body.key)
|
||||
ADD_TRAIT(avatar, TRAIT_NO_MINDSWAP, REF(src)) // do not remove this one
|
||||
ADD_TRAIT(old_body, TRAIT_MIND_TEMPORARILY_GONE, REF(src))
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@
|
||||
mutation_target.gib(DROP_ALL_REMAINS)
|
||||
|
||||
var/datum/mind/ghost_mind = ghost.mind
|
||||
new_mob.key = ghost.key
|
||||
new_mob.PossessByPlayer(ghost.key)
|
||||
|
||||
if(ghost_mind)
|
||||
new_mob.AddComponent(/datum/component/temporary_body, ghost_mind, ghost_mind.current, TRUE)
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
holder = c
|
||||
buttons = list()
|
||||
li_cb = CALLBACK(src, PROC_REF(post_login))
|
||||
holder.player_details.post_login_callbacks += li_cb
|
||||
holder.persistent_client.post_login_callbacks += li_cb
|
||||
holder.show_popup_menus = FALSE
|
||||
create_buttons()
|
||||
holder.screen += buttons
|
||||
@@ -47,7 +47,7 @@
|
||||
/datum/buildmode/Destroy()
|
||||
close_switchstates()
|
||||
close_preview()
|
||||
holder.player_details.post_login_callbacks -= li_cb
|
||||
holder.persistent_client.post_login_callbacks -= li_cb
|
||||
li_cb = null
|
||||
holder = null
|
||||
modebutton = null
|
||||
|
||||
@@ -138,7 +138,7 @@
|
||||
var/list/credits
|
||||
|
||||
///these persist between logins/logouts during the same round.
|
||||
var/datum/player_details/player_details
|
||||
var/datum/persistent_client/persistent_client
|
||||
|
||||
///Should only be a key-value list of north/south/east/west = atom/movable/screen.
|
||||
var/list/char_render_holders
|
||||
|
||||
@@ -249,6 +249,17 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
GLOB.clients += src
|
||||
GLOB.directory[ckey] = src
|
||||
|
||||
var/reconnecting = FALSE
|
||||
if(GLOB.persistent_clients_by_ckey[ckey])
|
||||
reconnecting = TRUE
|
||||
persistent_client = GLOB.persistent_clients_by_ckey[ckey]
|
||||
persistent_client.byond_build = byond_build
|
||||
persistent_client.byond_version = byond_version
|
||||
else
|
||||
persistent_client = new(ckey)
|
||||
persistent_client.byond_build = byond_build
|
||||
persistent_client.byond_version = byond_version
|
||||
|
||||
if(byond_version >= 516)
|
||||
winset(src, null, list("browser-options" = "find,refresh,byondstorage"))
|
||||
|
||||
@@ -328,18 +339,6 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
else
|
||||
message_admins(span_danger("<B>[message_type]: </B></span><span class='notice'>Connecting player [key_name_admin(src)] has the same [matches] as [joined_player_ckey](no longer logged in)<b>[in_round]</b>. "))
|
||||
log_admin_private("[message_type]: Connecting player [key_name(src)] has the same [matches] as [joined_player_ckey](no longer logged in)[in_round].")
|
||||
var/reconnecting = FALSE
|
||||
if(GLOB.player_details[ckey])
|
||||
reconnecting = TRUE
|
||||
player_details = GLOB.player_details[ckey]
|
||||
player_details.byond_version = byond_version
|
||||
player_details.byond_build = byond_build
|
||||
else
|
||||
player_details = new(ckey)
|
||||
player_details.byond_version = byond_version
|
||||
player_details.byond_build = byond_build
|
||||
GLOB.player_details[ckey] = player_details
|
||||
|
||||
|
||||
. = ..() //calls mob.Login()
|
||||
|
||||
@@ -586,6 +585,8 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
|
||||
GLOB.clients -= src
|
||||
GLOB.directory -= ckey
|
||||
persistent_client.client = null
|
||||
|
||||
log_access("Logout: [key_name(src)]")
|
||||
GLOB.ahelp_tickets.ClientLogout(src)
|
||||
GLOB.interviews.client_logout(src)
|
||||
@@ -1040,11 +1041,11 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
|
||||
|
||||
///Redirect proc that makes it easier to call the unlock achievement proc. Achievement type is the typepath to the award, user is the mob getting the award, and value is an optional variable used for leaderboard value increments
|
||||
/client/proc/give_award(achievement_type, mob/user, value = 1)
|
||||
return player_details.achievements.unlock(achievement_type, user, value)
|
||||
return persistent_client.achievements.unlock(achievement_type, user, value)
|
||||
|
||||
///Redirect proc that makes it easier to get the status of an achievement. Achievement type is the typepath to the award.
|
||||
/client/proc/get_award_status(achievement_type, mob/user, value = 1)
|
||||
return player_details.achievements.get_achievement_status(achievement_type)
|
||||
return persistent_client.achievements.get_achievement_status(achievement_type)
|
||||
|
||||
///Gives someone hearted status for OOC, from behavior commendations
|
||||
/client/proc/adjust_heart(duration = 24 HOURS)
|
||||
|
||||
@@ -1,55 +1,86 @@
|
||||
|
||||
///assoc list of ckey -> /datum/player_details
|
||||
GLOBAL_LIST_EMPTY_TYPED(player_details, /datum/player_details)
|
||||
///assoc list of ckey -> /datum/persistent_client
|
||||
GLOBAL_LIST_EMPTY_TYPED(persistent_clients_by_ckey, /datum/persistent_client)
|
||||
/// A flat list of all persistent clients, for her looping pleasure.
|
||||
GLOBAL_LIST_EMPTY_TYPED(persistent_clients, /datum/persistent_client)
|
||||
|
||||
/// Tracks information about a client between log in and log outs
|
||||
/datum/player_details
|
||||
/datum/persistent_client
|
||||
/// The true client
|
||||
var/client/client
|
||||
/// The mob this persistent client is currently bound to.
|
||||
var/mob/mob
|
||||
|
||||
/// Major version of BYOND this client is using.
|
||||
var/byond_version
|
||||
/// Build number of BYOND this client is using.
|
||||
var/byond_build
|
||||
|
||||
/// Action datums assigned to this player
|
||||
var/list/datum/action/player_actions = list()
|
||||
/// Tracks client action logging
|
||||
var/list/logging = list()
|
||||
|
||||
/// Callbacks invoked when this client logs in again
|
||||
var/list/post_login_callbacks = list()
|
||||
/// Callbacks invoked when this client logs out
|
||||
var/list/post_logout_callbacks = list()
|
||||
|
||||
/// List of names this key played under this round
|
||||
/// assoc list of name -> mob tag
|
||||
var/list/played_names = list()
|
||||
/// Lazylist of preference slots this client has joined the round under
|
||||
/// Numbers are stored as strings
|
||||
var/list/joined_as_slots
|
||||
/// Major version of BYOND this client is using.
|
||||
var/byond_version
|
||||
/// Build number of BYOND this client is using.
|
||||
var/byond_build
|
||||
|
||||
/// Tracks achievements they have earned
|
||||
var/datum/achievement_data/achievements
|
||||
|
||||
/// World.time this player last died
|
||||
var/time_of_death = 0
|
||||
|
||||
/datum/player_details/New(key)
|
||||
achievements = new(key)
|
||||
/datum/persistent_client/New(ckey, client)
|
||||
src.client = client
|
||||
achievements = new(ckey)
|
||||
GLOB.persistent_clients_by_ckey[ckey] = src
|
||||
GLOB.persistent_clients += src
|
||||
|
||||
/datum/persistent_client/Destroy(force)
|
||||
SHOULD_CALL_PARENT(FALSE)
|
||||
. = QDEL_HINT_LETMELIVE
|
||||
CRASH("Who the FUCK tried to delete a persistent client? Get your head checked you leadskull.")
|
||||
|
||||
/// Setter for the mob var, handles both references.
|
||||
/datum/persistent_client/proc/set_mob(mob/new_mob)
|
||||
if(mob == new_mob)
|
||||
return
|
||||
|
||||
mob?.persistent_client = null
|
||||
new_mob?.persistent_client?.set_mob(null)
|
||||
|
||||
mob = new_mob
|
||||
new_mob?.persistent_client = src
|
||||
|
||||
/// Writes all of the `played_names` into an HTML-escaped string.
|
||||
/datum/player_details/proc/get_played_names()
|
||||
/datum/persistent_client/proc/get_played_names()
|
||||
var/list/previous_names = list()
|
||||
for(var/previous_name in played_names)
|
||||
previous_names += html_encode("[previous_name] ([played_names[previous_name]])")
|
||||
return previous_names.Join("; ")
|
||||
|
||||
/// Returns the full version string (i.e 515.1642) of the BYOND version and build.
|
||||
/datum/player_details/proc/full_byond_version()
|
||||
/datum/persistent_client/proc/full_byond_version()
|
||||
if(!byond_version)
|
||||
return "Unknown"
|
||||
return "[byond_version].[byond_build || "xxx"]"
|
||||
|
||||
/// Adds the new names to the player's played_names list on their /datum/player_details for use of admins.
|
||||
/// Adds the new names to the player's played_names list on their /datum/persistent_client for use of admins.
|
||||
/// `ckey` should be their ckey, and `data` should be an associative list with the keys being the names they played under and the values being the unique mob ID tied to that name.
|
||||
/proc/log_played_names(ckey, data)
|
||||
if(!ckey)
|
||||
return
|
||||
|
||||
var/datum/player_details/writable = GLOB.player_details[ckey]
|
||||
var/datum/persistent_client/writable = GLOB.persistent_clients_by_ckey[ckey]
|
||||
if(isnull(writable))
|
||||
return
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
user.dropItemToGround(src)
|
||||
return
|
||||
|
||||
magnification.key = chosen_one.key
|
||||
magnification.PossessByPlayer(chosen_one.key)
|
||||
playsound(src, 'sound/machines/microwave/microwave-end.ogg', 100, FALSE)
|
||||
to_chat(magnification, span_notice("You're a mind magnified monkey! Protect your helmet with your life- if you lose it, your sentience goes with it!"))
|
||||
var/policy = get_policy(ROLE_MONKEY_HELMET)
|
||||
|
||||
@@ -148,7 +148,7 @@
|
||||
old_body = observer.mind.current, \
|
||||
)
|
||||
new_player.equipOutfit(loadout) // Loadout
|
||||
new_player.key = ckey
|
||||
new_player.PossessByPlayer(ckey)
|
||||
players_info["mob"] = new_player
|
||||
|
||||
for(var/datum/deathmatch_modifier/modifier as anything in modifiers)
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
var/obj/vent = pick_n_take(vents)
|
||||
var/mob/dead/observer/selected = pick_n_take(candidates)
|
||||
var/mob/living/carbon/alien/larva/new_xeno = new(vent.loc)
|
||||
new_xeno.key = selected.key
|
||||
new_xeno.PossessByPlayer(selected.key)
|
||||
new_xeno.move_into_vent(vent)
|
||||
|
||||
spawncount--
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
return MAP_ERROR
|
||||
|
||||
var/mob/living/basic/revenant/revvie = new(pick(spawn_locs))
|
||||
revvie.key = chosen_one.key
|
||||
revvie.PossessByPlayer(chosen_one.key)
|
||||
message_admins("[ADMIN_LOOKUPFLW(revvie)] has been made into a revenant by an event.")
|
||||
revvie.log_message("was spawned as a revenant by an event.", LOG_GAME)
|
||||
spawned_mobs += revvie
|
||||
|
||||
@@ -87,7 +87,7 @@ GLOBAL_LIST_INIT(high_priority_sentience, typecacheof(list(
|
||||
|
||||
spawned_animals++
|
||||
|
||||
selected.key = picked_candidate.key
|
||||
selected.PossessByPlayer(picked_candidate.key)
|
||||
|
||||
selected.grant_all_languages(UNDERSTOOD_LANGUAGE, grant_omnitongue = FALSE, source = LANGUAGE_ATOM)
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
if(isnull(spawn_location))
|
||||
return MAP_ERROR
|
||||
var/mob/living/basic/space_dragon/dragon = new(spawn_location)
|
||||
dragon.key = chosen_one.key
|
||||
dragon.PossessByPlayer(chosen_one.key)
|
||||
dragon.mind.add_antag_datum(/datum/antagonist/space_dragon)
|
||||
playsound(dragon, 'sound/effects/magic/ethereal_exit.ogg', 50, TRUE, -1)
|
||||
message_admins("[ADMIN_LOOKUPFLW(dragon)] has been made into a Space Dragon by an event.")
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
return NOT_ENOUGH_PLAYERS
|
||||
//spawn the ninja and assign the candidate
|
||||
var/mob/living/carbon/human/ninja = create_space_ninja(spawn_location)
|
||||
ninja.key = chosen_one.key
|
||||
ninja.PossessByPlayer(chosen_one.key)
|
||||
ninja.mind.add_antag_datum(/datum/antagonist/ninja)
|
||||
spawned_mobs += ninja
|
||||
message_admins("[ADMIN_LOOKUPFLW(ninja)] has been made into a space ninja by an event.")
|
||||
|
||||
@@ -89,6 +89,6 @@
|
||||
if(isnull(chosen_one))
|
||||
return NOT_ENOUGH_PLAYERS
|
||||
santa = new /mob/living/carbon/human(pick(GLOB.blobstart))
|
||||
santa.key = chosen_one.key
|
||||
santa.PossessByPlayer(chosen_one.key)
|
||||
var/datum/antagonist/santa/A = new
|
||||
santa.mind.add_antag_datum(A)
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
I.name = I.dna.real_name
|
||||
I.updateappearance(mutcolor_update=1)
|
||||
I.domutcheck()
|
||||
I.key = chosen_one.key
|
||||
I.PossessByPlayer(chosen_one.key)
|
||||
var/datum/antagonist/wizard/master = M.has_antag_datum(/datum/antagonist/wizard)
|
||||
if(!master.wiz_team)
|
||||
master.create_wiz_team()
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
/obj/item/fish/soul/proc/good_ending(mob/living/user)
|
||||
var/mob/living/basic/spaceman/soulman = new(get_turf(user))
|
||||
if(prob(80)) // the percentage is important.
|
||||
soulman.ckey = user.ckey
|
||||
soulman.PossessByPlayer(user.ckey)
|
||||
to_chat(soulman, span_notice("You finally feel at peace."))
|
||||
user.gib()
|
||||
qdel(src)
|
||||
|
||||
@@ -181,9 +181,9 @@
|
||||
podman.real_name = "Pod Person ([rand(1,999)])"
|
||||
mind.transfer_to(podman)
|
||||
if(ckey)
|
||||
podman.ckey = ckey
|
||||
podman.PossessByPlayer(ckey)
|
||||
else
|
||||
podman.ckey = ckey_holder
|
||||
podman.PossessByPlayer(ckey_holder)
|
||||
podman.gender = blood_gender
|
||||
podman.faction |= factions
|
||||
if(!features["mcolor"])
|
||||
|
||||
@@ -122,7 +122,7 @@
|
||||
old_mind = player.mob.mind, \
|
||||
old_body = player.mob.mind.current, \
|
||||
)
|
||||
body.key = player.key
|
||||
body.PossessByPlayer(player.key)
|
||||
|
||||
/**
|
||||
* Tests kill immunities, if nothing prevents the kill, kills this role.
|
||||
|
||||
@@ -456,7 +456,7 @@
|
||||
using = FALSE
|
||||
return
|
||||
|
||||
soul.ckey = ghost.ckey
|
||||
soul.PossessByPlayer(ghost.ckey)
|
||||
soul.copy_languages(master, LANGUAGE_MASTER) //Make sure the sword can understand and communicate with the master.
|
||||
soul.faction = list("[REF(master)]")
|
||||
balloon_alert(master, "the scythe glows")
|
||||
|
||||
@@ -90,14 +90,16 @@
|
||||
else
|
||||
to_chat(src, span_notice("Teleporting failed. Ahelp an admin please"))
|
||||
stack_trace("There's no freaking observer landmark available on this map or you're making observers before the map is initialised")
|
||||
observer.key = key
|
||||
|
||||
observer.PossessByPlayer(key)
|
||||
observer.client = client
|
||||
observer.set_ghost_appearance()
|
||||
if(observer.client && observer.client.prefs)
|
||||
observer.real_name = observer.client.prefs.read_preference(/datum/preference/name/real_name)
|
||||
observer.name = observer.real_name
|
||||
observer.client.init_verbs()
|
||||
observer.client.player_details.time_of_death = world.time
|
||||
observer.persistent_client.time_of_death = world.time
|
||||
|
||||
observer.update_appearance()
|
||||
observer.stop_sound_channel(CHANNEL_LOBBYMUSIC)
|
||||
deadchat_broadcast(" has observed.", "<b>[observer.real_name]</b>", follow_target = observer, turf_target = get_turf(observer), message_type = DEADCHAT_DEATHRATTLE)
|
||||
@@ -151,7 +153,7 @@
|
||||
/mob/dead/new_player/proc/AttemptLateSpawn(rank)
|
||||
// Check that they're picking someone new for new character respawning
|
||||
if(CONFIG_GET(flag/allow_respawn) == RESPAWN_FLAG_NEW_CHARACTER)
|
||||
if("[client.prefs.default_slot]" in client.player_details.joined_as_slots)
|
||||
if("[client.prefs.default_slot]" in persistent_client.joined_as_slots)
|
||||
tgui_alert(usr, "You already have played this character in this round!")
|
||||
return FALSE
|
||||
|
||||
@@ -263,8 +265,9 @@
|
||||
|
||||
mind.active = FALSE //we wish to transfer the key manually
|
||||
var/mob/living/spawning_mob = mind.assigned_role.get_spawn_mob(client, destination)
|
||||
if(QDELETED(src) || !client)
|
||||
if(QDELETED(src) || !HAS_CONNECTED_PLAYER(src))
|
||||
return // Disconnected while checking for the appearance ban.
|
||||
|
||||
if(!isAI(spawning_mob)) // Unfortunately there's still snowflake AI code out there.
|
||||
// transfer_to sets mind to null
|
||||
var/datum/mind/preserved_mind = mind
|
||||
@@ -272,7 +275,7 @@
|
||||
preserved_mind.transfer_to(spawning_mob) //won't transfer key since the mind is not active
|
||||
preserved_mind.set_original_character(spawning_mob)
|
||||
|
||||
LAZYADD(client.player_details.joined_as_slots, "[client.prefs.default_slot]")
|
||||
LAZYADD(persistent_client.joined_as_slots, "[client.prefs.default_slot]")
|
||||
client.init_verbs()
|
||||
. = spawning_mob
|
||||
new_character = .
|
||||
@@ -282,7 +285,7 @@
|
||||
. = new_character
|
||||
if(!.)
|
||||
return
|
||||
new_character.key = key //Manually transfer the key to log them in,
|
||||
new_character.PossessByPlayer(key) //Manually transfer the key to log them in,
|
||||
new_character.stop_sound_channel(CHANNEL_LOBBYMUSIC)
|
||||
var/area/joined_area = get_area(new_character.loc)
|
||||
if(joined_area)
|
||||
|
||||
@@ -283,7 +283,7 @@ Works together with spawning an observer, noted above.
|
||||
var/mob/dead/observer/ghost = new(src) // Transfer safety to observer spawning proc.
|
||||
SStgui.on_transfer(src, ghost) // Transfer NanoUIs.
|
||||
ghost.can_reenter_corpse = can_reenter_corpse
|
||||
ghost.key = key
|
||||
ghost.PossessByPlayer(key)
|
||||
ghost.client?.init_verbs()
|
||||
if(!can_reenter_corpse)// Disassociates observer mind from the body mind
|
||||
ghost.mind = null
|
||||
@@ -293,7 +293,7 @@ Works together with spawning an observer, noted above.
|
||||
if(isliving(former_mob))
|
||||
recordable_time = former_mob.timeofdeath
|
||||
|
||||
ghost.client?.player_details.time_of_death = recordable_time
|
||||
ghost.persistent_client?.time_of_death = recordable_time
|
||||
SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZED)
|
||||
return ghost
|
||||
|
||||
@@ -386,7 +386,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
SStgui.on_transfer(src, mind.current) // Transfer NanoUIs.
|
||||
if(mind.current.stat == DEAD && SSlag_switch.measures[DISABLE_DEAD_KEYLOOP])
|
||||
to_chat(src, span_warning("To leave your body again use the Ghost verb."))
|
||||
mind.current.key = key
|
||||
mind.current.PossessByPlayer(key)
|
||||
mind.current.client.init_verbs()
|
||||
return TRUE
|
||||
|
||||
@@ -680,7 +680,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
||||
to_chat(src, span_warning("Someone has taken this body while you were choosing!"))
|
||||
return FALSE
|
||||
|
||||
target.key = key
|
||||
target.PossessByPlayer(key)
|
||||
target.faction = list(FACTION_NEUTRAL)
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -719,7 +719,7 @@ GLOBAL_LIST_INIT(command_strings, list(
|
||||
if(isnull(mind))
|
||||
mind.transfer_to(paicard.pai)
|
||||
else
|
||||
paicard.pai.key = key
|
||||
paicard.pai.PossessByPlayer(key)
|
||||
else
|
||||
ghostize(FALSE) // The pAI card that just got ejected was dead.
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ GLOBAL_LIST_INIT(guardian_radial_images, setup_guardian_radial())
|
||||
var/datum/guardian_fluff/guardian_theme = GLOB.guardian_themes[theme]
|
||||
var/mob/living/basic/guardian/summoned_guardian = new guardian_path(user, guardian_theme)
|
||||
summoned_guardian.set_summoner(user, different_person = TRUE)
|
||||
summoned_guardian.key = candidate.key
|
||||
summoned_guardian.PossessByPlayer(candidate.key)
|
||||
user.log_message("has summoned [key_name(summoned_guardian)], a [summoned_guardian.creator_name] holoparasite.", LOG_GAME)
|
||||
summoned_guardian.log_message("was summoned as a [summoned_guardian.creator_name] holoparasite.", LOG_GAME)
|
||||
to_chat(user, guardian_theme.get_fluff_string(summoned_guardian.guardian_type))
|
||||
|
||||
@@ -180,7 +180,7 @@
|
||||
to_chat(owner, span_boldholoparasite("The personality of <font color=\"[chosen_guardian.guardian_colour]\">[chosen_guardian.theme.name]</font> has been successfully reset."))
|
||||
message_admins("[key_name_admin(chosen_one)] has taken control of ([ADMIN_LOOKUPFLW(chosen_guardian)])")
|
||||
chosen_guardian.ghostize(FALSE)
|
||||
chosen_guardian.key = chosen_one.key
|
||||
chosen_guardian.PossessByPlayer(chosen_one.key)
|
||||
COOLDOWN_START(chosen_guardian, resetting_cooldown, 5 MINUTES)
|
||||
chosen_guardian.guardian_rename() //give it a new color and name, to show it's a new person
|
||||
chosen_guardian.guardian_recolour()
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
if(mind)
|
||||
mind.transfer_to(specter)
|
||||
else
|
||||
specter.key = key
|
||||
specter.PossessByPlayer(key)
|
||||
return ..()
|
||||
|
||||
/mob/living/basic/parrot/poly/get_static_list_of_phrases() // there's only one poly, so there should only be one ongoing list of phrases. i guess
|
||||
|
||||
@@ -149,7 +149,7 @@
|
||||
new_slime.set_combat_mode(TRUE)
|
||||
|
||||
if(isnull(mind))
|
||||
new_slime.key = key
|
||||
new_slime.PossessByPlayer(key)
|
||||
else
|
||||
mind.transfer_to(new_slime)
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
var/user_name = old_ckey
|
||||
if(isnull(revenant.client))
|
||||
var/mob/potential_user = get_new_user()
|
||||
revenant.key = potential_user.key
|
||||
revenant.PossessByPlayer(potential_user.key)
|
||||
user_name = potential_user.ckey
|
||||
qdel(potential_user)
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
if(brainmob.mind)
|
||||
brainmob.mind.transfer_to(brain_owner)
|
||||
else
|
||||
brain_owner.key = brainmob.key
|
||||
brain_owner.PossessByPlayer(brainmob.key)
|
||||
|
||||
brain_owner.set_suicide(HAS_TRAIT(brainmob, TRAIT_SUICIDED))
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ GLOBAL_VAR(posibrain_notify_cooldown)
|
||||
if(candidate.mind && !isobserver(candidate))
|
||||
candidate.mind.transfer_to(brainmob)
|
||||
else
|
||||
brainmob.ckey = candidate.ckey
|
||||
brainmob.PossessByPlayer(candidate.ckey)
|
||||
name = "[initial(name)] ([brainmob.name])"
|
||||
var/policy = get_policy(ROLE_POSIBRAIN)
|
||||
if(policy)
|
||||
|
||||
@@ -119,7 +119,7 @@
|
||||
|
||||
var/atom/xeno_loc = get_turf(owner)
|
||||
var/mob/living/carbon/alien/larva/new_xeno = new(xeno_loc)
|
||||
new_xeno.key = ghost.key
|
||||
new_xeno.PossessByPlayer(ghost.key)
|
||||
SEND_SOUND(new_xeno, sound('sound/mobs/non-humanoids/hiss/hiss5.ogg',0,0,0,100)) //To get the player's attention
|
||||
new_xeno.add_traits(list(TRAIT_HANDS_BLOCKED, TRAIT_IMMOBILIZED, TRAIT_NO_TRANSFORM), type) //so we don't move during the bursting animation
|
||||
new_xeno.SetInvisibility(INVISIBILITY_MAXIMUM, id=type)
|
||||
|
||||
@@ -193,6 +193,7 @@
|
||||
|
||||
if (client)
|
||||
client.move_delay = initial(client.move_delay)
|
||||
client.player_details.time_of_death = timeofdeath
|
||||
|
||||
persistent_client?.time_of_death = timeofdeath
|
||||
|
||||
return TRUE
|
||||
|
||||
@@ -1781,7 +1781,7 @@
|
||||
|
||||
// Well, no mmind, guess we should try to move a key over
|
||||
else if(key)
|
||||
new_mob.key = key
|
||||
new_mob.PossessByPlayer(key)
|
||||
|
||||
/mob/living/proc/unfry_mob() //Callback proc to tone down spam from multiple sizzling frying oil dipping.
|
||||
REMOVE_TRAIT(src, TRAIT_OIL_FRIED, "cooking_oil_react")
|
||||
@@ -2932,7 +2932,7 @@ GLOBAL_LIST_EMPTY(fire_appearances)
|
||||
summoned_guardian.fully_replace_character_name(null, picked_name)
|
||||
if(picked_color)
|
||||
summoned_guardian.set_guardian_colour(picked_color)
|
||||
summoned_guardian.key = guardian_client?.key
|
||||
summoned_guardian.PossessByPlayer(guardian_client?.key)
|
||||
guardian_client?.init_verbs()
|
||||
if(del_mob)
|
||||
qdel(old_mob)
|
||||
|
||||
@@ -1097,7 +1097,7 @@ Pass a positive integer as an argument to override a bot's default speed.
|
||||
if(mind && paicard.pai)
|
||||
mind.transfer_to(paicard.pai)
|
||||
else if(paicard.pai)
|
||||
paicard.pai.key = key
|
||||
paicard.pai.PossessByPlayer(key)
|
||||
else
|
||||
ghostize(FALSE) // The pAI card that just got ejected was dead.
|
||||
key = null
|
||||
|
||||
@@ -468,7 +468,7 @@
|
||||
var/be_helper = tgui_alert(usr, "Become a Lightgeist? (Warning, You can no longer be revived!)", "Lightgeist Deployment", list("Yes", "No"))
|
||||
if((be_helper == "Yes") && !QDELETED(src) && isobserver(user))
|
||||
var/mob/living/basic/lightgeist/deployable = new(get_turf(loc))
|
||||
deployable.key = user.key
|
||||
deployable.PossessByPlayer(user.key)
|
||||
|
||||
/obj/machinery/anomalous_crystal/possessor //Allows you to bodyjack small animals, then exit them at your leisure, but you can only do this once per activation. Because they blow up. Also, if the bodyjacked animal dies, SO DO YOU.
|
||||
observer_desc = "When activated, this crystal allows you to take over small animals, and then exit them at the possessors leisure. Exiting the animal kills it, and if you die while possessing the animal, you die as well."
|
||||
|
||||
@@ -206,7 +206,7 @@ While using this makes the system rely on OnFire, it still gives options for tim
|
||||
visible_message(span_boldwarning("[mychild] emerges from [src]!"))
|
||||
playsound(loc,'sound/effects/phasein.ogg', 200, 0, 50, TRUE, TRUE)
|
||||
if(boosted)
|
||||
mychild.key = elitemind.key
|
||||
mychild.PossessByPlayer(elitemind.key)
|
||||
mychild.sentience_act()
|
||||
notify_ghosts(
|
||||
"\A [mychild] has been awakened in \the [get_area(src)]!",
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
return FALSE
|
||||
|
||||
canon_client = client
|
||||
client.persistent_client.set_mob(src)
|
||||
|
||||
add_to_player_list()
|
||||
lastKnownIP = client.address
|
||||
computer_id = client.computer_id
|
||||
@@ -108,13 +110,12 @@
|
||||
else
|
||||
client.change_view(getScreenSize(client.prefs.read_preference(/datum/preference/toggle/widescreen)))
|
||||
|
||||
if(client.player_details.player_actions.len)
|
||||
for(var/datum/action/A in client.player_details.player_actions)
|
||||
A.Grant(src)
|
||||
for(var/datum/action/A as anything in persistent_client.player_actions)
|
||||
A.Grant(src)
|
||||
|
||||
for(var/foo in client.player_details.post_login_callbacks)
|
||||
var/datum/callback/CB = foo
|
||||
for(var/datum/callback/CB as anything in persistent_client.post_login_callbacks)
|
||||
CB.Invoke()
|
||||
|
||||
log_played_names(
|
||||
client.ckey,
|
||||
list(
|
||||
|
||||
+16
-4
@@ -29,6 +29,8 @@
|
||||
else if(ckey)
|
||||
stack_trace("Mob without client but with associated ckey, [ckey], has been deleted.")
|
||||
|
||||
persistent_client?.set_mob(null)
|
||||
|
||||
remove_from_mob_list()
|
||||
remove_from_dead_mob_list()
|
||||
remove_from_alive_mob_list()
|
||||
@@ -107,6 +109,17 @@
|
||||
. = ..()
|
||||
tag = "mob_[next_mob_id++]"
|
||||
|
||||
/// Assigns a (c)key to this mob.
|
||||
/mob/proc/PossessByPlayer(ckey)
|
||||
SHOULD_NOT_OVERRIDE(TRUE)
|
||||
if(isnull(ckey))
|
||||
return
|
||||
|
||||
if(!istext(ckey))
|
||||
CRASH("Tried to assign a mob a non-text ckey, wtf?!")
|
||||
|
||||
src.ckey = ckey(ckey)
|
||||
|
||||
/mob/serialize_list(list/options, list/semvers)
|
||||
. = ..()
|
||||
|
||||
@@ -780,14 +793,14 @@
|
||||
qdel(M)
|
||||
return
|
||||
|
||||
M.key = key
|
||||
M.PossessByPlayer(key)
|
||||
|
||||
/// Checks if the mob can respawn yet according to the respawn delay
|
||||
/mob/proc/check_respawn_delay(override_delay = 0)
|
||||
if(!override_delay && !CONFIG_GET(number/respawn_delay))
|
||||
return TRUE
|
||||
|
||||
var/death_time = world.time - client.player_details.time_of_death
|
||||
var/death_time = world.time - persistent_client.time_of_death
|
||||
|
||||
var/required_delay = override_delay || CONFIG_GET(number/respawn_delay)
|
||||
|
||||
@@ -1535,8 +1548,7 @@
|
||||
if(!canon_client)
|
||||
return
|
||||
|
||||
for(var/foo in canon_client.player_details.post_logout_callbacks)
|
||||
var/datum/callback/CB = foo
|
||||
for(var/datum/callback/CB as anything in persistent_client.post_logout_callbacks)
|
||||
CB.Invoke()
|
||||
|
||||
if(canon_client?.movingmob)
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
/// We also need to clear this var/do other cleanup in client/Destroy, since that happens before logout
|
||||
/// HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
|
||||
var/client/canon_client
|
||||
/// It's like a client, but persists! Persistent clients will stick to a mob until the client in question is logged into a different mob.
|
||||
var/datum/persistent_client/persistent_client
|
||||
|
||||
var/shift_to_open_context_menu = TRUE
|
||||
|
||||
|
||||
@@ -376,7 +376,7 @@
|
||||
to_chat(M, "Your mob has been taken over by a ghost!")
|
||||
message_admins("[key_name_admin(chosen_one)] has taken control of ([ADMIN_LOOKUPFLW(M)])")
|
||||
M.ghostize(FALSE)
|
||||
M.key = chosen_one.key
|
||||
M.PossessByPlayer(chosen_one.key)
|
||||
M.client?.init_verbs()
|
||||
return TRUE
|
||||
else
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
|
||||
mind.transfer_to(desired_mob, 1) // second argument to force key move to new mob
|
||||
else
|
||||
desired_mob.key = key
|
||||
desired_mob.PossessByPlayer(key)
|
||||
|
||||
SEND_SIGNAL(src, COMSIG_MOB_CHANGED_TYPE, desired_mob)
|
||||
if(delete_old_mob)
|
||||
|
||||
@@ -155,7 +155,7 @@
|
||||
mind.active = FALSE
|
||||
mind.transfer_to(new_borg, TRUE)
|
||||
else if(transfer_after)
|
||||
new_borg.key = key
|
||||
new_borg.PossessByPlayer(key)
|
||||
|
||||
if(new_borg.mmi)
|
||||
new_borg.mmi.name = "[initial(new_borg.mmi.name)]: [real_name]"
|
||||
@@ -222,7 +222,7 @@
|
||||
new_xeno = new /mob/living/carbon/alien/adult/drone(loc)
|
||||
|
||||
new_xeno.set_combat_mode(TRUE)
|
||||
new_xeno.key = key
|
||||
new_xeno.PossessByPlayer(key)
|
||||
|
||||
to_chat(new_xeno, span_boldnotice("You are now an alien."))
|
||||
qdel(src)
|
||||
@@ -254,7 +254,7 @@
|
||||
else
|
||||
new_slime = new /mob/living/basic/slime(loc)
|
||||
new_slime.set_combat_mode(TRUE)
|
||||
new_slime.key = key
|
||||
new_slime.PossessByPlayer(key)
|
||||
|
||||
to_chat(new_slime, span_boldnotice("You are now a slime. Skreee!"))
|
||||
qdel(src)
|
||||
@@ -262,7 +262,7 @@
|
||||
|
||||
/mob/proc/become_overmind(starting_points = OVERMIND_STARTING_POINTS)
|
||||
var/mob/eye/blob/B = new /mob/eye/blob(get_turf(src), starting_points)
|
||||
B.key = key
|
||||
B.PossessByPlayer(key)
|
||||
. = B
|
||||
qdel(src)
|
||||
|
||||
@@ -282,7 +282,7 @@
|
||||
|
||||
var/mob/living/basic/pet/dog/corgi/new_corgi = new /mob/living/basic/pet/dog/corgi (loc)
|
||||
new_corgi.set_combat_mode(TRUE)
|
||||
new_corgi.key = key
|
||||
new_corgi.PossessByPlayer(key)
|
||||
|
||||
to_chat(new_corgi, span_boldnotice("You are now a Corgi. Yap Yap!"))
|
||||
qdel(src)
|
||||
@@ -333,7 +333,7 @@
|
||||
if(mind)
|
||||
mind.transfer_to(new_gorilla)
|
||||
else
|
||||
new_gorilla.key = key
|
||||
new_gorilla.PossessByPlayer(key)
|
||||
to_chat(new_gorilla, span_boldnotice("You are now a gorilla. Ooga ooga!"))
|
||||
qdel(src)
|
||||
return new_gorilla
|
||||
@@ -365,7 +365,7 @@
|
||||
|
||||
var/mob/living/new_mob = new mobpath(src.loc)
|
||||
|
||||
new_mob.key = key
|
||||
new_mob.PossessByPlayer(key)
|
||||
new_mob.set_combat_mode(TRUE)
|
||||
|
||||
to_chat(new_mob, span_boldnotice("You suddenly feel more... animalistic."))
|
||||
@@ -384,7 +384,7 @@
|
||||
|
||||
var/mob/living/new_mob = new mobpath(src.loc)
|
||||
|
||||
new_mob.key = key
|
||||
new_mob.PossessByPlayer(key)
|
||||
new_mob.set_combat_mode(TRUE)
|
||||
to_chat(new_mob, span_boldnotice("You feel more... animalistic."))
|
||||
|
||||
|
||||
@@ -242,7 +242,7 @@
|
||||
if(mob_possessor.mind)
|
||||
mob_possessor.mind.transfer_to(spawned_mob, force_key_move = TRUE)
|
||||
else
|
||||
spawned_mob.key = mob_possessor.key
|
||||
spawned_mob.PossessByPlayer(mob_possessor.key)
|
||||
var/datum/mind/spawned_mind = spawned_mob.mind
|
||||
if(spawned_mind)
|
||||
spawned_mob.mind.set_assigned_role_with_greeting(SSjob.get_job_type(spawner_job_path))
|
||||
|
||||
@@ -212,7 +212,7 @@
|
||||
var/mob/living/silicon/pai/new_pai = new(src)
|
||||
new_pai.name = candidate.name || pick(GLOB.ninja_names)
|
||||
new_pai.real_name = new_pai.name
|
||||
new_pai.key = candidate.ckey
|
||||
new_pai.PossessByPlayer(candidate.ckey)
|
||||
set_personality(new_pai)
|
||||
SSpai.candidates -= ckey
|
||||
return TRUE
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
pai.name = chosen_name
|
||||
pai.real_name = pai.name
|
||||
pai.key = choice.key
|
||||
pai.PossessByPlayer(choice.key)
|
||||
card.set_personality(pai)
|
||||
if(SSpai.candidates[key])
|
||||
SSpai.candidates -= key
|
||||
@@ -38,7 +38,7 @@
|
||||
/mob/proc/make_pai(delete_old)
|
||||
var/obj/item/pai_card/card = new(src)
|
||||
var/mob/living/silicon/pai/pai = new(card)
|
||||
pai.key = key
|
||||
pai.PossessByPlayer(key)
|
||||
pai.name = name
|
||||
card.set_personality(pai)
|
||||
if(delete_old)
|
||||
|
||||
@@ -378,7 +378,7 @@
|
||||
if(chosen_one)
|
||||
to_chat(target, span_boldnotice("You have been noticed by a ghost and it has possessed you!"))
|
||||
var/mob/dead/observer/ghosted_target = target.ghostize(FALSE)
|
||||
target.key = chosen_one.key
|
||||
target.PossessByPlayer(chosen_one.key)
|
||||
trauma.add_friend(ghosted_target)
|
||||
else
|
||||
to_chat(target, span_notice("Your mind has managed to go unnoticed in the spirit world."))
|
||||
|
||||
@@ -736,7 +736,7 @@
|
||||
being_used = FALSE
|
||||
return
|
||||
|
||||
dumb_mob.key = ghost.key
|
||||
dumb_mob.PossessByPlayer(ghost.key)
|
||||
dumb_mob.mind.enslave_mind_to_creator(user)
|
||||
SEND_SIGNAL(dumb_mob, COMSIG_SIMPLEMOB_SENTIENCEPOTION, user)
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@
|
||||
|
||||
// Just in case the swappee's key wasn't grabbed by transfer_to...
|
||||
if(to_swap_key)
|
||||
caster.key = to_swap_key
|
||||
caster.PossessByPlayer(to_swap_key)
|
||||
|
||||
// MIND TRANSFER END
|
||||
|
||||
|
||||
+1
-1
@@ -3797,7 +3797,7 @@
|
||||
#include "code\modules\client\client_defines.dm"
|
||||
#include "code\modules\client\client_procs.dm"
|
||||
#include "code\modules\client\message.dm"
|
||||
#include "code\modules\client\player_details.dm"
|
||||
#include "code\modules\client\persistent_client.dm"
|
||||
#include "code\modules\client\preferences.dm"
|
||||
#include "code\modules\client\preferences_menu.dm"
|
||||
#include "code\modules\client\preferences_savefile.dm"
|
||||
|
||||
Reference in New Issue
Block a user