mirror of
https://github.com/yogstation13/Yogstation.git
synced 2025-02-26 09:04:50 +00:00
502 lines
19 KiB
Plaintext
502 lines
19 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 = 0
|
|
|
|
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 = "<center><p><a href='byond://?src=[REF(src)];show_preferences=1'>Setup Character</a></p>"
|
|
|
|
if(SSticker.current_state <= GAME_STATE_PREGAME)
|
|
switch(ready)
|
|
if(PLAYER_NOT_READY)
|
|
output += "<p>\[ [LINKIFY_READY("Ready", PLAYER_READY_TO_PLAY)] | <b>Not Ready</b> | [LINKIFY_READY("Observe", PLAYER_READY_TO_OBSERVE)] \]</p>"
|
|
if(PLAYER_READY_TO_PLAY)
|
|
output += "<p>\[ <b>Ready</b> | [LINKIFY_READY("Not Ready", PLAYER_NOT_READY)] | [LINKIFY_READY("Observe", PLAYER_READY_TO_OBSERVE)] \]</p>"
|
|
if(PLAYER_READY_TO_OBSERVE)
|
|
output += "<p>\[ [LINKIFY_READY("Ready", PLAYER_READY_TO_PLAY)] | [LINKIFY_READY("Not Ready", PLAYER_NOT_READY)] | <b> Observe </b> \]</p>"
|
|
else
|
|
output += "<p><a href='byond://?src=[REF(src)];manifest=1'>View the Crew Manifest</a></p>"
|
|
output += "<p><a href='byond://?src=[REF(src)];late_join=1'>Join Game!</a></p>"
|
|
output += "<p>[LINKIFY_READY("Observe", PLAYER_READY_TO_OBSERVE)]</p>"
|
|
|
|
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 = \"[ckey]\") AND id NOT IN (SELECT pollid FROM [format_table_name("poll_textreply")] WHERE ckey = \"[ckey]\")")
|
|
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=[REF(src)];showpoll=1'>Show Player Polls</A> (NEW!)</b></p>"
|
|
else
|
|
output += "<p><a href='byond://?src=[REF(src)];showpoll=1'>Show Player Polls</A></p>"
|
|
|
|
output += "</center>"
|
|
|
|
//src << browse(output,"window=playersetup;size=210x240;can_close=0")
|
|
var/datum/browser/popup = new(src, "playersetup", "<div align='center'>New Player Options</div>", 250, 265)
|
|
popup.set_window_options("can_close=0")
|
|
popup.set_content(output)
|
|
popup.open(0)
|
|
return
|
|
|
|
|
|
/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, "<span class='danger'>The round is either not ready, or has already finished...</span>")
|
|
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, "<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["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(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(!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>")
|
|
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? 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, "<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.update_icon()
|
|
observer.stop_sound_channel(CHANNEL_LOBBYMUSIC)
|
|
QDEL_NULL(mind)
|
|
qdel(src)
|
|
return TRUE
|
|
|
|
/mob/dead/new_player/proc/IsJobAvailable(rank)
|
|
var/datum/job/job = SSjob.GetJob(rank)
|
|
if(!job)
|
|
return 0
|
|
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 1
|
|
for(var/datum/job/J in SSjob.occupations)
|
|
if(J && J.current_positions < J.total_positions && J.title != job.title)
|
|
return 0
|
|
else
|
|
return 0
|
|
if(jobban_isbanned(src,rank))
|
|
return 0
|
|
if(!job.player_old_enough(src.client))
|
|
return 0
|
|
if(job.required_playtime_remaining(client))
|
|
return 0
|
|
return 1
|
|
|
|
|
|
/mob/dead/new_player/proc/AttemptLateSpawn(rank)
|
|
if(!IsJobAvailable(rank))
|
|
alert(src, "[rank] is not available. Please try another.")
|
|
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
|
|
character.mind.quiet_round = character.client.prefs.toggles & QUIET_ROUND // yogs - Donor Features
|
|
var/equip = SSjob.EquipRank(character, rank, 1)
|
|
if(isliving(equip)) //Borgs get borged in the equip, so we need to make sure we handle the new mob.
|
|
character = equip
|
|
|
|
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, "<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
|
|
|
|
if(CONFIG_GET(flag/allow_latejoin_antagonists) && humanc && !character.mind.quiet_round) //Borgs aren't allowed to be antags. Will need to be tweaked if we get true latejoin ais. // yogs - Donor Features
|
|
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(CONFIG_GET(flag/roundstart_traits))
|
|
SStraits.AssignTraits(humanc, humanc.client, TRUE)
|
|
|
|
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/dat = "<div class='notice'>Round Duration: [DisplayTimeText(world.time - SSticker.round_start_time)]</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(job && IsJobAvailable(job.title))
|
|
available_job_count++;
|
|
|
|
|
|
for(var/datum/job/prioritized_job in SSjob.prioritized_jobs)
|
|
if(prioritized_job.current_positions >= prioritized_job.total_positions)
|
|
SSjob.prioritized_jobs -= prioritized_job
|
|
|
|
if(length(SSjob.prioritized_jobs))
|
|
dat += "<div class='notice red'>The station has flagged these jobs as high priority:<br>"
|
|
var/amt = length(SSjob.prioritized_jobs)
|
|
var/amt_count
|
|
for(var/datum/job/a in SSjob.prioritized_jobs)
|
|
amt_count++
|
|
if(amt_count != amt) // checks for the last job added.
|
|
dat += " [a.title], "
|
|
else
|
|
dat += " [a.title]. </div>"
|
|
|
|
dat += "<div class='clearBoth'>Choose from the following open positions:</div><br>"
|
|
dat += "<div class='jobs'><div class='jobsColumn'>"
|
|
var/job_count = 0
|
|
for(var/datum/job/job in SSjob.occupations)
|
|
if(job && IsJobAvailable(job.title))
|
|
job_count++;
|
|
if (job_count > round(available_job_count / 2))
|
|
dat += "</div><div class='jobsColumn'>"
|
|
var/position_class = "otherPosition"
|
|
if (job.title in GLOB.command_positions)
|
|
position_class = "commandPosition"
|
|
dat += "<a class='[position_class]' href='byond://?src=[REF(src)];SelectedJob=[job.title]'>[job.title] ([job.current_positions])</a><br>"
|
|
if(!job_count) //if there's nowhere to go, assistant opens up.
|
|
for(var/datum/job/job in SSjob.occupations)
|
|
if(job.title != "Assistant")
|
|
continue
|
|
dat += "<a class='otherPosition' href='byond://?src=[REF(src)];SelectedJob=[job.title]'>[job.title] ([job.current_positions])</a><br>"
|
|
break
|
|
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", 440, 500)
|
|
popup.add_stylesheet("playeroptions", 'html/browser/playeroptions.css')
|
|
popup.set_content(dat)
|
|
popup.open(0) // 0 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)
|
|
|
|
if(CONFIG_GET(flag/force_random_names) || jobban_isbanned(src, "appearance"))
|
|
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 = "<html><body>"
|
|
dat += "<h4>Crew Manifest</h4>"
|
|
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
|