#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 /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 = "

Welcome, [client ? client.prefs.real_name : "Unknown User"]

" output += "

Setup Character

" if(SSticker.current_state <= GAME_STATE_PREGAME) switch(ready) if(PLAYER_NOT_READY) output += "

\[ [LINKIFY_READY("Ready", PLAYER_READY_TO_PLAY)] | Not Ready | [LINKIFY_READY("Observe", PLAYER_READY_TO_OBSERVE)] \]

" if(PLAYER_READY_TO_PLAY) output += "

\[ Ready | [LINKIFY_READY("Not Ready", PLAYER_NOT_READY)] | [LINKIFY_READY("Observe", PLAYER_READY_TO_OBSERVE)] \]

" if(PLAYER_READY_TO_OBSERVE) output += "

\[ [LINKIFY_READY("Ready", PLAYER_READY_TO_PLAY)] | [LINKIFY_READY("Not Ready", PLAYER_NOT_READY)] | Observe \]

" else output += "

View the Crew Manifest

" output += "

Join Game!

" output += "

[LINKIFY_READY("Observe", PLAYER_READY_TO_OBSERVE)]

" 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 += "

Show Player Polls (NEW!)

" else output += "

Show Player Polls

" qdel(query_get_new_polls) if(QDELETED(src)) return output += "
" //src << browse(output,"window=playersetup;size=210x240;can_close=0") var/datum/browser/popup = new(src, "playersetup", "
New Player Options
", 250, 265) popup.set_window_options("can_close=0") popup.set_content(output) popup.open(0) /mob/dead/new_player/Topic(href, href_list[]) if(src != usr) return 0 if(!client) return 0 //Determines Relevent Population Cap var/relevant_cap var/hpc = CONFIG_GET(number/hard_popcap) var/epc = CONFIG_GET(number/extreme_popcap) if(hpc && epc) relevant_cap = min(hpc, epc) else relevant_cap = max(hpc, epc) if(href_list["show_preferences"]) client.prefs.ShowChoices(src) return 1 if(href_list["ready"]) var/tready = text2num(href_list["ready"]) //Avoid updating ready if we're after PREGAME (they should use latejoin instead) //This is likely not an actual issue but I don't have time to prove that this //no longer is required if(SSticker.current_state <= GAME_STATE_PREGAME) ready = tready //if it's post initialisation and they're trying to observe we do the needful if(!SSticker.current_state < GAME_STATE_PREGAME && tready == PLAYER_READY_TO_OBSERVE) ready = tready make_me_an_observer() return if(href_list["refresh"]) src << browse(null, "window=playersetup") //closes the player setup window new_player_panel() if(href_list["late_join"]) if(!SSticker || !SSticker.IsRoundInProgress()) to_chat(usr, "The round is either not ready, or has already finished...") return if(href_list["late_join"] == "override") LateChoices() return if(SSticker.queued_players.len || (relevant_cap && living_player_count() >= relevant_cap && !(ckey(key) in GLOB.admin_datums))) to_chat(usr, "[CONFIG_GET(string/hard_popcap_message)]") var/queue_position = SSticker.queued_players.Find(usr) if(queue_position == 1) to_chat(usr, "You are next in line to join the game. You will be notified when a slot opens up.") else if(queue_position) to_chat(usr, "There are [queue_position-1] players in front of you in the queue to join the game.") else SSticker.queued_players += usr to_chat(usr, "You have been added to the queue to join the game. Your position in queue is [SSticker.queued_players.len].") return LateChoices() if(href_list["manifest"]) ViewManifest() if(href_list["SelectedJob"]) if(!GLOB.enter_allowed) to_chat(usr, "There is an administrative lock on entering the game!") return if(SSticker.queued_players.len && !(ckey(key) in GLOB.admin_datums)) if((living_player_count() >= relevant_cap) || (src != SSticker.queued_players[1])) to_chat(usr, "Server is full.") return AttemptLateSpawn(href_list["SelectedJob"]) return if(href_list["JoinAsGhostRole"]) if(!GLOB.enter_allowed) to_chat(usr, " There is an administrative lock on entering the game!") if(SSticker.queued_players.len && !(ckey(key) in GLOB.admin_datums)) if((living_player_count() >= relevant_cap) || (src != SSticker.queued_players[1])) to_chat(usr, "Server is full.") return var/obj/effect/mob_spawn/MS = pick(GLOB.mob_spawners[href_list["JoinAsGhostRole"]]) if(MS.attack_ghost(src, latejoinercalling = TRUE)) SSticker.queued_players -= src SSticker.queue_delay = 4 qdel(src) if(!ready && href_list["preference"]) if(client) client.prefs.process_link(src, href_list) else if(!href_list["late_join"]) new_player_panel() if(href_list["showpoll"]) handle_player_polling() return if(href_list["pollid"]) var/pollid = href_list["pollid"] if(istext(pollid)) pollid = text2num(pollid) if(isnum(pollid) && ISINTEGER(pollid)) src.poll_player(pollid) return if(href_list["votepollid"] && href_list["votetype"]) var/pollid = text2num(href_list["votepollid"]) var/votetype = href_list["votetype"] //lets take data from the user to decide what kind of poll this is, without validating it //what could go wrong switch(votetype) if(POLLTYPE_OPTION) var/optionid = text2num(href_list["voteoptionid"]) if(vote_on_poll(pollid, optionid)) to_chat(usr, "Vote successful.") else to_chat(usr, "Vote failed, please try again or contact an administrator.") if(POLLTYPE_TEXT) var/replytext = href_list["replytext"] if(log_text_poll_reply(pollid, replytext)) to_chat(usr, "Feedback logging successful.") else to_chat(usr, "Feedback logging failed, please try again or contact an administrator.") if(POLLTYPE_RATING) var/id_min = text2num(href_list["minid"]) var/id_max = text2num(href_list["maxid"]) if( (id_max - id_min) > 100 ) //Basic exploit prevention //(protip, this stops no exploits) to_chat(usr, "The option ID difference is too big. Please contact administration or the database admin.") return for(var/optionid = id_min; optionid <= id_max; optionid++) if(!isnull(href_list["o[optionid]"])) //Test if this optionid was replied to var/rating if(href_list["o[optionid]"] == "abstain") rating = null else rating = text2num(href_list["o[optionid]"]) if(!isnum(rating) || !ISINTEGER(rating)) return if(!vote_on_numval_poll(pollid, optionid, rating)) to_chat(usr, "Vote failed, please try again or contact an administrator.") return to_chat(usr, "Vote successful.") if(POLLTYPE_MULTI) var/id_min = text2num(href_list["minoptionid"]) var/id_max = text2num(href_list["maxoptionid"]) if( (id_max - id_min) > 100 ) //Basic exploit prevention to_chat(usr, "The option ID difference is too big. Please contact administration or the database admin.") return for(var/optionid = id_min; optionid <= id_max; optionid++) if(!isnull(href_list["option_[optionid]"])) //Test if this optionid was selected var/i = vote_on_multi_poll(pollid, optionid) switch(i) if(0) continue if(1) to_chat(usr, "Vote failed, please try again or contact an administrator.") return if(2) to_chat(usr, "Maximum replies reached.") break to_chat(usr, "Vote successful.") if(POLLTYPE_IRV) if (!href_list["IRVdata"]) to_chat(src, "No ordering data found. Please try again or contact an administrator.") return var/list/votelist = splittext(href_list["IRVdata"], ",") if (!vote_on_irv_poll(pollid, votelist)) to_chat(src, "Vote failed, please try again or contact an administrator.") return to_chat(src, "Vote successful.") //When you cop out of the round (NB: this HAS A SLEEP FOR PLAYER INPUT IN IT) /mob/dead/new_player/proc/make_me_an_observer() if(QDELETED(src) || !src.client) ready = PLAYER_NOT_READY return FALSE var/this_is_like_playing_right = alert(src,"Are you sure you wish to observe? You will not be able to play this round!","Player Setup","Yes","No") if(QDELETED(src) || !src.client || this_is_like_playing_right != "Yes") ready = PLAYER_NOT_READY src << browse(null, "window=playersetup") //closes the player setup window new_player_panel() return FALSE var/mob/dead/observer/observer = new() spawning = TRUE observer.started_as_observer = TRUE close_spawn_windows() var/obj/effect/landmark/observer_start/O = locate(/obj/effect/landmark/observer_start) in GLOB.landmarks_list to_chat(src, "Now teleporting.") if (O) observer.forceMove(O.loc) else to_chat(src, "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.client = client observer.set_ghost_appearance() if(observer.client && observer.client.prefs) observer.real_name = observer.client.prefs.real_name observer.name = observer.real_name observer.update_icon() observer.stop_sound_channel(CHANNEL_LOBBYMUSIC) QDEL_NULL(mind) qdel(src) return TRUE /proc/get_job_unavailable_error_message(retval, jobtitle) switch(retval) if(JOB_AVAILABLE) return "[jobtitle] is available." if(JOB_UNAVAILABLE_GENERIC) return "[jobtitle] is unavailable." if(JOB_UNAVAILABLE_BANNED) return "You are currently banned from [jobtitle]." if(JOB_UNAVAILABLE_PLAYTIME) return "You do not have enough relevant playtime for [jobtitle]." if(JOB_UNAVAILABLE_ACCOUNTAGE) return "Your account is not old enough for [jobtitle]." if(JOB_UNAVAILABLE_SLOTFULL) return "[jobtitle] is already filled to capacity." return "Error: Unknown job availability." /mob/dead/new_player/proc/IsJobUnavailable(rank, latejoin = FALSE) var/datum/job/job = SSjob.GetJob(rank) if(!job) return JOB_UNAVAILABLE_GENERIC if((job.current_positions >= job.total_positions) && job.total_positions != -1) if(job.title == "Assistant") if(isnum(client.player_age) && client.player_age <= 14) //Newbies can always be assistants return JOB_AVAILABLE for(var/datum/job/J in SSjob.occupations) if(J && J.current_positions < J.total_positions && J.title != job.title) return JOB_UNAVAILABLE_SLOTFULL else return JOB_UNAVAILABLE_SLOTFULL if(jobban_isbanned(src,rank)) return JOB_UNAVAILABLE_BANNED if(QDELETED(src)) return JOB_UNAVAILABLE_GENERIC if(!job.player_old_enough(client)) return JOB_UNAVAILABLE_ACCOUNTAGE if(job.required_playtime_remaining(client)) return JOB_UNAVAILABLE_PLAYTIME if(latejoin && !job.special_check_latejoin(client)) return JOB_UNAVAILABLE_GENERIC return JOB_AVAILABLE /mob/dead/new_player/proc/AttemptLateSpawn(rank) var/error = IsJobUnavailable(rank) if(error != JOB_AVAILABLE) alert(src, get_job_unavailable_error_message(error, rank)) return FALSE if(SSticker.late_join_disabled) alert(src, "An administrator has disabled late join spawning.") return FALSE var/arrivals_docked = TRUE if(SSshuttle.arrivals) close_spawn_windows() //In case we get held up if(SSshuttle.arrivals.damaged && CONFIG_GET(flag/arrivals_shuttle_require_safe_latejoin)) src << alert("The arrivals shuttle is currently malfunctioning! You cannot join.") return FALSE if(CONFIG_GET(flag/arrivals_shuttle_require_undocked)) SSshuttle.arrivals.RequireUndocked(src) arrivals_docked = SSshuttle.arrivals.mode != SHUTTLE_CALL //Remove the player from the join queue if he was in one and reset the timer SSticker.queued_players -= src SSticker.queue_delay = 4 SSjob.AssignRole(src, rank, 1) var/mob/living/character = create_character(TRUE) //creates the human and transfers vars and mind var/equip = SSjob.EquipRank(character, rank, TRUE) if(isliving(equip)) //Borgs get borged in the equip, so we need to make sure we handle the new mob. character = equip var/datum/job/job = SSjob.GetJob(rank) if(job && !job.override_latejoin_spawn(character)) SSjob.SendToLateJoin(character) if(!arrivals_docked) var/obj/screen/splash/Spl = new(character.client, TRUE) Spl.Fade(TRUE) character.playsound_local(get_turf(character), 'sound/voice/ApproachingTG.ogg', 25) character.update_parallax_teleport() SSticker.minds += character.mind var/mob/living/carbon/human/humanc if(ishuman(character)) humanc = character //Let's retypecast the var to be human, if(humanc) //These procs all expect humans GLOB.data_core.manifest_inject(humanc) if(SSshuttle.arrivals) SSshuttle.arrivals.QueueAnnounce(humanc, rank) else AnnounceArrival(humanc, rank) AddEmploymentContract(humanc) if(GLOB.highlander) to_chat(humanc, "THERE CAN BE ONLY ONE!!!") humanc.make_scottish() if(GLOB.summon_guns_triggered) give_guns(humanc) if(GLOB.summon_magic_triggered) give_magic(humanc) GLOB.joined_player_list += character.ckey GLOB.latejoiners += character if(CONFIG_GET(flag/allow_latejoin_antagonists) && humanc) //Borgs aren't allowed to be antags. Will need to be tweaked if we get true latejoin ais. if(SSshuttle.emergency) switch(SSshuttle.emergency.mode) if(SHUTTLE_RECALL, SHUTTLE_IDLE) SSticker.mode.make_antag_chance(humanc) if(SHUTTLE_CALL) if(SSshuttle.emergency.timeLeft(1) > initial(SSshuttle.emergencyCallTime)*0.5) SSticker.mode.make_antag_chance(humanc) if(humanc && CONFIG_GET(flag/roundstart_traits)) SSquirks.AssignQuirks(humanc, humanc.client, TRUE, FALSE, job, FALSE) log_manifest(character.mind.key,character.mind,character,latejoin = TRUE) /mob/dead/new_player/proc/AddEmploymentContract(mob/living/carbon/human/employee) //TODO: figure out a way to exclude wizards/nukeops/demons from this. for(var/C in GLOB.employmentCabinets) var/obj/structure/filingcabinet/employment/employmentCabinet = C if(!employmentCabinet.virgin) employmentCabinet.addFile(employee) /mob/dead/new_player/proc/LateChoices() var/level = "green" switch(GLOB.security_level) if(SEC_LEVEL_BLUE) level = "blue" if(SEC_LEVEL_AMBER) level = "amber" if(SEC_LEVEL_RED) level = "red" if(SEC_LEVEL_DELTA) level = "delta" var/dat = "
Round Duration: [DisplayTimeText(world.time - SSticker.round_start_time)]
Alert Level: [capitalize(level)]
" if(SSshuttle.emergency) switch(SSshuttle.emergency.mode) if(SHUTTLE_ESCAPE) dat += "
The station has been evacuated.

" if(SHUTTLE_CALL) if(!SSshuttle.canRecall()) dat += "
The station is currently undergoing evacuation procedures.

" var/available_job_count = 0 for(var/datum/job/job in SSjob.occupations) if(job && IsJobUnavailable(job.title, TRUE) == JOB_AVAILABLE) available_job_count++ for(var/spawner in GLOB.mob_spawners) if(!LAZYLEN(spawner)) continue var/obj/effect/mob_spawn/S = pick(GLOB.mob_spawners[spawner]) if(!istype(S) || !S.can_latejoin()) continue available_job_count++ break if(!available_job_count) dat += "
There are currently no open positions!
" else dat += "
Choose from the following open positions:

" var/list/categorizedJobs = list( "Command" = list(jobs = list(), titles = GLOB.command_positions, color = "#aac1ee"), "Engineering" = list(jobs = list(), titles = GLOB.engineering_positions, color = "#ffd699"), "Supply" = list(jobs = list(), titles = GLOB.supply_positions, color = "#ead4ae"), "Miscellaneous" = list(jobs = list(), titles = list(), color = "#ffffff", colBreak = TRUE), "Ghost Role" = list(jobs = list(), titles = GLOB.mob_spawners, color = "#ffffff"), "Synthetic" = list(jobs = list(), titles = GLOB.nonhuman_positions, color = "#ccffcc"), "Service" = list(jobs = list(), titles = GLOB.civilian_positions, color = "#cccccc"), "Medical" = list(jobs = list(), titles = GLOB.medical_positions, color = "#99ffe6", colBreak = TRUE), "Science" = list(jobs = list(), titles = GLOB.science_positions, color = "#e6b3e6"), "Security" = list(jobs = list(), titles = GLOB.security_positions, color = "#ff9999"), ) for(var/spawner in GLOB.mob_spawners) if(!LAZYLEN(spawner)) continue var/obj/effect/mob_spawn/S = pick(GLOB.mob_spawners[spawner]) if(!istype(S) || !S.can_latejoin()) continue categorizedJobs["Ghost Role"]["jobs"] += spawner for(var/datum/job/job in SSjob.occupations) if(job && IsJobUnavailable(job.title, TRUE) == JOB_AVAILABLE) var/categorized = FALSE for(var/jobcat in categorizedJobs) var/list/jobs = categorizedJobs[jobcat]["jobs"] if(job.title in categorizedJobs[jobcat]["titles"]) categorized = TRUE if(jobcat == "Command") if(job.title == "Captain") // Put captain at top of command jobs 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 dat += "
" for(var/jobcat in categorizedJobs) if(categorizedJobs[jobcat]["colBreak"]) dat += "" if(!length(categorizedJobs[jobcat]["jobs"])) continue var/color = categorizedJobs[jobcat]["color"] dat += "
" dat += "[jobcat]" for(var/datum/job/job in categorizedJobs[jobcat]["jobs"]) var/position_class = "otherPosition" if(job.title in GLOB.command_positions) position_class = "commandPosition" if(job in SSjob.prioritized_jobs) dat += "[job.title] ([job.current_positions])" else dat += "[job.title] ([job.current_positions])" categorizedJobs[jobcat]["jobs"] -= job for(var/spawner in categorizedJobs[jobcat]["jobs"]) dat += "[spawner]" dat += "

" dat += "
" dat += "" // 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", 680, 580) popup.add_stylesheet("playeroptions", 'html/browser/playeroptions.css') popup.set_content(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