mirror of
https://github.com/quotefox/Hyper-Station-13.git
synced 2026-08-24 21:26:12 +01:00
Ensures (emagged or non hacked) borgs now show up on the manifest if found when either dead or in the round lobby.
784 lines
31 KiB
Plaintext
784 lines
31 KiB
Plaintext
#define LINKIFY_READY(string, value) "<a href='byond://?src=[REF(src)];ready=[value]'>[string]</a>"
|
|
|
|
/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
|
|
|
|
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/refresh_player_panel()
|
|
new_player_panel()
|
|
|
|
/mob/dead/new_player/proc/new_player_panel()
|
|
src << browse(null, "window=playersetup") //closes the player setup window if its already open.
|
|
var/output = ""
|
|
if(SSticker.current_state <= GAME_STATE_PREGAME)
|
|
switch(ready)
|
|
if(PLAYER_NOT_READY)
|
|
output += "<p><a style='background:#912c24;' href='byond://?src=[REF(src)];ready=[PLAYER_READY_TO_PLAY]'>[icon2html('hyperstation/icons/menu/menu.dmi', world, "notready")]Not Ready</a></p>"
|
|
if(PLAYER_READY_TO_OBSERVE)
|
|
output += "<p><a style='background:#912c24;' href='byond://?src=[REF(src)];ready=[PLAYER_READY_TO_PLAY]'>[icon2html('hyperstation/icons/menu/menu.dmi', world, "notready")]Not Ready</a></p>"
|
|
if(PLAYER_READY_TO_PLAY)
|
|
output += "<p><a style='background:#4CAF50;' href='byond://?src=[REF(src)];ready=[PLAYER_NOT_READY]'>[icon2html('hyperstation/icons/menu/menu.dmi', world, "ready")]Ready</a></p>"
|
|
output += "<p><a href='byond://?src=[REF(src)];show_preferences=1'>[icon2html('hyperstation/icons/menu/menu.dmi', world, "settings")]Setup Character</a></p>"
|
|
if(ready == PLAYER_READY_TO_OBSERVE)
|
|
output += "<p><a style='background:#4CAF50;' href='byond://?src=[REF(src)];ready=[PLAYER_NOT_READY]'>[icon2html('hyperstation/icons/menu/menu.dmi', world, "ghost")]Observe</a></p>"
|
|
else
|
|
output += "<p><a style='background:#912c24;' href='byond://?src=[REF(src)];ready=[PLAYER_READY_TO_OBSERVE]'>[icon2html('hyperstation/icons/menu/menu.dmi', world, "ghost")]Observe</a></p>"
|
|
|
|
else
|
|
//make menu preview
|
|
var/mob/living/carbon/human/dummy/mannequin = generate_or_wait_for_human_dummy(DUMMY_HUMAN_SLOT_ROLEPLAY)
|
|
var/icon/preview_icon = icon('icons/effects/effects.dmi', "nothing")
|
|
client.prefs.copy_to(mannequin)
|
|
COMPILE_OVERLAYS(mannequin)
|
|
var/icon/stamp = getFlatIcon(mannequin)
|
|
mannequin.setDir(SOUTH)
|
|
stamp = getFlatIcon(mannequin)
|
|
CHECK_TICK
|
|
preview_icon.Blend(stamp, ICON_OVERLAY, 0, 0)
|
|
CHECK_TICK
|
|
preview_icon.Scale(preview_icon.Width(), preview_icon.Height())
|
|
CHECK_TICK
|
|
unset_busy_human_dummy(DUMMY_HUMAN_SLOT_ROLEPLAY)
|
|
output += "<p><a href='byond://?src=[REF(src)];late_join=1'>[icon2html(preview_icon, world, "preview")]Join Game!</a></p>"
|
|
output += "<p><a href='byond://?src=[REF(src)];roleplay_join=1'>[icon2html('hyperstation/icons/menu/menu.dmi', world, "roleplay")]Roleplay Roles!</a></p>"
|
|
output += "<p><a href='byond://?src=[REF(src)];show_preferences=1'>[icon2html('hyperstation/icons/menu/menu.dmi', world, "settings")]Setup Character</a></p>"
|
|
output += "<p><a href='byond://?src=[REF(src)];manifest=1'>[icon2html('hyperstation/icons/menu/menu.dmi', world, "manifest")]View the Game Manifest</a></p>"
|
|
output += "<p><a href='byond://?src=[REF(src)];ready=[PLAYER_READY_TO_OBSERVE]'>[icon2html('hyperstation/icons/menu/menu.dmi', world, "ghost")]Observe</a></p>"
|
|
|
|
if(!IsGuestKey(src.key) && SSticker.current_state >= GAME_STATE_PREGAME)
|
|
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 += "<p><b><a href='byond://?src=[rs];showpoll=1'>[icon2html('hyperstation/icons/menu/menu.dmi', world, "manifest")]Show Player Polls</A> (NEW!)</b></p>"
|
|
else
|
|
output += "<p><a href='byond://?src=[rs];showpoll=1'>[icon2html('hyperstation/icons/menu/menu.dmi', world, "manifest")]Show Player Polls</A></p>"
|
|
qdel(query_get_new_polls)
|
|
if(QDELETED(src))
|
|
return
|
|
|
|
output += "</center>"
|
|
|
|
var/datum/browser/popup
|
|
if(SSticker.current_state <= GAME_STATE_PREGAME)
|
|
popup = new(src, "playersetup", "<div align='center'>New Player Options</div>", 268, 202)
|
|
else
|
|
popup = new(src, "playersetup", "<div align='center'>New Player Options</div>", 268, 342)
|
|
popup.set_window_options("can_close=0")
|
|
|
|
popup.add_stylesheet("playersetup", 'html/browser/mainmenu.css')
|
|
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["observe"])
|
|
if(!SSticker.current_state > GAME_STATE_PREGAME)
|
|
make_me_an_observer()
|
|
return
|
|
else
|
|
to_chat(usr, "<span class='notice'>The game is still loading...</span>")
|
|
return
|
|
|
|
|
|
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, "<span class='danger'>The round is either not ready, or has already finished...</span>")
|
|
return
|
|
|
|
if(href_list["late_join"] == "override")
|
|
LateChoices()
|
|
return
|
|
|
|
if(client.prefs.real_name in client.pastcharacters) //if character has been spawned before
|
|
to_chat(usr, "<span class='notice'>You have played that character before this round, please select a new one!</span>")
|
|
return
|
|
|
|
if(SSticker.queued_players.len || (relevant_cap && living_player_count() >= relevant_cap && !(ckey(key) in GLOB.admin_datums)))
|
|
to_chat(usr, "<span class='danger'>[CONFIG_GET(string/hard_popcap_message)]</span>")
|
|
|
|
var/queue_position = SSticker.queued_players.Find(usr)
|
|
if(queue_position == 1)
|
|
to_chat(usr, "<span class='notice'>You are next in line to join the game. You will be notified when a slot opens up.</span>")
|
|
else if(queue_position)
|
|
to_chat(usr, "<span class='notice'>There are [queue_position-1] players in front of you in the queue to join the game.</span>")
|
|
else
|
|
SSticker.queued_players += usr
|
|
to_chat(usr, "<span class='notice'>You have been added to the queue to join the game. Your position in queue is [SSticker.queued_players.len].</span>")
|
|
return
|
|
LateChoices()
|
|
|
|
if(href_list["roleplay_join"])
|
|
if(!SSticker || !SSticker.IsRoundInProgress())
|
|
to_chat(usr, "<span class='danger'>The round is either not ready, or has already finished...</span>")
|
|
return
|
|
|
|
if(href_list["late_join"] == "override")
|
|
LateChoices(TRUE)
|
|
return
|
|
|
|
if(client.prefs.real_name in client.pastcharacters) //if character has been spawned before
|
|
to_chat(usr, "<span class='notice'>You have played that character before this round, please select a new one!</span>")
|
|
return
|
|
|
|
if(SSticker.queued_players.len || (relevant_cap && living_player_count() >= relevant_cap && !(ckey(key) in GLOB.admin_datums)))
|
|
to_chat(usr, "<span class='danger'>[CONFIG_GET(string/hard_popcap_message)]</span>")
|
|
|
|
var/queue_position = SSticker.queued_players.Find(usr)
|
|
if(queue_position == 1)
|
|
to_chat(usr, "<span class='notice'>You are next in line to join the game. You will be notified when a slot opens up.</span>")
|
|
else if(queue_position)
|
|
to_chat(usr, "<span class='notice'>There are [queue_position-1] players in front of you in the queue to join the game.</span>")
|
|
else
|
|
SSticker.queued_players += usr
|
|
to_chat(usr, "<span class='notice'>You have been added to the queue to join the game. Your position in queue is [SSticker.queued_players.len].</span>")
|
|
return
|
|
LateChoices(TRUE)
|
|
|
|
if(href_list["manifest"])
|
|
ViewManifest()
|
|
|
|
if(href_list["SelectedJob"])
|
|
usr << browse(null, "window=roleplay") //closes the window
|
|
if(!SSticker || !SSticker.IsRoundInProgress())
|
|
var/msg = "[key_name(usr)] attempted to join the round using a href that shouldn't be available at this moment!"
|
|
log_admin(msg)
|
|
message_admins(msg)
|
|
to_chat(usr, "<span class='danger'>The round is either not ready, or has already finished...</span>")
|
|
return
|
|
|
|
|
|
if(!GLOB.enter_allowed)
|
|
to_chat(usr, "<span class='notice'>There is an administrative lock on entering the game!</span>")
|
|
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, "<span class='warning'>Server is full.</span>")
|
|
return
|
|
|
|
AttemptLateSpawn(href_list["SelectedJob"])
|
|
return
|
|
|
|
if(href_list["SelectedRoleplayJob"])
|
|
if(!SSticker || !SSticker.IsRoundInProgress())
|
|
var/msg = "[key_name(usr)] attempted to join the round using a href that shouldn't be available at this moment!"
|
|
log_admin(msg)
|
|
message_admins(msg)
|
|
to_chat(usr, "<span class='danger'>The round is either not ready, or has already finished...</span>")
|
|
return
|
|
|
|
|
|
if(!GLOB.enter_allowed)
|
|
to_chat(usr, "<span class='notice'>There is an administrative lock on entering the game!</span>")
|
|
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, "<span class='warning'>Server is full.</span>")
|
|
return
|
|
//make preview
|
|
var/mob/living/carbon/human/dummy/mannequin = generate_or_wait_for_human_dummy(DUMMY_HUMAN_SLOT_ROLEPLAY)
|
|
var/datum/job/roleplay/job = SSjob.GetJob(href_list["SelectedRoleplayJob"])
|
|
var/icon/preview_icon = icon('icons/effects/effects.dmi', "nothing")
|
|
job.equip(mannequin, TRUE)
|
|
client.prefs.copy_to(mannequin)
|
|
COMPILE_OVERLAYS(mannequin)
|
|
var/icon/stamp = getFlatIcon(mannequin)
|
|
mannequin.setDir(SOUTH)
|
|
stamp = getFlatIcon(mannequin)
|
|
CHECK_TICK
|
|
preview_icon.Blend(stamp, ICON_OVERLAY, 0, 0)
|
|
CHECK_TICK
|
|
preview_icon.Scale(preview_icon.Width() * 2, preview_icon.Height() * 2)
|
|
CHECK_TICK
|
|
unset_busy_human_dummy(DUMMY_HUMAN_SLOT_ROLEPLAY)
|
|
|
|
|
|
//make menu
|
|
var/dat = {"<B>[href_list["SelectedRoleplayJob"]]</B><BR><HR>"}
|
|
dat += "<center>[icon2html(preview_icon, world, "preview")]</center><BR><BR>"
|
|
if (length(job.info_text) > 0)
|
|
dat += "[job.info_text]<BR><BR>"
|
|
|
|
if (length(job.quest_info) > 0)
|
|
dat += {"<B>Role Job</B><BR><HR>"}
|
|
dat += "[job.quest_info]<BR><BR>"
|
|
|
|
if (length(job.failure_info) > 0)
|
|
dat += {"<B>Role Failure</B><BR><HR>"}
|
|
dat += "[job.failure_info]<BR><BR>"
|
|
if(client.prefs.roleplayroles)
|
|
dat += "<center><p><a href='byond://?src=[REF(src)];SelectedJob=[job.title]'>Play!</a></p></center>"
|
|
else
|
|
dat += "<center><p><span class='linkOff'>Whitelist Required</span></p></center>"
|
|
var/datum/browser/popup = new(usr, "roleplay", "Roleplay Panel")
|
|
popup.set_content(dat)
|
|
popup.set_title_image(usr.browse_rsc_icon(icon, icon_state), 500,600)
|
|
popup.open()
|
|
|
|
if(href_list["JoinAsGhostRole"])
|
|
if(!GLOB.enter_allowed)
|
|
to_chat(usr, "<span class='notice'> There is an administrative lock on entering the game!</span>")
|
|
|
|
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, "<span class='warning'>Server is full.</span>")
|
|
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, "<span class='notice'>Vote successful.</span>")
|
|
else
|
|
to_chat(usr, "<span class='danger'>Vote failed, please try again or contact an administrator.</span>")
|
|
if(POLLTYPE_TEXT)
|
|
var/replytext = href_list["replytext"]
|
|
if(log_text_poll_reply(pollid, replytext))
|
|
to_chat(usr, "<span class='notice'>Feedback logging successful.</span>")
|
|
else
|
|
to_chat(usr, "<span class='danger'>Feedback logging failed, please try again or contact an administrator.</span>")
|
|
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, "<span class='danger'>Vote failed, please try again or contact an administrator.</span>")
|
|
return
|
|
to_chat(usr, "<span class='notice'>Vote successful.</span>")
|
|
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, "<span class='danger'>Vote failed, please try again or contact an administrator.</span>")
|
|
return
|
|
if(2)
|
|
to_chat(usr, "<span class='danger'>Maximum replies reached.</span>")
|
|
break
|
|
to_chat(usr, "<span class='notice'>Vote successful.</span>")
|
|
if(POLLTYPE_IRV)
|
|
if (!href_list["IRVdata"])
|
|
to_chat(src, "<span class='danger'>No ordering data found. Please try again or contact an administrator.</span>")
|
|
return
|
|
var/list/votelist = splittext(href_list["IRVdata"], ",")
|
|
if (!vote_on_irv_poll(pollid, votelist))
|
|
to_chat(src, "<span class='danger'>Vote failed, please try again or contact an administrator.</span>")
|
|
return
|
|
to_chat(src, "<span class='notice'>Vote successful.</span>")
|
|
|
|
//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?","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
|
|
src.client.respawn_observing = 1
|
|
src.client.lastrespawn = world.time + 1800 SECONDS //reset respawn.
|
|
close_spawn_windows()
|
|
var/obj/effect/landmark/observer_start/O = locate(/obj/effect/landmark/observer_start) in GLOB.landmarks_list
|
|
to_chat(src, "<span class='notice'>Now teleporting.</span>")
|
|
if (O)
|
|
observer.forceMove(O.loc)
|
|
else
|
|
to_chat(src, "<span class='notice'>Teleporting failed. Ahelp an admin please</span>")
|
|
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.client.init_verbs()
|
|
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_WHITELIST)
|
|
return "You are not whitelisted for [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(job.whitelist_type) //whitelisting
|
|
if(job.whitelist_type == "roleplay" && !client.prefs.roleplayroles)
|
|
return JOB_UNAVAILABLE_WHITELIST
|
|
if(job.whitelist_type == "important" && !client.prefs.importantroles)
|
|
return JOB_UNAVAILABLE_WHITELIST
|
|
if(job.whitelist_type == "silly" && !client.prefs.sillyroles)
|
|
return JOB_UNAVAILABLE_WHITELIST
|
|
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/datum/job/job = SSjob.GetJob(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,job.loadout)
|
|
|
|
if(isliving(equip)) //Borgs get borged in the equip, so we need to make sure we handle the new mob.
|
|
character = equip
|
|
|
|
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)
|
|
if(!prob(1))
|
|
character.playsound_local(get_turf(character), 'sound/voice/Approaching.ogg', 25)
|
|
else
|
|
character.playsound_local(get_turf(character), 'sound/voice/boat.ogg', 35) //boatbomber easter egg. (love your videos man, thanks for visiting!)
|
|
|
|
character.update_parallax_teleport()
|
|
|
|
SSticker.minds += character.mind
|
|
character.client.init_verbs() // init verbs for the late join
|
|
|
|
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, humanc.client, humanc.client.prefs)
|
|
if(SSshuttle.arrivals)
|
|
SSshuttle.arrivals.QueueAnnounce(humanc, rank)
|
|
else
|
|
AnnounceArrival(humanc, rank)
|
|
AddEmploymentContract(humanc)
|
|
if(GLOB.highlander)
|
|
to_chat(humanc, "<span class='userdanger'><i>THERE CAN BE ONLY ONE!!!</i></span>")
|
|
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(roleplayonly)
|
|
|
|
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 = "<div class='notice'>Round Duration: [DisplayTimeText(world.time - SSticker.round_start_time)]<br>Alert Level: [capitalize(level)]<br>Chaos Level: [GLOB.dynamic_chaos_level]</div>"
|
|
|
|
if(SSshuttle.emergency)
|
|
switch(SSshuttle.emergency.mode)
|
|
if(SHUTTLE_ESCAPE)
|
|
dat += "<div class='notice red'>The station has been evacuated.</div><br>"
|
|
if(SHUTTLE_CALL)
|
|
if(!SSshuttle.canRecall())
|
|
dat += "<div class='notice red'>The station is currently undergoing evacuation procedures.</div><br>"
|
|
|
|
var/available_job_count = 0
|
|
for(var/datum/job/job in SSjob.occupations)
|
|
if(!roleplayonly)
|
|
if(job && IsJobUnavailable(job.title, TRUE) == JOB_AVAILABLE)
|
|
available_job_count++
|
|
else
|
|
if(job && IsJobUnavailable(job.title, TRUE) == JOB_AVAILABLE)
|
|
if(job.department_flag == ROLEPLAY)
|
|
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 += "<div class='notice red'>There are currently no open positions!</div>"
|
|
|
|
else
|
|
var/list/categorizedJobs
|
|
if(!roleplayonly)
|
|
dat += "<div class='clearBoth'>Choose from the following open positions:</div><br>"
|
|
categorizedJobs = list(
|
|
"Command" = list(jobs = list(), titles = GLOB.command_positions, color = "#aac1ee"),
|
|
"Roleplay" = list(jobs = list(), titles = GLOB.roleplay_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"),
|
|
)
|
|
else
|
|
dat += "<div class='clearBoth'>Choose from the following open positions:</div><br>"
|
|
categorizedJobs = list("Roleplay" = list(jobs = list(), titles = GLOB.roleplay_positions, color = "#aac1ee"))
|
|
if(!roleplayonly)
|
|
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 == "Roleplay" && !roleplayonly)
|
|
continue //dont put roleplay jobs here
|
|
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)
|
|
if(!roleplayonly)
|
|
categorizedJobs["Miscellaneous"]["jobs"] += job
|
|
|
|
|
|
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"]))
|
|
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"])
|
|
var/position_class = "otherPosition"
|
|
if(job.title in GLOB.command_positions)
|
|
position_class = "commandPosition"
|
|
var/jobline = ""
|
|
if(!roleplayonly)
|
|
if(job in SSjob.prioritized_jobs)
|
|
jobline += "<a class='[position_class]' style='display:block;width:170px' href='byond://?src=[REF(src)];SelectedJob=[job.title]'><font color='lime'><b>[job.title] ([job.current_positions])</b></font></a>"
|
|
else
|
|
jobline += "<a class='[position_class]' style='display:block;width:170px' href='byond://?src=[REF(src)];SelectedJob=[job.title]'>[job.title] ([job.current_positions])</a>"
|
|
if(client && client.prefs && client.prefs.alt_titles_preferences[job.title])
|
|
jobline += "<br><span style='color:#BBBBBB; font-style: italic;'>(as [client.prefs.alt_titles_preferences[job.title]])</span>"
|
|
else
|
|
jobline += "<a class='[position_class]' style='display:block;width:170px' href='byond://?src=[REF(src)];SelectedRoleplayJob=[job.title]'><font color='lime'><b>[job.title] ([job.current_positions])</b></font></a>"
|
|
dat += jobline
|
|
categorizedJobs[jobcat]["jobs"] -= job
|
|
|
|
for(var/spawner in categorizedJobs[jobcat]["jobs"])
|
|
dat += "<a class='otherPosition' style='display:block;width:170px' href='byond://?src=[REF(src)];JoinAsGhostRole=[spawner]'>[spawner]</a>"
|
|
|
|
dat += "</fieldset><br>"
|
|
dat += "</td></tr></table></center>"
|
|
dat += "</div></div>"
|
|
|
|
// 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
|
|
client.init_verbs()
|
|
//h13 assign your characters custom height.
|
|
if (H.custom_body_size) //Do they have it set?
|
|
H.resize(H.custom_body_size * 0.01)
|
|
if (H.breedable == TRUE)
|
|
H.impregchance = 25
|
|
. = 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 = "<html><body>"
|
|
dat += "<h4>Game Manifest</h4>"
|
|
dat += GLOB.data_core.get_manifest(OOC = TRUE)
|
|
|
|
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
|
|
|