Files
Paradise/code/modules/mob/new_player/new_player.dm
Ahzpy d2b092dad5 Round Rejoining (#30342)
* very simple functionality test

* formatting fix

* adapt 220 code, add logging, adjust config

* fixes

* appeases review overlords

* fixes

* 25 min respawn delay, warning is more noticable

* 10 minute respawn delay, cant respawn during wiz or nukies

* more logging + logging fix

* species logging, revert accidental config change

* antag logging + formatting

* pleases review overlords again

* linters

* uses CSS for warning

Co-authored-by: warriorstar-orion <orion@snowfrost.garden>
Signed-off-by: Ahzpy <88119260+Ahzpy@users.noreply.github.com>

* deconflicts paradise.dme?

* fixes runtime with destroyed bodies

* you cant respawn for ragin mages silly

* adds respawn button to ghost hud

* standardize new ghost button coloring

* remove you are not an admin message

* muscle memory fixer

* update hud locations

---------

Signed-off-by: Ahzpy <88119260+Ahzpy@users.noreply.github.com>
Co-authored-by: warriorstar-orion <orion@snowfrost.garden>
2025-10-11 15:37:45 +00:00

625 lines
25 KiB
Plaintext

/mob/new_player
var/ready = FALSE
var/spawning = FALSE //Referenced when you want to delete the new_player later on in the code.
/// Has this player chosen to respawn as a new character?
var/chose_respawn = FALSE
universal_speak = TRUE
invisibility = 101
density = FALSE
stat = DEAD
/mob/new_player/Initialize(mapload)
SHOULD_CALL_PARENT(FALSE)
if(initialized)
stack_trace("Warning: [src]([type]) initialized multiple times!")
initialized = TRUE
input_focus = src
GLOB.mob_list += src
return INITIALIZE_HINT_NORMAL
/mob/new_player/Destroy()
if(spawning)
// The mind is being reused elsewhere, so just unhook it here.
mind = null
if(mind)
// Minds really shouldn't bind to new players, but just in case...
mind.unbind()
qdel(mind)
return ..()
/mob/new_player/proc/new_player_panel()
if(client.tos_consent || GLOB.configuration.system.external_tos_handler)
new_player_panel_proc()
else
privacy_consent()
/mob/new_player/proc/privacy_consent()
var/output = "<!DOCTYPE html>[GLOB.join_tos]"
// Dont blank out the other window. This one is read only.
if(!GLOB.configuration.system.external_tos_handler)
src << browse(null, "window=playersetup")
output += "<p><a href='byond://?src=[UID()];consent_signed=SIGNED'>I consent</A>"
output += "<p><a href='byond://?src=[UID()];consent_rejected=NOTSIGNED'>I DO NOT consent</A>"
src << browse(output,"window=privacy_consent;size=500x300")
var/datum/browser/popup = new(src, "privacy_consent", "<div align='center'>Privacy Consent</div>", 500, 400)
// Let them close it here, this is a read only pane
if(!GLOB.configuration.system.external_tos_handler)
popup.set_window_options("can_close=0")
popup.set_content(output)
popup.open(0)
return
/mob/new_player/proc/new_player_panel_proc()
set waitfor = FALSE
var/real_name = client.prefs.active_character.real_name
if(client.prefs.toggles2 & PREFTOGGLE_2_RANDOMSLOT)
real_name = "Random Character Slot"
var/output = "<center><p><a href='byond://?src=[UID()];show_preferences=1'>Setup Character</A><br /><i>[real_name]</i></p>"
if(SSticker.current_state <= GAME_STATE_PREGAME)
if(!ready)
output += "<p><a href='byond://?src=[UID()];ready=1'>Declare Ready</A></p>"
else
output += "<p><b>You are ready</b> (<a href='byond://?src=[UID()];ready=2'>Cancel</A>)</p>"
else
output += "<p><a href='byond://?src=[UID()];manifest=1'>View the Crew Manifest</A></p>"
output += "<p><a href='byond://?src=[UID()];late_join=1'>Join Game!</A></p>"
var/list/antags = client.prefs.be_special
if(length(antags))
if(!client.persistent.skip_antag)
output += "<p><a href='byond://?src=[UID()];skip_antag=1'>Global Antag Candidacy</A>"
else
output += "<p><a href='byond://?src=[UID()];skip_antag=2'>Global Antag Candidacy</A>"
output += "<br /><small>You are <b>[client.persistent.skip_antag ? "ineligible" : "eligible"]</b> for all antag roles.</small></p>"
if(SSticker.current_state == GAME_STATE_STARTUP)
output += "<p>Observe (Please wait...)</p>"
else
output += "<p><a href='byond://?src=[UID()];observe=1'>Observe</A></p>"
if(GLOB.join_tos)
output += "<p><a href='byond://?src=[UID()];tos=1'>Terms of Service</A></p>"
if(length(GLOB.configuration.system.region_map))
output += "<p><a href='byond://?src=[UID()];setregion=1'>Set region (reduces ping)</A></p>"
output += "</center>"
var/datum/browser/popup = new(src, "playersetup", "<div align='center'>New Player Options</div>", 240, 340)
popup.set_window_options("can_close=0")
popup.set_content(output)
popup.open(FALSE)
/mob/new_player/get_status_tab_items()
var/list/status_tab_data = ..()
. = status_tab_data
if(SSticker)
if(!SSticker.hide_mode)
status_tab_data[++status_tab_data.len] = list("Game Mode:", "[GLOB.master_mode]")
else
status_tab_data[++status_tab_data.len] = list("Game Mode:", "Secret")
/mob/new_player/Topic(href, href_list[])
if(!client)
return FALSE
if(usr != src)
message_admins("[key_name_admin(usr)] may have attempted to href exploit with [key_name_admin(src)]'s new_player mob.")
return
if(href_list["consent_signed"])
var/datum/db_query/query = SSdbcore.NewQuery("REPLACE INTO privacy (ckey, datetime, consent) VALUES (:ckey, Now(), 1)", list(
"ckey" = ckey
))
// If the query fails we dont want them permenantly stuck on being unable to accept TOS
query.warn_execute()
qdel(query)
src << browse(null, "window=privacy_consent")
client.tos_consent = TRUE
new_player_panel_proc()
if(href_list["consent_rejected"])
client.tos_consent = FALSE
to_chat(usr, "<span class='warning'>You must consent to the terms of service before you can join!</span>")
var/datum/db_query/query = SSdbcore.NewQuery("REPLACE INTO privacy (ckey, datetime, consent) VALUES (:ckey, Now(), 0)", list(
"ckey" = ckey
))
// If the query fails we dont want them permenantly stuck on being unable to accept TOS
query.warn_execute()
qdel(query)
if(href_list["show_preferences"])
client.prefs.ShowChoices(src)
return TRUE
if(href_list["ready"])
if(!client.tos_consent)
to_chat(usr, "<span class='warning'>You must consent to the terms of service before you can join!</span>")
return FALSE
if(client.version_blocked)
client.show_update_notice()
return FALSE
if(!ready && !client.prefs.active_character.check_any_job() && (client.prefs.active_character.alternate_option == RETURN_TO_LOBBY))
to_chat(usr, "<span class='danger'>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.</span>")
ready = FALSE
return FALSE
ready = !ready
new_player_panel_proc()
if(href_list["skip_antag"])
client.persistent.skip_antag = !client.persistent.skip_antag
new_player_panel_proc()
if(href_list["refresh"])
src << browse(null, "window=playersetup") //closes the player setup window
new_player_panel_proc()
if(href_list["observe"])
if(!client.tos_consent)
to_chat(usr, "<span class='warning'>You must consent to the terms of service before you can join!</span>")
return FALSE
if(client.version_blocked)
client.show_update_notice()
return FALSE
if(!SSticker || SSticker.current_state == GAME_STATE_STARTUP)
to_chat(usr, "<span class='warning'>You must wait for the server to finish starting before you can join!</span>")
return FALSE
if(alert(usr, "Are you sure you wish to observe? You cannot normally join the round after doing this!", "Observe", "Yes", "No") == "Yes")
if(!client)
return TRUE
var/mob/dead/observer/observer = new(src, GHOST_FLAGS_START_AS_OBSERVER)
src << browse(null, "window=playersetup")
spawning = TRUE
stop_sound_channel(CHANNEL_LOBBYMUSIC)
if(ROUND_TIME <= (GLOB.configuration.general.roundstart_observer_period MINUTES))
GLOB.roundstart_observer_keys |= ckey
var/period_human_readable = "within [GLOB.configuration.general.roundstart_observer_period] minute\s"
if(GLOB.configuration.general.roundstart_observer_period == 0)
period_human_readable = "before the round started"
to_chat(src, "<span class='notice'>As you observed [period_human_readable], you can freely toggle antag-hud without losing respawnability, and can freely observe what other players see.</span>")
if(!check_rights(R_MOD | R_ADMIN | R_MENTOR, FALSE, src))
// admins always get aobserve
add_verb(observer, list(/mob/dead/observer/proc/do_observe, /mob/dead/observer/proc/observe))
close_spawn_windows()
var/obj/spawn_point
if(SSticker.current_state < GAME_STATE_PLAYING)
spawn_point = pick(GLOB.roundstart_observer_start)
else
spawn_point = locate("landmark*Observer-Start")
to_chat(src, "<span class='notice'>Now teleporting.</span>")
observer.forceMove(get_turf(spawn_point))
observer.timeofdeath = world.time // Set the time of death so that the respawn timer works correctly.
client.prefs.active_character.update_preview_icon(1)
observer.icon = client.prefs.active_character.preview_icon
observer.alpha = 127
if(client.prefs.active_character.be_random_name)
client.prefs.active_character.real_name = random_name(client.prefs.active_character.gender,client.prefs.active_character.species)
observer.real_name = client.prefs.active_character.real_name
observer.name = observer.real_name
observer.key = key
ADD_TRAIT(observer, TRAIT_RESPAWNABLE, GHOSTED)
qdel(src)
return TRUE
return FALSE
if(href_list["tos"])
privacy_consent()
return FALSE
if(href_list["setregion"])
usr.client.change_region()
return FALSE
if(href_list["late_join"])
if(!client.tos_consent)
to_chat(usr, "<span class='warning'>You must consent to the terms of service before you can join!</span>")
return FALSE
if(client.version_blocked)
client.show_update_notice()
return FALSE
if(!SSticker || SSticker.current_state != GAME_STATE_PLAYING)
to_chat(usr, "<span class='warning'>The round is either not ready, or has already finished...</span>")
return
if(!can_use_species(src, client.prefs.active_character.species))
to_chat(src, alert("You are currently not whitelisted to play [client.prefs.active_character.species]."))
return FALSE
LateChoices()
if(href_list["manifest"])
ViewManifest()
if(href_list["SelectedJob"])
if(!GLOB.enter_allowed)
to_chat(usr, "<span class='notice'>There is an administrative lock on entering the game!</span>")
return
if(client.prefs.toggles2 & PREFTOGGLE_2_RANDOMSLOT)
client.prefs.load_random_character_slot(client)
if(!can_use_species(src, client.prefs.active_character.species))
to_chat(src, alert("You are currently not whitelisted to play [client.prefs.active_character.species]."))
return FALSE
AttemptLateSpawn(href_list["SelectedJob"])
return
if(!ready && href_list["preference"])
if(client)
client.prefs.process_link(src, href_list)
else if(!href_list["late_join"])
new_player_panel()
/mob/new_player/proc/IsJobAvailable(rank)
var/datum/job/job = SSjobs.GetJob(rank)
if(!job)
return FALSE
if(!job.is_position_available())
return FALSE
if(jobban_isbanned(src, rank))
return FALSE
if(!job.player_old_enough(client))
return FALSE
if(job.admin_only && !check_rights(R_EVENT, FALSE))
return FALSE
if(job.get_exp_restrictions(client))
return FALSE
if(job.mentor_only && !check_rights(R_MENTOR | R_ADMIN, FALSE))
return FALSE
if(GLOB.configuration.jobs.assistant_limit)
if(job.title == "Assistant")
var/count = 0
var/datum/job/officer = SSjobs.GetJob("Security Officer")
var/datum/job/warden = SSjobs.GetJob("Warden")
var/datum/job/hos = SSjobs.GetJob("Head of Security")
count += (officer.current_positions + warden.current_positions + hos.current_positions)
if(job.current_positions > (GLOB.configuration.jobs.assistant_security_ratio * count))
if(count >= 5) // if theres more than 5 security on the station just let assistants join regardless, they should be able to handle the tide
return 1
return 0
return 1
/mob/new_player/proc/IsAdminJob(rank)
var/datum/job/job = SSjobs.GetJob(rank)
if(job.admin_only)
return 1
else
return 0
/mob/new_player/proc/IsERTSpawnJob(rank)
var/datum/job/job = SSjobs.GetJob(rank)
if(job.spawn_ert)
return 1
else
return 0
/mob/new_player/proc/IsSyndicateCommand(rank)
var/datum/job/job = SSjobs.GetJob(rank)
if(job.syndicate_command)
return 1
else
return 0
/mob/new_player/proc/AttemptLateSpawn(rank)
if(src != usr)
return 0
if(!SSticker || SSticker.current_state != GAME_STATE_PLAYING)
to_chat(usr, "<span class='warning'>The round is either not ready, or has already finished...</span>")
return 0
if(!GLOB.enter_allowed)
to_chat(usr, "<span class='notice'>There is an administrative lock on entering the game!</span>")
return 0
if(!IsJobAvailable(rank))
to_chat(src, alert("[rank] is not available. Please try another."))
return 0
var/datum/job/thisjob = SSjobs.GetJob(rank)
if(thisjob.barred_by_disability(client))
to_chat(src, alert("[rank] is not available due to your character's disability. Please try another."))
return 0
if(thisjob.barred_by_missing_limbs(client))
to_chat(src, alert("[rank] is not available due to your character having amputated limbs without a prosthetic replacement. Please try another."))
return 0
SSjobs.job_selector.latejoin_assign(src, thisjob)
var/mob/living/character = create_character() //creates the human and transfers vars and mind
character = SSjobs.AssignRank(character, rank, TRUE) //equips the human
if(chose_respawn)
SSblackbox.record_feedback("tally", "player_respawn", 1, "[thisjob]")
log_and_message_admins("[character.ckey] has respawned as [character.real_name], \a [character.dna?.species ? character.dna.species : "Undefined species"] [rank].")
// AIs don't need a spawnpoint, they must spawn at an empty core
if(character.mind.assigned_role == "AI")
var/mob/living/silicon/ai/ai_character = character.AIize() // AIize the character, but don't move them yet
// IsJobAvailable for AI checks that there is an empty core available in this list
ai_character.moveToEmptyCore()
AnnounceCyborg(ai_character, rank, "has been downloaded to the empty core in \the [get_area(ai_character)]")
SSticker.mode.latespawn(ai_character)
qdel(src)
return
//Find our spawning point.
var/join_message
if(IsAdminJob(rank))
if(IsERTSpawnJob(rank))
character.loc = pick(GLOB.ertdirector)
else if(IsSyndicateCommand(rank))
character.loc = pick(GLOB.syndicateofficer)
else
character.forceMove(pick(GLOB.aroomwarp))
join_message = "has arrived"
else
character.forceMove(pick(GLOB.latejoin))
join_message = "has arrived on the station"
character.lastarea = get_area(loc)
// Moving wheelchair if they have one
if(character.buckled && istype(character.buckled, /obj/structure/chair/wheelchair))
character.buckled.forceMove(character.loc)
character.buckled.dir = character.dir
character = SSjobs.EquipRank(character, rank, 1) //equips the human
SSticker.equip_cuis(character) // Gives them their CUIs
SSticker.mode.latespawn(character)
if(character.mind.assigned_role == "Cyborg")
AnnounceCyborg(character, rank, join_message)
else
SSticker.minds += character.mind//Cyborgs and AIs handle this in the transform proc. //TODO!!!!! ~Carn
if(!IsAdminJob(rank))
GLOB.data_core.manifest_inject(character)
AnnounceArrival(character, rank, join_message)
if(length(GLOB.current_pending_diseases) && character.ForceContractDisease(GLOB.current_pending_diseases[1]["disease"], TRUE, TRUE))
var/datum/event/disease_outbreak/outbreak = GLOB.current_pending_diseases[1]["event"]
outbreak.force_disease_time = 0
popleft(GLOB.current_pending_diseases)
if(GLOB.summon_guns_triggered)
give_guns(character)
if(GLOB.summon_magic_triggered)
give_magic(character)
if(!thisjob.is_position_available() && (thisjob in SSjobs.prioritized_jobs))
SSjobs.prioritized_jobs -= thisjob
qdel(src)
/mob/new_player/proc/AnnounceArrival(mob/living/carbon/human/character, rank, join_message)
if(SSticker.current_state == GAME_STATE_PLAYING)
var/ailist[] = list()
for(var/mob/living/silicon/ai/A in GLOB.ai_list)
if(A.stat != DEAD && A.announce_arrivals)
ailist += A
if(length(ailist))
var/mob/living/silicon/ai/announcer = pick(ailist)
if(character.mind)
if((character.mind.assigned_role != "Cyborg") && (character.mind.assigned_role != character.mind.special_role))
if(character.mind.role_alt_title)
rank = character.mind.role_alt_title
var/arrivalmessage = announcer.arrivalmsg
arrivalmessage = replacetext(arrivalmessage,"$name",character.real_name)
arrivalmessage = replacetext(arrivalmessage,"$rank",rank ? "[rank]" : "visitor")
arrivalmessage = replacetext(arrivalmessage,"$species",character.dna.species.name)
arrivalmessage = replacetext(arrivalmessage,"$age",num2text(character.age))
// Account for genderless mobs
var/target_gender = "genderless"
switch(character.gender)
if(MALE)
target_gender = "male"
if(FEMALE)
target_gender = "female"
arrivalmessage = replacetext(arrivalmessage,"$gender",target_gender)
announcer.say(";[arrivalmessage]", ignore_languages = TRUE, automatic = TRUE)
else
if(character.mind)
if((character.mind.assigned_role != "Cyborg") && (character.mind.assigned_role != character.mind.special_role))
if(character.mind.role_alt_title)
rank = character.mind.role_alt_title
GLOB.global_announcer.autosay("[character.real_name],[rank ? " [rank]," : " visitor," ] [join_message ? join_message : "has arrived on the station"].", "Arrivals Announcement Computer", follow_target_override = character)
/mob/new_player/proc/AnnounceCyborg(mob/living/character, rank, join_message)
if(SSticker.current_state == GAME_STATE_PLAYING)
var/ailist[] = list()
for(var/mob/living/silicon/ai/A in GLOB.ai_list)
ailist += A
if(length(ailist))
var/mob/living/silicon/ai/announcer = pick(ailist)
if(character.mind)
if(character.mind.assigned_role != character.mind.special_role)
var/arrivalmessage = "A new[rank ? " [rank]" : " visitor" ] [join_message ? join_message : "has arrived on the station"]."
announcer.say(";[arrivalmessage]", ignore_languages = TRUE, automatic = TRUE)
else
if(character.mind)
if(character.mind.assigned_role != character.mind.special_role)
// can't use their name here, since cyborg namepicking is done post-spawn, so we'll just say "A new Cyborg has arrived"/"A new Android has arrived"/etc.
GLOB.global_announcer.autosay("A new[rank ? " [rank]" : " visitor" ] [join_message ? join_message : "has arrived on the station"].", "Arrivals Announcement Computer", follow_target_override = character)
/mob/new_player/proc/LateChoices()
var/mills = ROUND_TIME // 1/10 of a second, not real milliseconds but whatever
//var/secs = ((mills % 36000) % 600) / 10 //Not really needed, but I'll leave it here for refrence.. or something
var/mins = (mills % 36000) / 600
var/hours = mills / 36000
var/dat = "<html><meta charset='utf-8'><body><center>"
dat += "Round Duration: [round(hours)]h [round(mins)]m<br>"
dat += "<b>The station alert level is: [SSsecurity_level.get_colored_current_security_level_name()]</b><br>"
if(SSshuttle.emergency.mode >= SHUTTLE_ESCAPE)
dat += "<font color='red'><b>The station has been evacuated.</b></font><br>"
else if(SSshuttle.emergency.mode >= SHUTTLE_CALL)
dat += "<font color='red'>The station is currently undergoing evacuation procedures.</font><br>"
if(length(SSjobs.prioritized_jobs))
dat += "<font color='lime'>The station has flagged these jobs as high priority: "
var/amt = length(SSjobs.prioritized_jobs)
var/amt_count
for(var/datum/job/a in SSjobs.prioritized_jobs)
amt_count++
if(amt_count != amt)
dat += " [a.title], "
else
dat += " [a.title]. </font><br>"
var/num_jobs_available = 0
var/list/activePlayers = list()
var/list/categorizedJobs = list(
"Command" = list(jobs = list(), titles = GLOB.command_positions, color = "#aac1ee"),
"Engineering" = list(jobs = list(), titles = GLOB.engineering_positions, color = "#ffd699"),
"Security" = list(jobs = list(), titles = GLOB.active_security_positions, color = "#ff9999"),
"Miscellaneous" = list(jobs = list(), titles = list(), color = "#ffffff", colBreak = 1),
"Synthetic" = list(jobs = list(), titles = GLOB.nonhuman_positions, color = "#ccffcc"),
"Support / Service" = list(jobs = list(), titles = GLOB.service_positions, color = "#cccccc"),
"Medical" = list(jobs = list(), titles = GLOB.medical_positions, color = "#99ffe6", colBreak = 1),
"Science" = list(jobs = list(), titles = GLOB.science_positions, color = "#e6b3e6"),
"Supply" = list(jobs = list(), titles = GLOB.supply_positions, color = "#ead4ae"),
)
for(var/datum/job/job in SSjobs.occupations)
if(job && IsJobAvailable(job.title) && !job.barred_by_disability(client) && !job.barred_by_missing_limbs(client))
num_jobs_available++
activePlayers[job] = 0
var/categorized = 0
// Only players with the job assigned and AFK for less than 10 minutes count as active
for(var/mob/M in GLOB.player_list) if(M.mind && M.client && M.mind.assigned_role == job.title && M.client.inactivity <= 10 MINUTES)
activePlayers[job]++
for(var/jobcat in categorizedJobs)
var/list/jobs = categorizedJobs[jobcat]["jobs"]
if(job.title in categorizedJobs[jobcat]["titles"])
categorized = 1
if(jobcat == "Command") // Put captain at top of command jobs
if(job.title == "Captain")
jobs.Insert(1, job)
else
jobs += job
else // Put heads at top of non-command jobs
if(job.title in GLOB.command_positions)
jobs.Insert(1, job)
else
jobs += job
if(!categorized)
categorizedJobs["Miscellaneous"]["jobs"] += job
if(num_jobs_available)
dat += "Choose from the following open positions:<br><br>"
dat += "<table><tr><td valign='top'>"
for(var/jobcat in categorizedJobs)
if(categorizedJobs[jobcat]["colBreak"])
dat += "</td><td valign='top'>"
if(length(categorizedJobs[jobcat]["jobs"]) < 1)
continue
var/color = categorizedJobs[jobcat]["color"]
dat += "<fieldset style='border: 2px solid [color]; display: inline'>"
dat += "<legend align='center' style='color: [color]'>[jobcat]</legend>"
for(var/datum/job/job in categorizedJobs[jobcat]["jobs"])
if(job in SSjobs.prioritized_jobs)
dat += "<a href='byond://?src=[UID()];SelectedJob=[job.title]'><font color='lime'><B>[job.title] ([job.current_positions]) (Active: [activePlayers[job]])</B></font></a><br>"
else
dat += "<a href='byond://?src=[UID()];SelectedJob=[job.title]'>[job.title] ([job.current_positions]) (Active: [activePlayers[job]])</a><br>"
dat += "</fieldset><br>"
dat += "</td></tr></table></center>"
else
dat += "<br><br><center>Unfortunately, there are no job slots free currently.<BR>Wait a few minutes, then try again.<BR>Or, try observing the round.</center>"
// Removing the old window method but leaving it here for reference
// src << browse(dat, "window=latechoices;size=300x640;can_close=1")
// Added the new browser window method
var/datum/browser/popup = new(src, "latechoices", "Choose Profession", 900, 600)
popup.add_stylesheet("playeroptions", 'html/browser/playeroptions.css')
popup.add_script("delay_interactivity", 'html/browser/delay_interactivity.js')
popup.set_content(dat)
popup.open(0) // 0 is passed to open so that it doesn't use the onclose() proc
/mob/new_player/proc/create_character()
spawning = TRUE
close_spawn_windows()
check_prefs_are_sane()
var/mob/living/carbon/human/new_character = new(loc)
new_character.lastarea = get_area(loc)
client.prefs.active_character.copy_to(new_character)
if(SSticker.random_players)
var/mob/living/carbon/human/H = new_character
scramble(1, H, 100)
H.real_name = random_name(H.gender, H.dna.species.name)
H.sync_organ_dna(assimilate = 1)
H.update_body()
H.reset_hair()
H.reset_markings()
H.dna.ResetUIFrom(H)
H.flavor_text = ""
stop_sound_channel(CHANNEL_LOBBYMUSIC)
mind.set_original_mob(new_character)
mind.transfer_to(new_character)
// Clowns and mimes get appropriate default names, and the chance to pick a custom one.
if(mind.assigned_role == "Clown")
new_character.rename_character(new_character.real_name, pick(GLOB.clown_names))
new_character.rename_self("clown")
else if(mind.assigned_role == "Mime")
new_character.rename_character(new_character.real_name, pick(GLOB.mime_names))
new_character.rename_self("mime")
return new_character
// This is to check that the player only has preferences set that they're supposed to
/mob/new_player/proc/check_prefs_are_sane()
var/datum/species/chosen_species
if(client.prefs.active_character.species)
chosen_species = GLOB.all_species[client.prefs.active_character.species]
if(!(chosen_species && (is_species_whitelisted(chosen_species) || has_admin_rights())))
// Have to recheck admin due to no usr at roundstart. Latejoins are fine though.
stack_trace("[src] had species [client.prefs.active_character.species], though they weren't supposed to. Setting to Human.")
client.prefs.active_character.species = "Human"
var/datum/language/chosen_language
if(client.prefs.active_character.language)
chosen_language = GLOB.all_languages[client.prefs.active_character.language]
if((chosen_language == null && client.prefs.active_character.language != "None") || (chosen_language && chosen_language.flags & RESTRICTED))
stack_trace("[src] had language [client.prefs.active_character.language], though they weren't supposed to. Setting to None.")
client.prefs.active_character.language = "None"
/mob/new_player/proc/ViewManifest()
GLOB.generic_crew_manifest.ui_interact(usr)
/mob/new_player/Move()
return 0
/mob/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
/mob/new_player/proc/has_admin_rights()
return check_rights(R_ADMIN, 0, src)
/mob/new_player/proc/is_species_whitelisted(datum/species/S)
if(!S)
return TRUE // Allow null species?
return can_use_species(src, S.name)
/mob/new_player/get_gender()
if(!client || !client.prefs) ..()
return client.prefs.active_character.gender
/mob/new_player/proc/is_ready()
return ready && client
// No hearing announcements
/mob/new_player/can_hear()
return 0