"
-
- if(!IsGuestKey(src.key))
- if (SSdbcore.Connect())
- var/isadmin = 0
- if(src.client && src.client.holder)
- isadmin = 1
- var/datum/DBQuery/query_get_new_polls = SSdbcore.NewQuery("SELECT id FROM [format_table_name("poll_question")] WHERE [(isadmin ? "" : "adminonly = false AND")] Now() BETWEEN starttime AND endtime AND id NOT IN (SELECT pollid FROM [format_table_name("poll_vote")] WHERE ckey = \"[sanitizeSQL(ckey)]\") AND id NOT IN (SELECT pollid FROM [format_table_name("poll_textreply")] WHERE ckey = \"[sanitizeSQL(ckey)]\")")
- var/rs = REF(src)
- if(query_get_new_polls.Execute())
- var/newpoll = 0
- if(query_get_new_polls.NextRow())
- newpoll = 1
-
- if(newpoll)
- output += "
"
- for(var/jobcat in categorizedJobs)
- if(!length(categorizedJobs[jobcat]["jobs"]))
- continue
- var/color = categorizedJobs[jobcat]["color"]
- dat += " "
- dat += "
"
- dat += ""
-
- var/datum/browser/popup = new(src, "latechoices", "Choose Profession", 720, 600)
- popup.add_stylesheet("playeroptions", 'html/browser/playeroptions.css')
- popup.set_content(jointext(dat, ""))
- popup.open(FALSE) // FALSE is passed to open so that it doesn't use the onclose() proc
-
-/mob/dead/new_player/proc/create_character(transfer_after)
- spawning = 1
- close_spawn_windows()
-
- var/mob/living/carbon/human/H = new(loc)
-
- var/frn = CONFIG_GET(flag/force_random_names)
- if(!frn)
- frn = jobban_isbanned(src, "appearance")
- if(QDELETED(src))
- return
- if(frn)
- client.prefs.random_character()
- client.prefs.real_name = client.prefs.pref_species.random_name(gender,1)
- client.prefs.copy_to(H)
- H.dna.update_dna_identity()
- if(mind)
- if(transfer_after)
- mind.late_joiner = TRUE
- mind.active = 0 //we wish to transfer the key manually
- mind.transfer_to(H) //won't transfer key since the mind is not active
-
- H.name = real_name
-
- . = H
- new_character = .
- if(transfer_after)
- transfer_character()
-
-/mob/dead/new_player/proc/transfer_character()
- . = new_character
- if(.)
- new_character.key = key //Manually transfer the key to log them in
- new_character.stop_sound_channel(CHANNEL_LOBBYMUSIC)
- new_character = null
- qdel(src)
-
-/mob/dead/new_player/proc/ViewManifest()
- var/dat = ""
- dat += "
Crew Manifest
"
- dat += GLOB.data_core.get_manifest(OOC = 1)
-
- src << browse(dat, "window=manifest;size=387x420;can_close=1")
-
-/mob/dead/new_player/Move()
- return 0
-
-
-/mob/dead/new_player/proc/close_spawn_windows()
-
- src << browse(null, "window=latechoices") //closes late choices window
- src << browse(null, "window=playersetup") //closes the player setup window
- src << browse(null, "window=preferences") //closes job selection
- src << browse(null, "window=mob_occupation")
- src << browse(null, "window=latechoices") //closes late job selection
-
-/* Used to make sure that a player has a valid job preference setup, used to knock players out of eligibility for anything if their prefs don't make sense.
- A "valid job preference setup" in this situation means at least having one job set to low, or not having "return to lobby" enabled
- Prevents "antag rolling" by setting antag prefs on, all jobs to never, and "return to lobby if preferences not availible"
- Doing so would previously allow you to roll for antag, then send you back to lobby if you didn't get an antag role
- This also does some admin notification and logging as well, as well as some extra logic to make sure things don't go wrong
-*/
-
-/mob/dead/new_player/proc/check_preferences()
- if(!client)
- return FALSE //Not sure how this would get run without the mob having a client, but let's just be safe.
- if(client.prefs.joblessrole != RETURNTOLOBBY)
- return TRUE
- // If they have antags enabled, they're potentially doing this on purpose instead of by accident. Notify admins if so.
- var/has_antags = FALSE
- if(client.prefs.be_special.len > 0)
- has_antags = TRUE
- if(client.prefs.job_preferences.len == 0)
- if(!ineligible_for_roles)
- to_chat(src, "You have no jobs enabled, along with return to lobby if job is unavailable. This makes you ineligible for any round start role, please update your job preferences.")
- ineligible_for_roles = TRUE
- ready = PLAYER_NOT_READY
- if(has_antags)
- log_admin("[src.ckey] just got booted back to lobby with no jobs, but antags enabled.")
- message_admins("[src.ckey] just got booted back to lobby with no jobs enabled, but antag rolling enabled. Likely antag rolling abuse.")
-
- return FALSE //This is the only case someone should actually be completely blocked from antag rolling as well
- return TRUE
+#define LINKIFY_READY(string, value) "[string]"
+
+/mob/dead/new_player
+ var/ready = 0
+ var/spawning = 0//Referenced when you want to delete the new_player later on in the code.
+
+ flags_1 = NONE
+
+ invisibility = INVISIBILITY_ABSTRACT
+
+ density = FALSE
+ stat = DEAD
+ canmove = FALSE
+
+ anchored = TRUE // don't get pushed around
+
+ var/mob/living/new_character //for instant transfer once the round is set up
+
+ //Used to make sure someone doesn't get spammed with messages if they're ineligible for roles
+ var/ineligible_for_roles = FALSE
+
+/mob/dead/new_player/Initialize()
+ if(client && SSticker.state == GAME_STATE_STARTUP)
+ var/obj/screen/splash/S = new(client, TRUE, TRUE)
+ S.Fade(TRUE)
+
+ if(length(GLOB.newplayer_start))
+ forceMove(pick(GLOB.newplayer_start))
+ else
+ forceMove(locate(1,1,1))
+
+ ComponentInitialize()
+
+ . = ..()
+
+/mob/dead/new_player/prepare_huds()
+ return
+
+/mob/dead/new_player/proc/new_player_panel()
+ var/output = "
"
+
+ if(!IsGuestKey(src.key))
+ if (SSdbcore.Connect())
+ var/isadmin = 0
+ if(src.client && src.client.holder)
+ isadmin = 1
+ var/datum/DBQuery/query_get_new_polls = SSdbcore.NewQuery("SELECT id FROM [format_table_name("poll_question")] WHERE [(isadmin ? "" : "adminonly = false AND")] Now() BETWEEN starttime AND endtime AND id NOT IN (SELECT pollid FROM [format_table_name("poll_vote")] WHERE ckey = \"[sanitizeSQL(ckey)]\") AND id NOT IN (SELECT pollid FROM [format_table_name("poll_textreply")] WHERE ckey = \"[sanitizeSQL(ckey)]\")")
+ var/rs = REF(src)
+ if(query_get_new_polls.Execute())
+ var/newpoll = 0
+ if(query_get_new_polls.NextRow())
+ newpoll = 1
+
+ if(newpoll)
+ output += "
"
+ for(var/jobcat in categorizedJobs)
+ if(!length(categorizedJobs[jobcat]["jobs"]))
+ continue
+ var/color = categorizedJobs[jobcat]["color"]
+ dat += " "
+ dat += "
"
+ dat += ""
+
+ var/datum/browser/popup = new(src, "latechoices", "Choose Profession", 720, 600)
+ popup.add_stylesheet("playeroptions", 'html/browser/playeroptions.css')
+ popup.set_content(jointext(dat, ""))
+ popup.open(FALSE) // FALSE is passed to open so that it doesn't use the onclose() proc
+
+/mob/dead/new_player/proc/create_character(transfer_after)
+ spawning = 1
+ close_spawn_windows()
+
+ var/mob/living/carbon/human/H = new(loc)
+
+ var/frn = CONFIG_GET(flag/force_random_names)
+ if(!frn)
+ frn = jobban_isbanned(src, "appearance")
+ if(QDELETED(src))
+ return
+ if(frn)
+ client.prefs.random_character()
+ client.prefs.real_name = client.prefs.pref_species.random_name(gender,1)
+ client.prefs.copy_to(H)
+ H.dna.update_dna_identity()
+ if(mind)
+ if(transfer_after)
+ mind.late_joiner = TRUE
+ mind.active = 0 //we wish to transfer the key manually
+ mind.transfer_to(H) //won't transfer key since the mind is not active
+
+ H.name = real_name
+
+ . = H
+ new_character = .
+ if(transfer_after)
+ transfer_character()
+
+/mob/dead/new_player/proc/transfer_character()
+ . = new_character
+ if(.)
+ new_character.key = key //Manually transfer the key to log them in
+ new_character.stop_sound_channel(CHANNEL_LOBBYMUSIC)
+ new_character = null
+ qdel(src)
+
+/mob/dead/new_player/proc/ViewManifest()
+ var/dat = ""
+ dat += "
Crew Manifest
"
+ dat += GLOB.data_core.get_manifest(OOC = 1)
+
+ src << browse(dat, "window=manifest;size=387x420;can_close=1")
+
+/mob/dead/new_player/Move()
+ return 0
+
+
+/mob/dead/new_player/proc/close_spawn_windows()
+
+ src << browse(null, "window=latechoices") //closes late choices window
+ src << browse(null, "window=playersetup") //closes the player setup window
+ src << browse(null, "window=preferences") //closes job selection
+ src << browse(null, "window=mob_occupation")
+ src << browse(null, "window=latechoices") //closes late job selection
+
+/* Used to make sure that a player has a valid job preference setup, used to knock players out of eligibility for anything if their prefs don't make sense.
+ A "valid job preference setup" in this situation means at least having one job set to low, or not having "return to lobby" enabled
+ Prevents "antag rolling" by setting antag prefs on, all jobs to never, and "return to lobby if preferences not availible"
+ Doing so would previously allow you to roll for antag, then send you back to lobby if you didn't get an antag role
+ This also does some admin notification and logging as well, as well as some extra logic to make sure things don't go wrong
+*/
+
+/mob/dead/new_player/proc/check_preferences()
+ if(!client)
+ return FALSE //Not sure how this would get run without the mob having a client, but let's just be safe.
+ if(client.prefs.joblessrole != RETURNTOLOBBY)
+ return TRUE
+ // If they have antags enabled, they're potentially doing this on purpose instead of by accident. Notify admins if so.
+ var/has_antags = FALSE
+ if(client.prefs.be_special.len > 0)
+ has_antags = TRUE
+ if(client.prefs.job_preferences.len == 0)
+ if(!ineligible_for_roles)
+ to_chat(src, "You have no jobs enabled, along with return to lobby if job is unavailable. This makes you ineligible for any round start role, please update your job preferences.")
+ ineligible_for_roles = TRUE
+ ready = PLAYER_NOT_READY
+ if(has_antags)
+ log_admin("[src.ckey] just got booted back to lobby with no jobs, but antags enabled.")
+ message_admins("[src.ckey] just got booted back to lobby with no jobs enabled, but antag rolling enabled. Likely antag rolling abuse.")
+
+ return FALSE //This is the only case someone should actually be completely blocked from antag rolling as well
+ return TRUE
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index fefa032e4f..d599d55886 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -260,16 +260,16 @@ Transfer_mind is there to check if mob is being deleted/not going to have a body
Works together with spawning an observer, noted above.
*/
-/mob/proc/ghostize(can_reenter_corpse = 1)
- if(key)
- if(!cmptext(copytext(key,1,2),"@")) // Skip aghosts.
- stop_sound_channel(CHANNEL_HEARTBEAT) //Stop heartbeat sounds because You Are A Ghost Now
- 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.can_reenter_round = (can_reenter_corpse && !suiciding)
- ghost.key = key
- return ghost
+/mob/proc/ghostize(can_reenter_corpse = TRUE, special = FALSE)
+ if(!key || cmptext(copytext(key,1,2),"@") || (!special && SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, can_reenter_corpse, special) & COMPONENT_BLOCK_GHOSTING))
+ return //mob has no key, is an aghost or some component hijacked.
+ stop_sound_channel(CHANNEL_HEARTBEAT) //Stop heartbeat sounds because You Are A Ghost Now
+ 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.can_reenter_round = (can_reenter_corpse && !suiciding)
+ transfer_ckey(ghost, FALSE)
+ return ghost
/*
This is the proc mobs get to turn into a ghost. Forked from ghostize due to compatibility issues.
@@ -280,6 +280,9 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
set name = "Ghost"
set desc = "Relinquish your life and enter the land of the dead."
+ if(SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, (stat == DEAD) ? TRUE : FALSE, FALSE) & COMPONENT_BLOCK_GHOSTING)
+ return
+
// CITADEL EDIT
if(istype(loc, /obj/machinery/cryopod))
var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst still alive you won't be able to re-enter this round! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
@@ -306,6 +309,9 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
set name = "Ghost"
set desc = "Relinquish your life and enter the land of the dead."
+ if(SEND_SIGNAL(src, COMSIG_MOB_GHOSTIZE, FALSE, FALSE) & COMPONENT_BLOCK_GHOSTING)
+ return
+
var/response = alert(src, "Are you -sure- you want to ghost?\n(You are alive. If you ghost whilst still alive you won't be able to re-enter this round! You can't change your mind so choose wisely!!)","Are you sure you want to ghost?","Ghost","Stay in body")
if(response != "Ghost")
return
@@ -348,7 +354,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
return
client.change_view(CONFIG_GET(string/default_view))
SStgui.on_transfer(src, mind.current) // Transfer NanoUIs.
- mind.current.key = key
+ transfer_ckey(mind.current, FALSE)
return 1
/mob/dead/observer/proc/notify_cloning(var/message, var/sound, var/atom/source, flashwindow = TRUE)
@@ -628,7 +634,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
to_chat(src, "Someone has taken this body while you were choosing!")
return 0
- target.key = key
+ transfer_ckey(target, FALSE)
target.faction = list("neutral")
return 1
diff --git a/code/modules/mob/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm
index 17f81981d1..41a8944015 100644
--- a/code/modules/mob/living/brain/brain_item.dm
+++ b/code/modules/mob/living/brain/brain_item.dm
@@ -42,7 +42,7 @@
if(brainmob.mind)
brainmob.mind.transfer_to(C)
else
- C.key = brainmob.key
+ brainmob.transfer_ckey(C)
QDEL_NULL(brainmob)
diff --git a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
index 9706fde782..04a2e56857 100644
--- a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
+++ b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
@@ -87,7 +87,7 @@
var/atom/xeno_loc = get_turf(owner)
var/mob/living/carbon/alien/larva/new_xeno = new(xeno_loc)
- new_xeno.key = ghost.key
+ ghost.transfer_ckey(new_xeno, FALSE)
SEND_SOUND(new_xeno, sound('sound/voice/hiss5.ogg',0,0,0,100)) //To get the player's attention
new_xeno.canmove = 0 //so we don't move during the bursting animation
new_xeno.notransform = 1
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 5ff78ec1c9..812733ebe2 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -912,7 +912,7 @@
if(mind)
mind.transfer_to(new_mob)
else
- new_mob.key = key
+ transfer_ckey(new_mob)
for(var/para in hasparasites())
var/mob/living/simple_animal/hostile/guardian/G = para
diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm
index 7fd861bfeb..0f8687397d 100644
--- a/code/modules/mob/living/silicon/pai/pai.dm
+++ b/code/modules/mob/living/silicon/pai/pai.dm
@@ -192,7 +192,7 @@
/mob/proc/makePAI(delold)
var/obj/item/paicard/card = new /obj/item/paicard(get_turf(src))
var/mob/living/silicon/pai/pai = new /mob/living/silicon/pai(card)
- pai.key = key
+ transfer_ckey(pai)
pai.name = name
card.setPersonality(pai)
if(delold)
diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm
index 49261d6e38..46d9525046 100644
--- a/code/modules/mob/living/simple_animal/bot/bot.dm
+++ b/code/modules/mob/living/simple_animal/bot/bot.dm
@@ -915,7 +915,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
+ transfer_ckey(paicard.pai)
else
ghostize(0) // The pAI card that just got ejected was dead.
key = null
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
index 6d3121474c..d7d4d1b9f2 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
@@ -160,7 +160,7 @@
if(mind)
mind.transfer_to(R, 1)
else
- R.key = key
+ transfer_ckey(R)
qdel(src)
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm b/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm
index a655bdf231..e54b21724d 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm
@@ -61,5 +61,5 @@
var/obj/item/new_hat = new hat_type(D)
D.equip_to_slot_or_del(new_hat, SLOT_HEAD)
D.flags_1 |= (flags_1 & ADMIN_SPAWNED_1)
- D.key = user.key
+ user.transfer_ckey(D, FALSE)
qdel(src)
diff --git a/code/modules/mob/living/simple_animal/guardian/guardian.dm b/code/modules/mob/living/simple_animal/guardian/guardian.dm
index 5aec56b1e7..e3ef14c784 100644
--- a/code/modules/mob/living/simple_animal/guardian/guardian.dm
+++ b/code/modules/mob/living/simple_animal/guardian/guardian.dm
@@ -429,9 +429,9 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
to_chat(G, "Your user reset you, and your body was taken over by a ghost. Looks like they weren't happy with your performance.")
to_chat(src, "Your [G.real_name] has been successfully reset.")
message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(G)])")
- G.ghostize(0)
+ G.ghostize(FALSE)
G.setthemename(G.namedatum.theme) //give it a new color, to show it's a new person
- G.key = C.key
+ C.transfer_ckey(G)
G.reset = 1
switch(G.namedatum.theme)
if("tech")
diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
index cfdf302d6b..f5b1706f87 100644
--- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
+++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
@@ -90,7 +90,7 @@
if(key)
to_chat(user, "Someone else already took this spider.")
return 1
- key = user.key
+ user.transfer_ckey(src, FALSE)
return 1
//nursemaids - these create webs and eggs
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
index b529d826c9..b43bf2bb51 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
@@ -585,7 +585,7 @@ Difficulty: Very Hard
var/be_helper = alert("Become a Lightgeist? (Warning, You can no longer be cloned!)",,"Yes","No")
if(be_helper == "Yes" && !QDELETED(src) && isobserver(user))
var/mob/living/simple_animal/hostile/lightgeist/W = new /mob/living/simple_animal/hostile/lightgeist(get_turf(loc))
- W.key = user.key
+ user.transfer_ckey(W, FALSE)
/obj/machinery/anomalous_crystal/helpers/Topic(href, href_list)
@@ -649,7 +649,7 @@ Difficulty: Very Hard
L.heal_overall_damage(heal_power, heal_power)
new /obj/effect/temp_visual/heal(get_turf(target), "#80F5FF")
-/mob/living/simple_animal/hostile/lightgeist/ghostize()
+/mob/living/simple_animal/hostile/lightgeist/ghostize(can_reenter_corpse = TRUE, send_the_signal = TRUE)
. = ..()
if(.)
death()
diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm
index 86f63a729d..5e2798cc8e 100644
--- a/code/modules/mob/living/simple_animal/parrot.dm
+++ b/code/modules/mob/living/simple_animal/parrot.dm
@@ -916,7 +916,7 @@
if(mind)
mind.transfer_to(G)
else
- G.key = key
+ transfer_ckey(G)
..(gibbed)
/mob/living/simple_animal/parrot/Poly/proc/Read_Memory()
diff --git a/code/modules/mob/living/simple_animal/slime/powers.dm b/code/modules/mob/living/simple_animal/slime/powers.dm
index a3e2f48b75..bf80ab9ff4 100644
--- a/code/modules/mob/living/simple_animal/slime/powers.dm
+++ b/code/modules/mob/living/simple_animal/slime/powers.dm
@@ -198,7 +198,7 @@
if(src.mind)
src.mind.transfer_to(new_slime)
else
- new_slime.key = src.key
+ transfer_ckey(new_slime)
qdel(src)
else
to_chat(src, "I am not ready to reproduce yet...")
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index bd3c813b12..5a7c6e21ab 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -444,7 +444,13 @@
// M.Login() //wat
return
-
+/mob/proc/transfer_ckey(mob/new_mob, send_signal = TRUE)
+ if(!ckey)
+ return FALSE
+ if(send_signal)
+ SEND_SIGNAL(src, COMSIG_MOB_KEY_CHANGE, new_mob, src)
+ new_mob.ckey = ckey
+ return TRUE
/mob/verb/cancel_camera()
set name = "Cancel Camera View"
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index 776bd04935..5519c9be95 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -429,8 +429,8 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
var/mob/dead/observer/C = pick(candidates)
to_chat(M, "Your mob has been taken over by a ghost!")
message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(M)])")
- M.ghostize(0)
- M.key = C.key
+ M.ghostize(FALSE, TRUE)
+ C.transfer_ckey(M, FALSE)
return TRUE
else
to_chat(M, "There were no ghosts willing to take control.")
diff --git a/code/modules/mob/mob_transformation_simple.dm b/code/modules/mob/mob_transformation_simple.dm
index 673548ff48..a11e7a228e 100644
--- a/code/modules/mob/mob_transformation_simple.dm
+++ b/code/modules/mob/mob_transformation_simple.dm
@@ -53,7 +53,7 @@
if(mind && isliving(M))
mind.transfer_to(M, 1) // second argument to force key move to new mob
else
- M.key = key
+ transfer_ckey(M)
if(delete_old_mob)
QDEL_IN(src, 1)
diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm
index 6bbe512776..6394b45aa7 100644
--- a/code/modules/mob/transform_procs.dm
+++ b/code/modules/mob/transform_procs.dm
@@ -382,7 +382,7 @@
mind.active = FALSE
mind.transfer_to(R)
else if(transfer_after)
- R.key = key
+ transfer_ckey(R)
R.apply_pref_name("cyborg")
@@ -401,7 +401,7 @@
qdel(src)
//human -> alien
-/mob/living/carbon/human/proc/Alienize()
+/mob/living/carbon/human/proc/Alienize(mind_transfer = TRUE)
if (notransform)
return
for(var/obj/item/W in src)
@@ -425,13 +425,16 @@
new_xeno = new /mob/living/carbon/alien/humanoid/drone(loc)
new_xeno.a_intent = INTENT_HARM
- new_xeno.key = key
+ if(mind && mind_transfer)
+ mind.transfer_to(new_xeno)
+ else
+ transfer_ckey(new_xeno)
to_chat(new_xeno, "You are now an alien.")
. = new_xeno
qdel(src)
-/mob/living/carbon/human/proc/slimeize(reproduce as num)
+/mob/living/carbon/human/proc/slimeize(reproduce, mind_transfer = TRUE)
if (notransform)
return
for(var/obj/item/W in src)
@@ -457,20 +460,26 @@
else
new_slime = new /mob/living/simple_animal/slime(loc)
new_slime.a_intent = INTENT_HARM
- new_slime.key = key
+ if(mind && mind_transfer)
+ mind.transfer_to(new_slime)
+ else
+ transfer_ckey(new_slime)
to_chat(new_slime, "You are now a slime. Skreee!")
. = new_slime
qdel(src)
-/mob/proc/become_overmind(starting_points = 60)
+/mob/proc/become_overmind(starting_points = 60, mind_transfer = FALSE)
var/mob/camera/blob/B = new /mob/camera/blob(get_turf(src), starting_points)
- B.key = key
+ if(mind && mind_transfer)
+ mind.transfer_to(B)
+ else
+ transfer_ckey(B)
. = B
qdel(src)
-/mob/living/carbon/human/proc/corgize()
+/mob/living/carbon/human/proc/corgize(mind_transfer = TRUE)
if (notransform)
return
for(var/obj/item/W in src)
@@ -485,13 +494,16 @@
var/mob/living/simple_animal/pet/dog/corgi/new_corgi = new /mob/living/simple_animal/pet/dog/corgi (loc)
new_corgi.a_intent = INTENT_HARM
- new_corgi.key = key
+ if(mind && mind_transfer)
+ mind.transfer_to(new_corgi)
+ else
+ transfer_ckey(new_corgi)
to_chat(new_corgi, "You are now a Corgi. Yap Yap!")
. = new_corgi
qdel(src)
-/mob/living/carbon/proc/gorillize()
+/mob/living/carbon/proc/gorillize(mind_transfer = TRUE)
if(notransform)
return
@@ -509,22 +521,22 @@
invisibility = INVISIBILITY_MAXIMUM
var/mob/living/simple_animal/hostile/gorilla/new_gorilla = new (get_turf(src))
new_gorilla.a_intent = INTENT_HARM
- if(mind)
+ if(mind && mind_transfer)
mind.transfer_to(new_gorilla)
else
- new_gorilla.key = key
+ transfer_ckey(new_gorilla)
to_chat(new_gorilla, "You are now a gorilla. Ooga ooga!")
. = new_gorilla
qdel(src)
-/mob/living/carbon/human/Animalize()
+/mob/living/carbon/human/Animalize(mind_transfer = TRUE)
var/list/mobtypes = typesof(/mob/living/simple_animal)
- var/mobpath = input("Which type of mob should [src] turn into?", "Choose a type") in mobtypes
-
- if(!safe_animal(mobpath))
- to_chat(usr, "Sorry but this mob type is currently unavailable.")
+ var/mobpath = input("Which type of mob should [src] turn into?", "Choose a type") as null|anything in mobtypes
+ if(!mobpath)
return
+ if(mind)
+ mind_transfer = alert("Want to transfer their mind into the new mob", "Mind Transfer", "Yes", "No") == "Yes" ? TRUE : FALSE
if(notransform)
return
@@ -532,8 +544,8 @@
dropItemToGround(W)
regenerate_icons()
- notransform = 1
- canmove = 0
+ notransform = TRUE
+ canmove = FALSE
icon = null
invisibility = INVISIBILITY_MAXIMUM
@@ -541,8 +553,10 @@
qdel(t)
var/mob/new_mob = new mobpath(src.loc)
-
- new_mob.key = key
+ if(mind && mind_transfer)
+ mind.transfer_to(new_mob)
+ else
+ transfer_ckey(new_mob)
new_mob.a_intent = INTENT_HARM
@@ -550,59 +564,23 @@
. = new_mob
qdel(src)
-/mob/proc/Animalize()
+/mob/proc/Animalize(mind_transfer = TRUE)
var/list/mobtypes = typesof(/mob/living/simple_animal)
- var/mobpath = input("Which type of mob should [src] turn into?", "Choose a type") in mobtypes
-
- if(!safe_animal(mobpath))
- to_chat(usr, "Sorry but this mob type is currently unavailable.")
+ var/mobpath = input("Which type of mob should [src] turn into?", "Choose a type") as null|anything in mobtypes
+ if(!mobpath)
return
+ if(mind)
+ mind_transfer = alert("Want to transfer their mind into the new mob", "Mind Transfer", "Yes", "No") == "Yes" ? TRUE : FALSE
var/mob/new_mob = new mobpath(src.loc)
- new_mob.key = key
+ if(mind && mind_transfer)
+ mind.transfer_to(new_mob)
+ else
+ transfer_ckey(new_mob)
new_mob.a_intent = INTENT_HARM
to_chat(new_mob, "You feel more... animalistic")
. = new_mob
qdel(src)
-
-/* Certain mob types have problems and should not be allowed to be controlled by players.
- *
- * This proc is here to force coders to manually place their mob in this list, hopefully tested.
- * This also gives a place to explain -why- players shouldnt be turn into certain mobs and hopefully someone can fix them.
- */
-/mob/proc/safe_animal(MP)
-
-//Bad mobs! - Remember to add a comment explaining what's wrong with the mob
- if(!MP)
- return 0 //Sanity, this should never happen.
-
- if(ispath(MP, /mob/living/simple_animal/hostile/construct))
- return 0 //Verbs do not appear for players.
-
-//Good mobs!
- if(ispath(MP, /mob/living/simple_animal/pet/cat))
- return 1
- if(ispath(MP, /mob/living/simple_animal/pet/dog/corgi))
- return 1
- if(ispath(MP, /mob/living/simple_animal/crab))
- return 1
- if(ispath(MP, /mob/living/simple_animal/hostile/carp))
- return 1
- if(ispath(MP, /mob/living/simple_animal/hostile/mushroom))
- return 1
- if(ispath(MP, /mob/living/simple_animal/shade))
- return 1
- if(ispath(MP, /mob/living/simple_animal/hostile/killertomato))
- return 1
- if(ispath(MP, /mob/living/simple_animal/mouse))
- return 1 //It is impossible to pull up the player panel for mice (Fixed! - Nodrak)
- if(ispath(MP, /mob/living/simple_animal/hostile/bear))
- return 1 //Bears will auto-attack mobs, even if they're player controlled (Fixed! - Nodrak)
- if(ispath(MP, /mob/living/simple_animal/parrot))
- return 1 //Parrots are no longer unfinished! -Nodrak
-
- //Not in here? Must be untested!
- return 0
diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm
index b062893954..c31fc58817 100644
--- a/code/modules/research/xenobiology/xenobiology.dm
+++ b/code/modules/research/xenobiology/xenobiology.dm
@@ -681,7 +681,7 @@
var/list/candidates = pollCandidatesForMob("Do you want to play as [SM.name]?", ROLE_SENTIENCE, null, ROLE_SENTIENCE, 50, SM, POLL_IGNORE_SENTIENCE_POTION) // see poll_ignore.dm
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
- SM.key = C.key
+ C.transfer_ckey(SM, FALSE)
SM.mind.enslave_mind_to_creator(user)
SM.sentience_act()
to_chat(SM, "All at once it makes sense: you know what you are and who you are! Self awareness is yours!")
diff --git a/code/modules/spells/spell_types/mind_transfer.dm b/code/modules/spells/spell_types/mind_transfer.dm
index ffdd270994..107f303049 100644
--- a/code/modules/spells/spell_types/mind_transfer.dm
+++ b/code/modules/spells/spell_types/mind_transfer.dm
@@ -70,12 +70,12 @@ Also, you never added distance checking after target is selected. I've went ahea
var/mob/living/caster = user//The wizard/whomever doing the body transferring.
//MIND TRANSFER BEGIN
- var/mob/dead/observer/ghost = victim.ghostize(0)
+ var/mob/dead/observer/ghost = victim.ghostize(FALSE, TRUE)
caster.mind.transfer_to(victim)
ghost.mind.transfer_to(caster)
if(ghost.key)
- caster.key = ghost.key //have to transfer the key since the mind was not active
+ ghost.transfer_ckey(caster) //have to transfer the key since the mind was not active
qdel(ghost)
//MIND TRANSFER END
diff --git a/modular_citadel/code/modules/mob/living/simple_animal/banana_spider.dm b/modular_citadel/code/modules/mob/living/simple_animal/banana_spider.dm
index d2006cd12c..fdc271a158 100644
--- a/modular_citadel/code/modules/mob/living/simple_animal/banana_spider.dm
+++ b/modular_citadel/code/modules/mob/living/simple_animal/banana_spider.dm
@@ -38,7 +38,7 @@
return
to_chat(user, "You decide to wake up the banana spider...")
awakening = 1
-
+
spawn(30)
if(!QDELETED(src))
var/mob/living/simple_animal/banana_spider/S = new /mob/living/simple_animal/banana_spider(get_turf(src.loc))
@@ -98,7 +98,7 @@
if(be_spider == "No" || QDELETED(src) || !isobserver(user))
return
sentience_act()
- key = user.key
+ user.transfer_ckey(src, FALSE)
density = TRUE
/mob/living/simple_animal/banana_spider/ComponentInitialize()
diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/SDGF.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/SDGF.dm
index c405bb1a88..a7e1ac8e92 100644
--- a/modular_citadel/code/modules/reagents/chemistry/reagents/SDGF.dm
+++ b/modular_citadel/code/modules/reagents/chemistry/reagents/SDGF.dm
@@ -86,7 +86,7 @@ IMPORTANT FACTORS TO CONSIDER WHILE BALANCING
candies = shuffle(candies)//Shake those ghosts up!
for(var/mob/dead/observer/C2 in candies)
if(C2.key && C2)
- SM.key = C2.key
+ C2.transfer_ckey(SM, FALSE)
message_admins("Ghost candidate found! [C2] key [C2.key] is becoming a clone of [M] key: [M.key] (They agreed to respect the character they're becoming, and agreed to not ERP without express permission from the original.)")
log_game("FERMICHEM: [M] ckey: [M.key] is creating a clone, controlled by [C2]")
break
diff --git a/tgstation.dme b/tgstation.dme
index 1e632e4fa6..dc556999d2 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -382,6 +382,7 @@
#include "code\datums\components\swarming.dm"
#include "code\datums\components\thermite.dm"
#include "code\datums\components\uplink.dm"
+#include "code\datums\components\virtual_reality.dm"
#include "code\datums\components\wearertargeting.dm"
#include "code\datums\components\wet_floor.dm"
#include "code\datums\components\decals\blood.dm"
@@ -2884,7 +2885,7 @@
#include "code\modules\vending\toys.dm"
#include "code\modules\vending\wardrobes.dm"
#include "code\modules\vending\youtool.dm"
-#include "code\modules\VR\vr_human.dm"
+#include "code\modules\VR\vr_mob.dm"
#include "code\modules\VR\vr_sleeper.dm"
#include "code\modules\zombie\items.dm"
#include "code\modules\zombie\organs.dm"
diff --git a/tgui/src/interfaces/vr_sleeper.ract b/tgui/src/interfaces/vr_sleeper.ract
index 32f3ab33b3..91074a9425 100644
--- a/tgui/src/interfaces/vr_sleeper.ract
+++ b/tgui/src/interfaces/vr_sleeper.ract
@@ -22,12 +22,14 @@
{{data.vr_avatar.name}}
-
- {{data.vr_avatar.status}}
-
-
- {{Math.round(adata.vr_avatar.health)}}/{{adata.vr_avatar.maxhealth}}
-
+ {{#if data.isliving}}
+
+ {{data.vr_avatar.status}}
+
+
+ {{Math.round(adata.vr_avatar.health)}}/{{adata.vr_avatar.maxhealth}}
+
+ {{/if}}
{{else}}