Files
Bubberstation/code/modules/mob/new_player/new_player.dm
Cyberboss e03144dc1d Smoother roundstart take II (#24504)
* Revert "Until I figure out why random keys aren't being transferred"

* Fixes cyborgs not getting their key at roundstart

* Fixes mimes not getting the prefs name

* Fixes clowns not getting prefs names

* Sets the round start timer when it actually starts

* Remove fluff CHECK_TICKs

* Moves siliconization to the jobs module

* Yeah whatever

* Fixes AIization

* HNNNNGHHHH WHY IS THIS UP HERE?

* Fix cyborgs not linking to AI
2017-03-07 21:06:33 +01:00

476 lines
17 KiB
Plaintext

/mob/new_player
var/ready = 0
var/spawning = 0//Referenced when you want to delete the new_player later on in the code.
flags = NONE
invisibility = INVISIBILITY_ABSTRACT
density = 0
stat = DEAD
canmove = 0
anchored = 1 // don't get pushed around
var/mob/living/new_character //for instant transfer once the round is set up
/mob/new_player/New()
tag = "mob_[next_mob_id++]"
mob_list += src
if(client && ticker.state == GAME_STATE_STARTUP)
var/obj/screen/splash/S = new(client, TRUE, TRUE)
S.Fade(TRUE)
if(length(newplayer_start))
loc = pick(newplayer_start)
else
loc = locate(1,1,1)
/mob/new_player/proc/new_player_panel()
var/output = "<center><p><a href='byond://?src=\ref[src];show_preferences=1'>Setup Character</A></p>"
if(!ticker || ticker.current_state <= GAME_STATE_PREGAME)
if(ready)
output += "<p>\[ <b>Ready</b> | <a href='byond://?src=\ref[src];ready=0'>Not Ready</a> \]</p>"
else
output += "<p>\[ <a href='byond://?src=\ref[src];ready=1'>Ready</a> | <b>Not Ready</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><a href='byond://?src=\ref[src];observe=1'>Observe</A></p>"
if(!IsGuestKey(src.key))
if (dbcon.Connect())
var/isadmin = 0
if(src.client && src.client.holder)
isadmin = 1
var/DBQuery/query_get_new_polls = dbcon.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())
return
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>", 220, 265)
popup.set_window_options("can_close=0")
popup.set_content(output)
popup.open(0)
return
/mob/new_player/Stat()
..()
if(statpanel("Lobby"))
stat("Game Mode:", (ticker.hide_mode) ? "Secret" : "[master_mode]")
stat("Map:", SSmapping.config.map_name)
if(ticker.current_state == GAME_STATE_PREGAME)
var/time_remaining = ticker.GetTimeLeft()
if(time_remaining >= 0)
time_remaining /= 10
stat("Time To Start:", (time_remaining >= 0) ? "[round(time_remaining)]s" : "DELAYED")
stat("Players:", "[ticker.totalPlayers]")
if(client.holder)
stat("Players Ready:", "[ticker.totalPlayersReady]")
/mob/new_player/Topic(href, href_list[])
if(src != usr)
return 0
if(!client)
return 0
//Determines Relevent Population Cap
var/relevant_cap
if(config.hard_popcap && config.extreme_popcap)
relevant_cap = min(config.hard_popcap, config.extreme_popcap)
else
relevant_cap = max(config.hard_popcap, config.extreme_popcap)
if(href_list["show_preferences"])
client.prefs.ShowChoices(src)
return 1
if(href_list["ready"])
if(!ticker || ticker.current_state <= GAME_STATE_PREGAME) // Make sure we don't ready up after the round has started
ready = text2num(href_list["ready"])
if(href_list["refresh"])
src << browse(null, "window=playersetup") //closes the player setup window
new_player_panel()
if(href_list["observe"])
if(alert(src,"Are you sure you wish to observe? You will not be able to play this round!","Player Setup","Yes","No") == "Yes")
if(!client)
return 1
var/mob/dead/observer/observer = new()
spawning = 1
observer.started_as_observer = 1
close_spawn_windows()
var/obj/O = locate("landmark*Observer-Start")
src << "<span class='notice'>Now teleporting.</span>"
if (O)
observer.loc = O.loc
else
src << "<span class='notice'>Teleporting failed. The map is probably still loading...</span>"
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.stopLobbySound()
qdel(mind)
qdel(src)
return 1
if(href_list["late_join"])
if(!ticker || ticker.current_state != GAME_STATE_PLAYING)
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(ticker.queued_players.len || (relevant_cap && living_player_count() >= relevant_cap && !(ckey(key) in admin_datums)))
usr << "<span class='danger'>[config.hard_popcap_message]</span>"
var/queue_position = ticker.queued_players.Find(usr)
if(queue_position == 1)
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)
usr << "<span class='notice'>There are [queue_position-1] players in front of you in the queue to join the game.</span>"
else
ticker.queued_players += usr
usr << "<span class='notice'>You have been added to the queue to join the game. Your position in queue is [ticker.queued_players.len].</span>"
return
LateChoices()
if(href_list["manifest"])
ViewManifest()
if(href_list["SelectedJob"])
if(!enter_allowed)
usr << "<span class='notice'>There is an administrative lock on entering the game!</span>"
return
if(ticker.queued_players.len && !(ckey(key) in admin_datums))
if((living_player_count() >= relevant_cap) || (src != ticker.queued_players[1]))
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))
usr << "<span class='notice'>Vote successful.</span>"
else
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))
usr << "<span class='notice'>Feedback logging successful.</span>"
else
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)
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))
usr << "<span class='danger'>Vote failed, please try again or contact an administrator.</span>"
return
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
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)
usr << "<span class='danger'>Vote failed, please try again or contact an administrator.</span>"
return
if(2)
usr << "<span class='danger'>Maximum replies reached.</span>"
break
usr << "<span class='notice'>Vote successful.</span>"
if(POLLTYPE_IRV)
if (!href_list["IRVdata"])
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))
src << "<span class='danger'>Vote failed, please try again or contact an administrator.</span>"
return
src << "<span class='notice'>Vote successful.</span>"
/mob/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(config.enforce_human_authority && !client.prefs.pref_species.qualifies_for_rank(rank, client.prefs.features))
return 0
return 1
/mob/new_player/proc/AttemptLateSpawn(rank)
if(!IsJobAvailable(rank))
src << alert("[rank] is not available. Please try another.")
return 0
//Remove the player from the join queue if he was in one and reset the timer
ticker.queued_players -= src
ticker.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, 1)
if(isliving(equip)) //Borgs get borged in the equip, so we need to make sure we handle the new mob.
character = equip
var/D = pick(latejoin)
if(!D)
for(var/turf/T in get_area_turfs(/area/shuttle/arrival))
if(!T.density)
var/clear = 1
for(var/obj/O in T)
if(O.density)
clear = 0
break
if(clear)
D = T
continue
character.loc = D
ticker.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
data_core.manifest_inject(humanc)
AnnounceArrival(humanc, rank)
AddEmploymentContract(humanc)
if(highlander)
humanc << "<span class='userdanger'><i>THERE CAN BE ONLY ONE!!!</i></span>"
humanc.make_scottish()
joined_player_list += character.ckey
if(config.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)
ticker.mode.make_antag_chance(humanc)
if(SHUTTLE_CALL)
if(SSshuttle.emergency.timeLeft(1) > initial(SSshuttle.emergencyCallTime)*0.5)
ticker.mode.make_antag_chance(humanc)
qdel(src)
/mob/new_player/proc/AnnounceArrival(var/mob/living/carbon/human/character, var/rank)
if(ticker.current_state != GAME_STATE_PLAYING)
return
var/area/A = get_area(character)
var/message = "<span class='game deadsay'><span class='name'>\
[character.real_name]</span> ([rank]) has arrived at the station at \
<span class='name'>[A.name]</span>.</span>"
deadchat_broadcast(message, follow_target = character, message_type=DEADCHAT_ARRIVALRATTLE)
if((!announcement_systems.len) || (!character.mind))
return
if((character.mind.assigned_role == "Cyborg") || (character.mind.assigned_role == character.mind.special_role))
return
var/obj/machinery/announcement_system/announcer = pick(announcement_systems)
announcer.announce("ARRIVAL", character.real_name, rank, list()) //make the list empty to make it announce it in common
/mob/new_player/proc/AddEmploymentContract(mob/living/carbon/human/employee)
//TODO: figure out a way to exclude wizards/nukeops/demons from this.
sleep(30)
for(var/C in employmentCabinets)
var/obj/structure/filingcabinet/employment/employmentCabinet = C
if(!employmentCabinet.virgin)
employmentCabinet.addFile(employee)
/mob/new_player/proc/LateChoices()
var/mills = world.time - round_start_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 = "<div class='notice'>Round Duration: [round(hours)]h [round(mins)]m</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++;
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 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/new_player/proc/create_character(transfer_after)
spawning = 1
close_spawn_windows()
var/mob/living/carbon/human/H = new(loc)
if(config.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)
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/new_player/proc/transfer_character()
. = new_character
if(.)
new_character.key = key //Manually transfer the key to log them in
new_character.stopLobbySound()
/mob/new_player/proc/ViewManifest()
var/dat = "<html><body>"
dat += "<h4>Crew Manifest</h4>"
dat += data_core.get_manifest(OOC = 1)
src << browse(dat, "window=manifest;size=387x420;can_close=1")
/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