mob/new_player anchored = 1 var/ready = 0 var/spawning = 0 var/keyd var/adminspawned = 0 invisibility = 101 density = 0 stat = 2 canmove = 0 anchored = 1 // don't get pushed around // How could this even happen? Regardless, no log entries for unaffected mobs (Convair880). ex_act(severity) return disposing() mobs.Remove(src) if (mind) if (mind.current == src) mind.current = null mind = null key = null ..() Login() ..() if(!mind) mind = new(src) keyd = mind.key // moved the below to /client/New() so mentor-related preference loading works properly /*if ((NT.Find(ckey(mind.key)) || mentors.Find(ckey(mind.key))) && !admins.Find(ckey(mind.key))) client.mentor = 1 client.mentor_authed = 1*/ new_player_panel() var/starting_loc if (newplayer_start.len > 0) starting_loc = pick(newplayer_start) else starting_loc = locate(1,1,1) src.set_loc(starting_loc) src.sight |= SEE_TURFS var/list/watch_locations = list() for(var/obj/landmark/landmark in world) if(landmark.tag == "landmark*new_player") watch_locations += landmark.loc if(watch_locations.len>0) loc = pick(watch_locations) if (src.ckey && !adminspawned) if (spawned_in_keys.Find("[src.ckey]")) if (!(client && client.holder) && !abandon_allowed) //They have already been alive this round!! var/mob/dead/observer/observer = new() src.spawning = 1 close_spawn_windows() boutput(src, "Now teleporting.") var/ASLoc = pick(observer_start) if (ASLoc) observer.set_loc(ASLoc) else observer.set_loc(locate(1, 1, 1)) observer.key = key if(client.preferences.be_random_name) client.preferences.randomize_name() observer.name = client.preferences.real_name observer.real_name = observer.name qdel(src) else spawned_in_keys += "[src.ckey]" Logout() ready = 0 if (src.ckey) //Null if the client changed to another mob, but not null if they disconnected. spawned_in_keys -= "[src.ckey]" ..() close_spawn_windows() if(!spawning) qdel(src) return verb/new_player_panel() set src = usr if(client) winset(src, "joinmenu.button_charsetup", "is-disabled=false") // drsingh i put the extra ifs here. i think its dumb but there's a bad client error here so maybe it's somehow going away in winset because byond is shitty if(client) winset(src, "joinmenu.button_ready", "is-disabled=false;is-visible=true") if(client) winset(src, "joinmenu.button_cancel", "is-disabled=true;is-visible=false") if(client) winshow(src, "joinmenu", 1) /* var/output = "
New Player Options
" output += "

Setup Character

" if(!ticker || ticker.current_state <= GAME_STATE_PREGAME) if(!ready) output += "Declare Ready
" else output += "You are ready.
" else output += "Join Game!
" output += "
Observe
" src << browse(output,"window=playersetup;size=250x200;can_close=0") */ Stat() ..() statpanel("Lobby") if(client.statpanel=="Lobby" && ticker) if(ticker.current_state == GAME_STATE_PREGAME) for(var/mob/new_player/player in mobs) if (player.client && player.client.holder && (player.client.stealth || player.client.alt_key)) // are they an admin and in stealth mode/have a fake key? if (client.holder) // are we an admin? stat("[player.key] (as [player.client.fakekey])", (player.ready)?("(Playing)"):(null)) // give us the full deets else // are we not an admin? stat("[player.client.fakekey]", (player.ready)?("(Playing)"):(null)) // only show the fake key else // are they a normal player or not in stealth mode/using a fake key? stat("[player.key]", (player.ready)?("(Playing)"):(null)) // show them normally Topic(href, href_list[]) if(href_list["show_preferences"]) client.preferences.ShowChoices(src) return 1 if(href_list["ready"]) if(!ready) if(alert(src,"Are you sure you are ready? This will lock-in your preferences.","Player Setup","Yes","No") == "Yes") ready = 1 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") var/mob/dead/observer/observer = new() src.spawning = 1 close_spawn_windows() boutput(src, "Now teleporting.") var/ASLoc = observer_start.len ? pick(observer_start) : locate(1, 1, 1) if (ASLoc) observer.set_loc(ASLoc) else observer.set_loc(locate(1, 1, 1)) observer.apply_looks_of(client) if(src.mind) src.mind.dnr = 1 src.mind.transfer_to(observer) else src.mind = new /datum/mind() src.mind.dnr = 1 src.mind.transfer_to(observer) if(client.preferences.be_random_name) client.preferences.randomize_name() observer.name = client.preferences.real_name observer.real_name = observer.name src.client.loadResources() qdel(src) if(href_list["late_join"]) LateChoices() if(href_list["SelectedJob"]) if (src.spawning) return if (!enter_allowed) boutput(usr, "There is an administrative lock on entering the game!") return if (ticker.mode && !istype(ticker.mode, /datum/game_mode/construction)) var/list/alljobs = job_controls.staple_jobs | job_controls.special_jobs var/datum/job/JOB = locate(href_list["SelectedJob"]) in alljobs AttemptLateSpawn(JOB) else var/datum/game_mode/construction/C = ticker.mode var/datum/job/JOB = locate(href_list["SelectedJob"]) in C.enabled_jobs AttemptLateSpawn(JOB) if(href_list["preferences"]) if (!ready) client.preferences.process_link(src, href_list) else if(!href_list["late_join"]) new_player_panel() proc/IsJobAvailable(var/datum/job/JOB) if(!ticker || !ticker.mode) return 0 if (!JOB || !istype(JOB,/datum/job/) || JOB.limit == 0) return 0 if((ticker && ticker.mode && istype(ticker.mode, /datum/game_mode/revolution)) && istype(JOB,/datum/job/command/)) return 0 if (!JOB.no_jobban_from_this_job && jobban_isbanned(src,JOB.name)) return 0 if (JOB.requires_whitelist) if (!NT.Find(src.ckey)) return 0 if (JOB.limit < 0 || countJob(JOB.name) < JOB.limit) return 1 return 0 proc/AttemptLateSpawn(var/datum/job/JOB) if (!JOB) return if (JOB && IsJobAvailable(JOB)) var/mob/character = create_character(JOB, JOB.allow_traitors) if (isnull(character)) return if (ticker.current_state == GAME_STATE_PLAYING) //for (var/mob/living/silicon/ai/A in mobs) if (map_setting != "DESTINY") for (var/obj/machinery/computer/announcement/A in machines) if (!A.stat && A.announces_arrivals) A.announce_arrival("[character.real_name]","[JOB.name]") #ifdef MAP_OVERRIDE_DESTINY var/obj/cryotron/starting_loc = null if (ishuman(character) && rp_latejoin && rp_latejoin.len) starting_loc = pick(rp_latejoin) if (istype(starting_loc)) starting_loc.add_person_to_queue(character) else starting_loc = latejoin.len ? pick(latejoin) : locate(1, 1, 1) character.set_loc(starting_loc) #else var/starting_loc = null starting_loc = latejoin.len ? pick(latejoin) : locate(1, 1, 1) character.set_loc(starting_loc) #endif if (ishuman(character)) var/mob/living/carbon/human/HC = character HC.Equip_Rank(JOB.name, joined_late=1) var/miscreant = 0 #ifdef MISCREANTS if (ticker && character.mind && JOB.allow_traitors != 0 && prob(10)) if (map_setting != "DESTINY") // miscreants are causing issue in the rp setting atm ticker.generate_miscreant_objectives(character.mind) miscreant = 1 #endif #ifdef CREW_OBJECTIVES if (ticker && character.mind && !miscreant) ticker.generate_individual_objectives(character.mind) #endif if (manualbreathing) boutput(character, "You must breathe manually using the *inhale and *exhale commands!") if (manualblinking) boutput(character, "You must blink manually using the *closeeyes and *openeyes commands!") if (ticker && character.mind) //ticker.implant_skull_key() // This also checks if a key has been implanted already or not. If not then it'll implant a random sucker with a key. if (!(character.mind in ticker.minds)) logTheThing("debug", character, null, "Late join: added player to ticker.minds.") ticker.minds += character.mind logTheThing("debug", character, null, "Late join: assigned job: [JOB.name]") spawn (0) qdel(src) else src << alert("[JOB.name] is not available. Please try another.") return // This fxn creates positions for assistants based on existing positions. This could be more elgant. proc/LateChoices() var/dat = "Select a Job" dat += "Which job would you like?
" dat += "" if (ticker.mode && !istype(ticker.mode, /datum/game_mode/construction)) dat += "" dat += "" dat += "" dat += "" dat += "" if (job_controls.allow_special_jobs) dat += "" dat += "" dat += {"" dat += {"" dat += {"" dat += {"" if (job_controls.allow_special_jobs) dat += {"" dat += "" else var/datum/game_mode/construction/C = ticker.mode if (!C.enabled_jobs.len) var/datum/job/engineering/construction_worker/D = new /datum/job/engineering/construction_worker() D.limit = -1 C.enabled_jobs += D for (var/datum/job/J in C.enabled_jobs) if (IsJobAvailable(J) && !J.no_late_join) dat += "" dat += "
Command/Security
Research
Engineering
Civilian
Special Jobs
"} for(var/datum/job/command/J in job_controls.staple_jobs) if (IsJobAvailable(J) && !J.no_late_join) dat += {"[J.name]
"} for(var/datum/job/security/J in job_controls.staple_jobs) if (IsJobAvailable(J) && !J.no_late_join) dat += {"[J.name]
"} dat += "
"} for(var/datum/job/research/J in job_controls.staple_jobs) if (IsJobAvailable(J) && !J.no_late_join) dat += {"[J.name]
"} dat += "
"} for(var/datum/job/engineering/J in job_controls.staple_jobs) if (IsJobAvailable(J) && !J.no_late_join) dat += {"[J.name]
"} dat += "
"} for(var/datum/job/civilian/J in job_controls.staple_jobs) if (IsJobAvailable(J) && !J.no_late_join) dat += {"[J.name]
"} for(var/datum/job/daily/J in job_controls.staple_jobs) if (IsJobAvailable(J) && !J.no_late_join) dat += {"[J.name]
"} dat += "
"} for(var/datum/job/special/J in job_controls.special_jobs) if (IsJobAvailable(J) && !J.no_late_join) dat += {"[J.name]
"} for(var/datum/job/created/J in job_controls.special_jobs) if (IsJobAvailable(J) && !J.no_late_join) dat += {"[J.name]
"} dat += "
" dat += {"[J.name]
"} dat += "
" src << browse(dat, "window=latechoices;size=500x400;can_close=0") proc/create_character(var/datum/job/J, var/allow_late_antagonist = 0) if (!src || !src.mind || !src.client) return null if (!J) J = find_job_in_controller_by_string(src.mind.assigned_role) src.spawning = 1 if(latejoin.len == 0) boutput(world, "No latejoin landmarks placed, dumping [src] to (1,1,1)") src.set_loc(locate(1,1,1)) else src.set_loc(pick(latejoin)) var/mob/new_character = null if (J) new_character = new J.mob_type(src.loc) else new_character = new /mob/living/carbon/human(src.loc) // fallback close_spawn_windows() client.preferences.copy_to(new_character,src) var/client/C = client mind.transfer_to(new_character) if (ishuman(new_character) && allow_late_antagonist && ticker.current_state == GAME_STATE_PLAYING && ticker.round_elapsed_ticks >= 6000 && emergency_shuttle.timeleft() >= 300 && !C.hellbanned) // no new evils for the first 10 minutes or last 5 before shuttle if (late_traitors && ticker.mode && ticker.mode.latejoin_antag_compatible == 1) var/livingtraitor = 0 for(var/datum/mind/brain in ticker.minds) if(brain.current && checktraitor(brain.current)) // if a traitor if (issilicon(brain.current) || brain.current.stat & 2 || brain.current.client == null) // if a silicon mob, dead or logged out, skip continue livingtraitor = 1 logTheThing("debug", null, null, "Late join: checking [new_character.ckey], found livingtraitor [brain.key].") break if ((!livingtraitor && prob(40)) || (livingtraitor && ticker.mode.latejoin_only_if_all_antags_dead == 0 && prob(4))) var/bad_type = null if (islist(ticker.mode.latejoin_antag_roles) && ticker.mode.latejoin_antag_roles.len) bad_type = pick(ticker.mode.latejoin_antag_roles) else bad_type = "traitor" makebad(new_character, bad_type) new_character.mind.late_special_role = 1 logTheThing("debug", new_character, null, "Late join: assigned antagonist role.") if(new_character && new_character.client) new_character.client.loadResources() new_character.temporary_attack_alert(1200) //Messages admins if this new character attacks someone within 2 minutes of signing up. Might help detect grief, who knows? return new_character Move() return 1 // do not return 0 in here for the love of god, let me tell you the tale of why: // the default mob/Login (which got called before we actually set our loc onto the start screen), will attempt to put the mob at (1, 1, 1) if the loc is null // however, the documentation actually says "near" (1, 1, 1), and will count Move returning 0 as that it cannot be placed there // by "near" it means anywhere on the goddamn map where Move will return 1, this meant that anyone logging in would cause the server to // grind itself to a slow death in a caciphony of endless Move calls proc/makebad(var/mob/living/carbon/human/traitormob, type) if (!traitormob || !ismob(traitormob) || !traitormob.mind) return var/datum/mind/traitor = traitormob.mind ticker.mode.traitors += traitor var/objective_set_path = null switch (type) if ("traitor") traitor.special_role = "traitor" var/role = traitor.assigned_role if(role in list("Captain","Head of Personnel","Head of Security","Chief Engineer","Research Director")) objective_set_path = pick(typesof(/datum/objective_set/traitor/hard)) else objective_set_path = pick(typesof(/datum/objective_set/traitor/easy)) if ("changeling") traitor.special_role = "changeling" objective_set_path = /datum/objective_set/changeling traitormob.make_changeling() if ("vampire") traitor.special_role = "vampire" objective_set_path = /datum/objective_set/vampire traitormob.make_vampire() if ("wrestler") traitor.special_role = "wrestler" objective_set_path = pick(typesof(/datum/objective_set/traitor/easy)) traitormob.make_wrestler(1) if ("grinch") traitor.special_role = "grinch" objective_set_path = /datum/objective_set/grinch traitormob.make_grinch() if ("predator") traitor.special_role = "predator" objective_set_path = /datum/objective_set/predator traitormob.make_predator() if ("werewolf") traitor.special_role = "werewolf" objective_set_path = /datum/objective_set/werewolf traitormob.make_werewolf() if ("wraith") traitor.special_role = "wraith" traitormob.make_wraith() generate_wraith_objectives(traitor) else // Fallback if role is unrecognized. traitor.special_role = "traitor" var/role = traitor.assigned_role if(role in list("Captain","Head of Personnel","Head of Security","Chief Engineer","Research Director")) objective_set_path = pick(typesof(/datum/objective_set/traitor/hard)) else objective_set_path = pick(typesof(/datum/objective_set/traitor/easy)) if (!isnull(objective_set_path)) if (ispath(objective_set_path, /datum/objective_set)) new objective_set_path(traitor) else if (ispath(objective_set_path, /datum/objective)) ticker.mode.bestow_objective(traitor, objective_set_path) var/obj_count = 1 for(var/datum/objective/objective in traitor.objectives) #ifdef CREW_OBJECTIVES if (istype(objective, /datum/objective/crew) || istype(objective, /datum/objective/miscreant)) continue #endif boutput(traitor.current, "Objective #[obj_count]: [objective.explanation_text]") obj_count++ proc/close_spawn_windows() if(client) src << browse(null, "window=latechoices") //closes late choices window src << browse(null, "window=playersetup") //closes the player setup window winshow(src, "joinmenu", 0) winshow(src, "playerprefs", 0) verb/show_preferences() set hidden = 1 set name = ".show_preferences" client.preferences.ShowChoices(src) verb/declare_ready() set hidden = 1 set name = ".ready" if (ticker) if (ticker.mode) if (istype(ticker.mode, /datum/game_mode/construction)) var/datum/game_mode/construction/C = ticker.mode if (C.in_setup) boutput(usr, "The round is currently being set up. Please wait.") return if(!ticker || ticker.current_state <= GAME_STATE_PREGAME) if(!ready) ready = 1 if (usr.client) winset(src, "joinmenu.button_charsetup", "is-disabled=true") if (usr.client) winset(src, "joinmenu.button_ready", "is-disabled=true;is-visible=false") if (usr.client) winset(src, "joinmenu.button_cancel", "is-disabled=false;is-visible=true") usr << browse(null, "window=mob_occupation") if(master_mode in list("secret","traitor","nuclear","blob","wizard","changeling","mixed")) if (src.client.antag_tokens > 0) //If the player has any antag tokens available, check if they want to redeem one. if(alert(src,"Would you like to use an Antagonist Token for this round? (Modes that do not support redemption will not alter token balance.)","Remaining Tokens: [src.client.antag_tokens]","Yes","No") == "Yes") src.client.using_antag_token = 1 src.show_text("Token redeemed, if mode supports redemption your new total will be [src.client.antag_tokens - 1].", "red") else if (src.client.antag_tokens > 0) //If the player has any antag tokens available, check if they want to redeem one. if(alert(src,"Would you like to use an Antagonist Token for this round? (Modes that do not support redemption will not alter token balance.)","Remaining Tokens: [src.client.antag_tokens]","Yes","No") == "Yes") src.show_text("Token redeemed, if mode supports redemption your new total will be [src.client.antag_tokens - 1].", "red") src.client.loadResources() else LateChoices() verb/cancel_ready() set hidden = 1 set name = ".cancel_ready" if (ticker) if (ticker.mode) if (istype(ticker.mode, /datum/game_mode/construction)) var/datum/game_mode/construction/C = ticker.mode if (C.in_setup) boutput(usr, "You are already spawning, and cannot unready. Please wait until setup finishes.") return if(ready) ready = 0 winset(src, "joinmenu.button_charsetup", "is-disabled=false") winset(src, "joinmenu.button_ready", "is-disabled=false;is-visible=true") winset(src, "joinmenu.button_cancel", "is-disabled=true;is-visible=false") if (src.client.using_antag_token) src.client.using_antag_token = 0 src.show_text("Token cancelled", "red") verb/observe_round() set hidden = 1 set name = ".observe_round" if(alert(src,"Are you sure you wish to observe? You will not be able to play this round!","Player Setup","Yes","No") == "Yes") var/mob/dead/observer/observer = new() if (src.client.using_antag_token) src.client.using_antag_token = 0 src.show_text("Token refunded, your new total is [src.client.antag_tokens].", "red") src.spawning = 1 close_spawn_windows() boutput(src, "Now teleporting.") var/ASLoc = observer_start.len ? pick(observer_start) : locate(1, 1, 1) if (ASLoc) observer.set_loc(ASLoc) observer.apply_looks_of(client) observer.observe_round = 1 if(client.preferences && client.preferences.be_random_name) //Wire: fix for Cannot read null.be_random_name (preferences &&) client.preferences.randomize_name() observer.name = client.preferences.real_name if(!src.mind) src.mind = new(src) src.mind.dnr=1 src.mind.transfer_to(observer) observer.real_name = observer.name if(observer && observer.client) observer.client.loadResources() qdel(src)