diff --git a/_maps/_basemap.dm b/_maps/_basemap.dm index 4192461a4c6..de57328405c 100644 --- a/_maps/_basemap.dm +++ b/_maps/_basemap.dm @@ -7,7 +7,6 @@ #ifndef LOWMEMORYMODE #ifdef ALL_MAPS #include "map_files\Mining\Lavaland.dmm" - #include "skyrat\planets\rockplanet.dmm" #include "map_files\debug\runtimestation.dmm" #include "map_files\debug\multiz.dmm" #include "map_files\Deltastation\DeltaStation2.dmm" diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 8c0f5b9703d..7275c7b647f 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -673,6 +673,7 @@ plane = SPLASHSCREEN_PLANE var/client/holder +/* SKYRAT EDIT REMOVAL /atom/movable/screen/splash/New(client/C, visible, use_previous_title) //TODO: Make this use INITIALIZE_IMMEDIATE, except its not easy . = ..() @@ -691,6 +692,7 @@ icon = SStitle.previous_icon holder.screen += src +*/ /atom/movable/screen/splash/proc/Fade(out, qdel_after = TRUE) if(QDELETED(src)) diff --git a/code/controllers/master.dm b/code/controllers/master.dm index 8f24bdb3de6..abdac644e0c 100644 --- a/code/controllers/master.dm +++ b/code/controllers/master.dm @@ -185,7 +185,8 @@ GLOBAL_REAL(Master, /datum/controller/master) = new if(init_sss) init_subtypes(/datum/controller/subsystem, subsystems) - to_chat(world, "Initializing subsystems...") + //to_chat(world, "Initializing subsystems...") + add_startupmessage("Initializing subsystems...") //SKYRAT EDIT CHANGE // Sort subsystems by init_order, so they initialize in the correct order. sortTim(subsystems, /proc/cmp_subsystem_init) @@ -226,6 +227,7 @@ GLOBAL_REAL(Master, /datum/controller/master) = new initializations_finished_with_no_players_logged_in = initialized_tod < REALTIMEOFDAY - 10 // Loop. Master.StartProcessing(0) + add_startupmessage("Clearing clutter...") //SKYRAT EDIT ADDITION /datum/controller/master/proc/SetRunLevel(new_runlevel) var/old_runlevel = current_runlevel diff --git a/code/controllers/subsystem.dm b/code/controllers/subsystem.dm index 091d495d3c4..52ad29ef94c 100644 --- a/code/controllers/subsystem.dm +++ b/code/controllers/subsystem.dm @@ -217,7 +217,8 @@ SEND_SIGNAL(src, COMSIG_SUBSYSTEM_POST_INITIALIZE, start_timeofday) var/time = (REALTIMEOFDAY - start_timeofday) / 10 var/msg = "Initialized [name] subsystem within [time] second[time == 1 ? "" : "s"]!" - to_chat(world, "[msg]") + //to_chat(world, "[msg]") + add_startupmessage(msg) //SKYRAT EDIT CHANGE log_world(msg) return time diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm index 8836ce36f5b..102c76bc91f 100644 --- a/code/controllers/subsystem/job.dm +++ b/code/controllers/subsystem/job.dm @@ -683,6 +683,7 @@ SUBSYSTEM_DEF(job) to_chat(player, "You have failed to qualify for any job you desired.") unassigned -= player player.ready = PLAYER_NOT_READY + player.client << output(player.ready, "lobbybrowser:imgsrc") //SKYRAT EDIT ADDITION /datum/controller/subsystem/job/Recover() diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm index b818e211632..d7d7b75cfe6 100644 --- a/code/controllers/subsystem/mapping.dm +++ b/code/controllers/subsystem/mapping.dm @@ -246,7 +246,8 @@ Used by the AI doomsday and the self-destruct nuke. if (!pm.load(1, 1, start_z + parsed_maps[P], no_changeturf = TRUE)) errorList |= pm.original_path if(!silent) - INIT_ANNOUNCE("Loaded [name] in [(REALTIMEOFDAY - start_time)/10]s!") + //INIT_ANNOUNCE("Loaded [name] in [(REALTIMEOFDAY - start_time)/10]s!") + add_startupmessage("Loaded [name] in [(REALTIMEOFDAY - start_time)/10]s!") //SKYRAT EDIT CHANGE return parsed_maps /datum/controller/subsystem/mapping/proc/loadWorld() @@ -258,7 +259,8 @@ Used by the AI doomsday and the self-destruct nuke. // load the station station_start = world.maxz + 1 - INIT_ANNOUNCE("Loading [config.map_name]...") + //INIT_ANNOUNCE("Loading [config.map_name]...") SKYRAT EDIT REMOVAL + add_startupmessage("Loading [config.map_name]...") LoadGroup(FailedZs, "Station", config.map_path, config.map_file, config.traits, ZTRAITS_STATION) if(SSdbcore.Connect()) @@ -274,8 +276,6 @@ Used by the AI doomsday and the self-destruct nuke. ++space_levels_so_far add_new_zlevel("Empty Area [space_levels_so_far]", ZTRAITS_SPACE) - LoadGroup(FailedZs, "Rockplanet", "skyrat/planets", "rockplanet.dmm", default_traits = ZTRAITS_ROCKPLANET) - if(config.minetype == "lavaland") LoadGroup(FailedZs, "Lavaland", "map_files/Mining", "Lavaland.dmm", default_traits = ZTRAITS_LAVALAND) else if (!isnull(config.minetype) && config.minetype != "none") diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 37dfd9fcbed..7556e3108f4 100755 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -161,6 +161,7 @@ SUBSYSTEM_DEF(ticker) to_chat(world, "Welcome to [station_name()]!") send2chat("<@&[CONFIG_GET(string/game_alert_role_id)]> New round starting on [SSmapping.config.map_name], [CONFIG_GET(string/servername)]! \nIf you wish to be pinged for game related stuff, go to <#[CONFIG_GET(string/role_assign_channel_id)]> and assign yourself the roles.", CONFIG_GET(string/chat_announce_new_game)) // Skyrat EDIT -- role ping current_state = GAME_STATE_PREGAME + change_lobbyscreen() //SKYRAT EDIT ADDITION //Everyone who wants to be an observer is now spawned create_observers() fire() @@ -380,7 +381,7 @@ SUBSYSTEM_DEF(ticker) GLOB.joined_player_list += player.ckey player.create_character(FALSE) else - player.new_player_panel() + player.show_titlescreen() CHECK_TICK /datum/controller/subsystem/ticker/proc/collect_minds() diff --git a/code/controllers/subsystem/title.dm b/code/controllers/subsystem/title.dm index ce5d1d4dde2..daaa754cd0f 100644 --- a/code/controllers/subsystem/title.dm +++ b/code/controllers/subsystem/title.dm @@ -1,3 +1,4 @@ +/* SKYRAT EDIT REMOVAL - MOVED TO MODULAR SUBSYSTEM_DEF(title) name = "Title Screen" flags = SS_NO_FIRE @@ -67,3 +68,4 @@ SUBSYSTEM_DEF(title) splash_turf = SStitle.splash_turf file_path = SStitle.file_path previous_icon = SStitle.previous_icon +*/ diff --git a/code/datums/mapgen/CaveGenerator.dm b/code/datums/mapgen/CaveGenerator.dm index 64c13410c0a..6e2a909c7aa 100644 --- a/code/datums/mapgen/CaveGenerator.dm +++ b/code/datums/mapgen/CaveGenerator.dm @@ -140,5 +140,6 @@ CHECK_TICK var/message = "[name] finished in [(REALTIMEOFDAY - start_time)/10]s!" - to_chat(world, "[message]") + //to_chat(world, "[message]") + add_startupmessage(message) //SKYRAT EDIT CHANGE log_world(message) diff --git a/code/game/turfs/closed/_closed.dm b/code/game/turfs/closed/_closed.dm index 567c20a28f7..99ed3284c89 100644 --- a/code/game/turfs/closed/_closed.dm +++ b/code/game/turfs/closed/_closed.dm @@ -60,6 +60,7 @@ plane = SPLASHSCREEN_PLANE bullet_bounce_sound = null +/* SKYRAT EDIT REMOVAL /turf/closed/indestructible/splashscreen/New() SStitle.splash_turf = src if(SStitle.icon) @@ -72,7 +73,7 @@ switch(var_name) if(NAMEOF(src, icon)) SStitle.icon = icon - +*/ /turf/closed/indestructible/reinforced name = "reinforced wall" diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index aa9480c1ce4..fbae3ed8fdd 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -92,6 +92,7 @@ GLOBAL_PROTECT(admin_verbs_ban) GLOBAL_LIST_INIT(admin_verbs_sounds, list(/client/proc/play_local_sound, /client/proc/play_direct_mob_sound, /client/proc/play_sound, /client/proc/set_round_end_sound)) GLOBAL_PROTECT(admin_verbs_sounds) GLOBAL_LIST_INIT(admin_verbs_fun, list( + /client/proc/change_title_screen, //SKYRAT EDIT ADDITION /client/proc/cmd_select_equipment, /client/proc/cmd_admin_gib_self, /client/proc/drop_bomb, diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index ca39b0ada1a..bbb8ba86613 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -2,7 +2,7 @@ //SECURITY// //////////// #define UPLOAD_LIMIT 524288 //Restricts client uploads to the server to 0.5MB -#define UPLOAD_LIMIT_ADMIN 2621440 //Restricts admin client uploads to the server to 2.5MB +#define UPLOAD_LIMIT_ADMIN 5550000 //Restricts admin client uploads to the server to 2.5MB //SKYRAT EDIT CHANGE - CHANGED TO 5.55 MB GLOBAL_LIST_INIT(blacklisted_builds, list( "1407" = "bug preventing client display overrides from working leads to clients being able to see things/mobs they shouldn't be able to see", diff --git a/code/modules/mob/dead/new_player/login.dm b/code/modules/mob/dead/new_player/login.dm index 19aa1525057..b18361e769b 100644 --- a/code/modules/mob/dead/new_player/login.dm +++ b/code/modules/mob/dead/new_player/login.dm @@ -8,7 +8,7 @@ mind = new /datum/mind(key) mind.active = TRUE mind.current = src - + my_client = client //SKYRAT EDIT ADDITION . = ..() if(!. || !client) return FALSE @@ -37,7 +37,7 @@ register_for_interview() return - new_player_panel() + show_titlescreen() //SKYRAT EDIT CHANGE if(SSticker.current_state < GAME_STATE_SETTING_UP) - var/tl = SSticker.GetTimeLeft() - to_chat(src, "Please set up your character and select \"Ready\". The game will start [tl > 0 ? "in about [DisplayTimeText(tl)]" : "soon"].") + // var/tl = SSticker.GetTimeLeft() + //to_chat(src, "Please set up your character and select \"Ready\". The game will start [tl > 0 ? "in about [DisplayTimeText(tl)]" : "soon"].") SKYRAT EDIT REMOVAL diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index 15f51f5c34e..53832c03b60 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -1,3 +1,4 @@ +/* SKYRAT EDIT REMOVAL - MOVED TO MODULAR #define LINKIFY_READY(string, value) "[string]" /mob/dead/new_player @@ -49,7 +50,7 @@ var/datum/asset/asset_datum = get_asset_datum(/datum/asset/simple/lobby) asset_datum.send(client) - var/list/output = list("

Setup Character([client.prefs.real_name])

") //SKYRAT EDIT CHANGE - ORIGINAL: var/list/output = list("

Setup Character

") + var/list/output = list("

Setup Character

") if(SSticker.current_state <= GAME_STATE_PREGAME) switch(ready) @@ -59,14 +60,10 @@ 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 \]

" - output += "

Be antagonist: [client.prefs.be_antag ? "Enabled" : "Disabled"]

" //SKYRAT EDIT ADDITION - output += "

Be midround antagonist: [(client.prefs.toggles & MIDROUND_ANTAG) ? "Enabled" : "Disabled"]

" //SKYRAT EDIT ADDITION else output += "

View the Crew Manifest

" output += "

Join Game!

" output += "

[LINKIFY_READY("Observe", PLAYER_READY_TO_OBSERVE)]

" - output += "

Be Latejoin Antagonist: [client.prefs.be_antag ? "Enabled" : "Disabled"]

" //SKYRAT EDIT ADDITION - output += "

Be Midround Antagonist: [(client.prefs.toggles & MIDROUND_ANTAG) ? "Enabled" : "Disabled"]

" //SKYRAT EDIT ADDITION if(!IsGuestKey(src.key)) output += playerpolls() @@ -133,7 +130,6 @@ relevant_cap = max(hpc, epc) if(href_list["show_preferences"]) - client.prefs.needs_update = TRUE //SKYRAT EDIT ADDITION - CUSTOMIZATION client.prefs.ShowChoices(src) return TRUE @@ -154,18 +150,6 @@ src << browse(null, "window=playersetup") //closes the player setup window new_player_panel() - //SKYRAT EDIT ADDITION BEGIN - if(href_list["antagtoggle"]) - client.prefs.be_antag = !client.prefs.be_antag - to_chat(usr, "You will now [client.prefs.be_antag ? "be considered" : "not be considered"] for any antagonist positions set in your preferences.") - new_player_panel() - - if(href_list["midroundantag"]) - client.prefs.toggles ^= MIDROUND_ANTAG - to_chat(usr, "You will now [(client.prefs.toggles & MIDROUND_ANTAG) ? "be considered" : "not be considered"] for any midround antagonist opportunities.") - new_player_panel() - //SKYRAT EDIT END - if(href_list["late_join"]) if(!SSticker?.IsRoundInProgress()) to_chat(usr, "The round is either not ready, or has already finished...") @@ -278,12 +262,6 @@ return "Your account is not old enough for [jobtitle]." if(JOB_UNAVAILABLE_SLOTFULL) return "[jobtitle] is already filled to capacity." - //SKYRAT EDIT ADDITION BEGIN - CUSTOMIZATION - if(JOB_UNAVAILABLE_QUIRK) - return "[jobtitle] is restricted from your quirks." - if(JOB_UNAVAILABLE_SPECIES) - return "[jobtitle] is restricted from your species." - //SKYRAT EDIT END return "Error: Unknown job availability." /mob/dead/new_player/proc/IsJobUnavailable(rank, latejoin = FALSE) @@ -307,12 +285,6 @@ return JOB_UNAVAILABLE_ACCOUNTAGE if(job.required_playtime_remaining(client)) return JOB_UNAVAILABLE_PLAYTIME - //SKYRAT EDIT ADDITION BEGIN - CUSTOMIZATION - if(job.has_banned_quirk(client.prefs)) - return JOB_UNAVAILABLE_QUIRK - if(job.has_banned_species(client.prefs)) - return JOB_UNAVAILABLE_SPECIES - //SKYRAT EDIT END if(latejoin && !job.special_check_latejoin(client)) return JOB_UNAVAILABLE_GENERIC return JOB_AVAILABLE @@ -372,15 +344,6 @@ SSticker.minds += character.mind character.client.init_verbs() // init verbs for the late join var/mob/living/carbon/human/humanc - - //SKRYAT EDIT ADDITION BEGIN - ASSAULTOPS - if(SSticker.mode.name == "assaultops") - if(is_assaultops_target(character.mind)) - remove_assaultops_target(character.mind, original=TRUE) - if(check_assaultops_target(character)) - add_assaultops_target(character, notify_target = TRUE) - //SKYRAT EDIT ADDITION END - if(ishuman(character)) humanc = character //Let's retypecast the var to be human, @@ -426,9 +389,6 @@ /mob/dead/new_player/proc/LateChoices() var/list/dat = list("
Round Duration: [DisplayTimeText(world.time - SSticker.round_start_time)]
") - //SKYRAT EDIT ADDITION BEGIN - ALERTS - dat += "
Alert Level: [capitalize(num2seclevel(GLOB.security_level))]
" - //SKYRAT EDIT END if(SSshuttle.emergency) switch(SSshuttle.emergency.mode) if(SHUTTLE_ESCAPE) @@ -599,3 +559,4 @@ // Add verb for re-opening the interview panel, and re-init the verbs for the stat panel add_verb(src, /mob/dead/new_player/proc/open_interview) +*/ diff --git a/html/browser/FixedsysExcelsior3.01Regular.ttf b/html/browser/FixedsysExcelsior3.01Regular.ttf new file mode 100644 index 00000000000..a4f177c41a8 Binary files /dev/null and b/html/browser/FixedsysExcelsior3.01Regular.ttf differ diff --git a/html/browser/TerminusTTFWindows-4.47.0.ttf b/html/browser/TerminusTTFWindows-4.47.0.ttf new file mode 100644 index 00000000000..180b60d3158 Binary files /dev/null and b/html/browser/TerminusTTFWindows-4.47.0.ttf differ diff --git a/interface/skin.dmf b/interface/skin.dmf index 168dd6eb06c..b616cd2c330 100644 --- a/interface/skin.dmf +++ b/interface/skin.dmf @@ -116,6 +116,17 @@ window "mapwindow" right-click = true saved-params = "zoom;letterbox;zoom-mode" style = ".center { text-align: center; } .maptext { font-family: 'Small Fonts'; font-size: 7px; -dm-text-outline: 1px black; color: white; line-height: 1.1; } .command_headset { font-weight: bold;\tfont-size: 8px; } .small { font-size: 6px; } .big { font-size: 8px; } .reallybig { font-size: 8px; } .extremelybig { font-size: 8px; } .greentext { color: #00FF00; font-size: 7px; } .redtext { color: #FF0000; font-size: 7px; } .clown { color: #FF69Bf; font-size: 7px; font-weight: bold; } .his_grace { color: #15D512; } .hypnophrase { color: #0d0d0d; font-weight: bold; } .yell { font-weight: bold; } .italics { font-size: 6px; }" + elem "lobbybrowser" + type = BROWSER + pos = 0,0 + size = 640x480 + anchor1 = 0,0 + anchor2 = 100,100 + background-color = none + is-visible = false + is-disabled = true + saved-params = "" + auto-format = false elem "status_bar" type = LABEL pos = 0,464 diff --git a/modular_skyrat/master_files/code/modules/mob/living/dead/new_player/new_player.dm b/modular_skyrat/master_files/code/modules/mob/living/dead/new_player/new_player.dm new file mode 100644 index 00000000000..259226694c7 --- /dev/null +++ b/modular_skyrat/master_files/code/modules/mob/living/dead/new_player/new_player.dm @@ -0,0 +1,572 @@ +#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 + hud_possible = list() + + var/mob/living/new_character //for instant transfer once the round is set up + + //Used to make sure someone doesn't get spammed with messages if they're ineligible for roles + var/ineligible_for_roles = FALSE + + var/client/my_client + +/mob/dead/new_player/Initialize() + if(client && SSticker.state == GAME_STATE_STARTUP) + var/atom/movable/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() + + . = ..() + + GLOB.new_player_list += src + +/mob/dead/new_player/Destroy() + GLOB.new_player_list -= src + return ..() + +/mob/dead/new_player/prepare_huds() + return + +/** + * This proc generates the panel that opens to all newly joining players, allowing them to join, observe, view polls, view the current crew manifest, and open the character customization menu. + */ +/mob/dead/new_player/proc/show_titlescreen() + if (client?.interviewee) + return + + winset(src, "lobbybrowser", "is-disabled=false;is-visible=true") + + var/datum/asset/assets = get_asset_datum(/datum/asset/simple/lobby) //Sending pictures to the client + assets.send(src) + + update_titlescreen() + +/mob/dead/new_player/proc/update_titlescreen() + var/dat = get_lobby_html() + + src << browse(GLOB.current_lobby_screen, "file=titlescreen.gif;display=0") + src << browse(dat, "window=lobbybrowser") + +/datum/asset/simple/lobby + assets = list( + "FixedsysExcelsior3.01Regular.ttf" = 'html/browser/FixedsysExcelsior3.01Regular.ttf', + ) + +/mob/dead/new_player/proc/hide_titlescreen() + if(my_client.mob) + winset(my_client, "lobbybrowser", "is-disabled=true;is-visible=false") + +/mob/dead/new_player/proc/playerpolls() + var/output + if (SSdbcore.Connect()) + var/isadmin = FALSE + if(client?.holder) + isadmin = TRUE + var/datum/db_query/query_get_new_polls = SSdbcore.NewQuery({" + SELECT id FROM [format_table_name("poll_question")] + WHERE (adminonly = 0 OR :isadmin = 1) + AND Now() BETWEEN starttime AND endtime + AND deleted = 0 + AND id NOT IN ( + SELECT pollid FROM [format_table_name("poll_vote")] + WHERE ckey = :ckey + AND deleted = 0 + ) + AND id NOT IN ( + SELECT pollid FROM [format_table_name("poll_textreply")] + WHERE ckey = :ckey + AND deleted = 0 + ) + "}, list("isadmin" = isadmin, "ckey" = ckey)) + if(!query_get_new_polls.Execute()) + qdel(query_get_new_polls) + return + if(query_get_new_polls.NextRow()) + output +={"POLLS!"} + else + output +={"POLLS"} + qdel(query_get_new_polls) + if(QDELETED(src)) + return + return output + +/mob/dead/new_player/Topic(href, href_list[]) + if(src != usr || !client) + return + + if(client.interviewee) + return FALSE + + //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["lobby_setup"]) + client.prefs.needs_update = TRUE + client.prefs.ShowChoices(src) + return TRUE + + if(href_list["lobby_ready"]) + if(SSticker.current_state <= GAME_STATE_PREGAME) + client << output(null, "lobbybrowser:imgsrc") + ready = !ready + return + + if(href_list["lobby_observe"]) + ready = PLAYER_READY_TO_OBSERVE + hide_titlescreen() + make_me_an_observer() + return + + if(href_list["lobby_antagtoggle"]) + client.prefs.be_antag = !client.prefs.be_antag + update_titlescreen() + to_chat(usr, "You will now [client.prefs.be_antag ? "be considered" : "not be considered"] for any antagonist positions set in your preferences.") + return + + if(href_list["lobby_join"]) + if(!SSticker?.IsRoundInProgress()) + to_chat(usr, "The round is either not ready, or has already finished...") + return + + if(href_list["lobby_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["lobby_crew"]) + ViewManifest() + return + + + if(href_list["SelectedJob"]) + if(!SSticker?.IsRoundInProgress()) + to_chat(usr, "The round is either not ready, or has already finished...") + return + + 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["showpoll"]) + handle_player_polling() + return + + if(href_list["viewpoll"]) + var/datum/poll_question/poll = locate(href_list["viewpoll"]) in GLOB.polls + poll_player(poll) + + if(href_list["votepollref"]) + var/datum/poll_question/poll = locate(href_list["votepollref"]) in GLOB.polls + vote_on_poll_handler(poll, href_list) + + if(href_list["lobby_changelog"]) + client.changelog() + +//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 + show_titlescreen() + 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.client.init_verbs() + observer.update_appearance() + observer.stop_sound_channel(CHANNEL_LOBBYMUSIC) + deadchat_broadcast(" has observed.", "[observer.real_name]", follow_target = observer, turf_target = get_turf(observer), message_type = DEADCHAT_DEATHRATTLE) + 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." + if(JOB_UNAVAILABLE_QUIRK) + return "[jobtitle] is restricted from your quirks." + if(JOB_UNAVAILABLE_SPECIES) + return "[jobtitle] is restricted from your species." + 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(is_banned_from(ckey, 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(job.has_banned_quirk(client.prefs)) + return JOB_UNAVAILABLE_QUIRK + if(job.has_banned_species(client.prefs)) + return JOB_UNAVAILABLE_SPECIES + 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/is_captain = FALSE + // If we don't have an assigned cap yet, check if this person qualifies for some from of captaincy. + if(!SSjob.assigned_captain && ishuman(character) && SSjob.chain_of_command[rank] && !is_banned_from(ckey, list("Captain"))) + is_captain = TRUE + // If we already have a captain, are they a "Captain" rank and are we allowing multiple of them to be assigned? + else if(SSjob.always_promote_captain_job && (rank == "Captain")) + is_captain = TRUE + + var/equip = SSjob.EquipRank(character, rank, TRUE, is_captain) + 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/atom/movable/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 + character.client.init_verbs() // init verbs for the late join + var/mob/living/carbon/human/humanc + + if(SSticker.mode.name == "assaultops") + if(is_assaultops_target(character.mind)) + remove_assaultops_target(character.mind, original=TRUE) + if(check_assaultops_target(character)) + add_assaultops_target(character, notify_target = TRUE) + + 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) + + humanc.increment_scar_slot() + humanc.load_persistent_scars() + + if(GLOB.curse_of_madness_triggered) + give_madness(humanc, GLOB.curse_of_madness_triggered) + + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_CREWMEMBER_JOINED, humanc, rank) + + GLOB.joined_player_list += character.ckey + + 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) + + 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/list/dat = list("
Round Duration: [DisplayTimeText(world.time - SSticker.round_start_time)]
") + dat += "
Alert Level: [capitalize(num2seclevel(GLOB.security_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.

" + for(var/datum/job/prioritized_job in SSjob.prioritized_jobs) + if(prioritized_job.current_positions >= prioritized_job.total_positions) + SSjob.prioritized_jobs -= prioritized_job + dat += "
" + var/column_counter = 0 + // render each category's available jobs + for(var/category in GLOB.position_categories) + // position_categories contains category names mapped to available jobs and an appropriate color + var/cat_color = GLOB.position_categories[category]["color"] + dat += "
" + dat += "[category]" + var/list/dept_dat = list() + for(var/job in GLOB.position_categories[category]["jobs"]) + var/datum/job/job_datum = SSjob.name_occupations[job] + if(job_datum && IsJobUnavailable(job_datum.title, TRUE) == JOB_AVAILABLE) + var/command_bold = "" + if(job in GLOB.command_positions) + command_bold = " command" + if(job_datum in SSjob.prioritized_jobs) + dept_dat += "[job_datum.title] ([job_datum.current_positions])" + else + dept_dat += "[job_datum.title] ([job_datum.current_positions])" + if(!dept_dat.len) + dept_dat += "No positions open." + dat += jointext(dept_dat, "") + dat += "

" + column_counter++ + if(column_counter > 0 && (column_counter % 3 == 0)) + dat += "
" + dat += "
" + dat += "" + var/datum/browser/popup = new(src, "latechoices", "Choose Profession", 680, 580) + popup.add_stylesheet("playeroptions", 'html/browser/playeroptions.css') + popup.set_content(jointext(dat, "")) + popup.open(FALSE) // 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) + + var/frn = CONFIG_GET(flag/force_random_names) + var/admin_anon_names = SSticker.anonymousnames + if(!frn) + frn = is_banned_from(ckey, "Appearance") + if(QDELETED(src)) + return + if(frn) + client.prefs.random_character() + client.prefs.real_name = client.prefs.pref_species.random_name(gender,1) + + var/is_antag + if(mind in GLOB.pre_setup_antags) + is_antag = TRUE + + client.prefs.copy_to(H, antagonist = is_antag, is_latejoiner = transfer_after) + + if(admin_anon_names)//overrides random name because it achieves the same effect and is an admin enabled event tool + randomize_human(H) + H.fully_replace_character_name(null, SSticker.anonymousnames.anonymous_name(H)) + + H.dna.update_dna_identity() + if(mind) + if(transfer_after) + mind.late_joiner = TRUE + mind.active = FALSE //we wish to transfer the key manually + mind.original_character_slot_index = client.prefs.default_slot + mind.transfer_to(H) //won't transfer key since the mind is not active + mind.original_character = H + + H.name = real_name + client.init_verbs() + . = 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() + if(!client) + return + if(world.time < client.crew_manifest_delay) + return + client.crew_manifest_delay = world.time + (1 SECONDS) + + var/dat = "" + dat += "

Crew Manifest

" + dat += GLOB.data_core.get_manifest_html() + + 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 + hide_titlescreen() //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 + +// Used to make sure that a player has a valid job preference setup, used to knock players out of eligibility for anything if their prefs don't make sense. +// A "valid job preference setup" in this situation means at least having one job set to low, or not having "return to lobby" enabled +// Prevents "antag rolling" by setting antag prefs on, all jobs to never, and "return to lobby if preferences not available" +// Doing so would previously allow you to roll for antag, then send you back to lobby if you didn't get an antag role +// This also does some admin notification and logging as well, as well as some extra logic to make sure things don't go wrong +/mob/dead/new_player/proc/check_preferences() + if(!client) + return FALSE //Not sure how this would get run without the mob having a client, but let's just be safe. + if(client.prefs.joblessrole != RETURNTOLOBBY) + return TRUE + // If they have antags enabled, they're potentially doing this on purpose instead of by accident. Notify admins if so. + var/has_antags = FALSE + if(client.prefs.be_special.len > 0) + has_antags = TRUE + if(client.prefs.job_preferences.len == 0) + if(!ineligible_for_roles) + to_chat(src, "You have no jobs enabled, along with return to lobby if job is unavailable. This makes you ineligible for any round start role, please update your job preferences.") + ineligible_for_roles = TRUE + ready = PLAYER_NOT_READY + if(has_antags) + log_admin("[src.ckey] just got booted back to lobby with no jobs, but antags enabled.") + message_admins("[src.ckey] just got booted back to lobby with no jobs enabled, but antag rolling enabled. Likely antag rolling abuse.") + + return FALSE //This is the only case someone should actually be completely blocked from antag rolling as well + return TRUE + +/** + * Prepares a client for the interview system, and provides them with a new interview + * + * This proc will both prepare the user by removing all verbs from them, as well as + * giving them the interview form and forcing it to appear. + */ +/mob/dead/new_player/proc/register_for_interview() + // First we detain them by removing all the verbs they have on client + for (var/v in client.verbs) + var/procpath/verb_path = v + if (!(verb_path in GLOB.stat_panel_verbs)) + remove_verb(client, verb_path) + + // Then remove those on their mob as well + for (var/v in verbs) + var/procpath/verb_path = v + if (!(verb_path in GLOB.stat_panel_verbs)) + remove_verb(src, verb_path) + + // Then we create the interview form and show it to the client + var/datum/interview/I = GLOB.interviews.interview_for_client(client) + if (I) + I.ui_interact(src) + + // Add verb for re-opening the interview panel, and re-init the verbs for the stat panel + add_verb(src, /mob/dead/new_player/proc/open_interview) diff --git a/modular_skyrat/modules/customization/modules/client/preferences.dm b/modular_skyrat/modules/customization/modules/client/preferences.dm index d4a2a4de7c8..c1d3f974cb6 100644 --- a/modular_skyrat/modules/customization/modules/client/preferences.dm +++ b/modular_skyrat/modules/customization/modules/client/preferences.dm @@ -2786,7 +2786,7 @@ GLOBAL_LIST_INIT(food, list( if(istype(parent.mob, /mob/dead/new_player)) //is this shitcode? probably - I DONT CAREEE~ var/mob/dead/new_player/NP = parent.mob - NP.new_player_panel() + NP.show_titlescreen() if("tab") if (href_list["tab"]) diff --git a/modular_skyrat/modules/lobbyscreen/code/change_titlescreen.dm b/modular_skyrat/modules/lobbyscreen/code/change_titlescreen.dm new file mode 100644 index 00000000000..1c1cc5445f3 --- /dev/null +++ b/modular_skyrat/modules/lobbyscreen/code/change_titlescreen.dm @@ -0,0 +1,24 @@ +/client/proc/change_title_screen() + set category = "Admin.Fun" + set name = "Title Screen: Change" + + if(!check_rights(R_FUN)) + return + + log_admin("[key_name(usr)] is changing the titlescreen.") + message_admins("[key_name_admin(usr)] is changing the titlescreen.") + + switch(alert(usr, "Please select a new titlescreen.", "Title Screen", "Change", "Reset", "Cancel")) + if("Change") + var/file = input(usr) as icon|null + if(!file) + return + change_lobbyscreen(file) + if("Reset") + change_lobbyscreen() + if("Cancel") + return + + for(var/mob/dead/new_player/N in GLOB.new_player_list) + N.show_titlescreen() + diff --git a/modular_skyrat/modules/lobbyscreen/code/lobby.dm b/modular_skyrat/modules/lobbyscreen/code/lobby.dm new file mode 100644 index 00000000000..2cbf5275174 --- /dev/null +++ b/modular_skyrat/modules/lobbyscreen/code/lobby.dm @@ -0,0 +1,210 @@ +GLOBAL_LIST_EMPTY(startup_messages) + +/mob/dead/new_player/proc/get_lobby_html() + var/dat = {" + + + + + + + + "} + if(SSticker.current_state == GAME_STATE_STARTUP) + dat += {""} + dat += {" +
+ + "} + var/loop_index = 0 + for(var/i in GLOB.startup_messages) + if(loop_index >= 25) + break + dat += i + loop_index++ + dat += "
" + + else + + if(!IsGuestKey(src.key)) + dat += {" +
+ "} + dat += playerpolls() + dat += "
" + + dat += {" +
+ SETUP ([uppertext(client.prefs.real_name)]) + "} + if(!SSticker || SSticker.current_state <= GAME_STATE_PREGAME) + dat += {"[ready ? "READY ☑" : "READY ☒"] + "} + else + dat += {"JOIN + "} + dat += {"CREW + "} + + dat += {"[client.prefs.be_antag ? "BE ANTAG ☑" : "BE ANTAG ☒"] + "} + + dat += {"OBSERVE + "} + dat += {"

CHANGELOG + "} + + dat += "
" + dat += {""} + dat += {" + + "} + + dat += "" + + return dat + +/proc/add_startupmessage(msg) + var/msg_dat = {""} + + GLOB.startup_messages.Insert(1, msg_dat) + + for(var/mob/dead/new_player/N in GLOB.new_player_list) + INVOKE_ASYNC(N, /mob/dead/new_player.proc/update_titlescreen) diff --git a/modular_skyrat/modules/lobbyscreen/code/title_screen.dm b/modular_skyrat/modules/lobbyscreen/code/title_screen.dm new file mode 100644 index 00000000000..0b6c866367d --- /dev/null +++ b/modular_skyrat/modules/lobbyscreen/code/title_screen.dm @@ -0,0 +1,59 @@ +GLOBAL_VAR(current_lobby_screen) + +GLOBAL_LIST_EMPTY(lobby_screens) + +SUBSYSTEM_DEF(title) + name = "Title Screen" + flags = SS_NO_FIRE + init_order = INIT_ORDER_TITLE + + var/file_path + var/icon/startup_splash + +/datum/controller/subsystem/title/Initialize() + if(file_path) + return + + var/list/provisional_title_screens = flist("[global.config.directory]/title_screens/images/") + var/list/title_screens = list() + + for(var/S in provisional_title_screens) + var/list/L = splittext(S,"+") + if((L.len == 1 && (L[1] != "exclude" && L[1] != "blank.png" && L[1] != "startup_splash"))) + title_screens += S + + if(L.len > 1 && lowertext(L[1]) == "startup_splash") + var/file_path = "[global.config.directory]/title_screens/images/[S]" + ASSERT(fexists(file_path)) + startup_splash = new(fcopy_rsc(file_path)) + + if(startup_splash) + change_lobbyscreen(startup_splash) + else + change_lobbyscreen('modular_skyrat/modules/lobbyscreen/icons/loading_screen.gif') + + if(length(title_screens)) + for(var/i in title_screens) + var/file_path = "[global.config.directory]/title_screens/images/[i]" + ASSERT(fexists(file_path)) + var/icon/title2use = new(fcopy_rsc(file_path)) + GLOB.lobby_screens += title2use + + return ..() + +/datum/controller/subsystem/title/Recover() + startup_splash = SStitle.startup_splash + file_path = SStitle.file_path + + +/proc/change_lobbyscreen(new_screen) + if(new_screen) + GLOB.current_lobby_screen = new_screen + else + if(GLOB.lobby_screens.len) + GLOB.current_lobby_screen = pick(GLOB.lobby_screens) + else + GLOB.current_lobby_screen = 'modular_skyrat/modules/lobbyscreen/icons/skyrat_lobbyscreen.png' + + for(var/mob/dead/new_player/N in GLOB.new_player_list) + INVOKE_ASYNC(N, /mob/dead/new_player.proc/show_titlescreen) diff --git a/modular_skyrat/modules/lobbyscreen/icons/loading_screen.gif b/modular_skyrat/modules/lobbyscreen/icons/loading_screen.gif new file mode 100644 index 00000000000..c8a2c487037 Binary files /dev/null and b/modular_skyrat/modules/lobbyscreen/icons/loading_screen.gif differ diff --git a/modular_skyrat/modules/lobbyscreen/icons/skyrat_lobbyscreen.png b/modular_skyrat/modules/lobbyscreen/icons/skyrat_lobbyscreen.png new file mode 100644 index 00000000000..3141156a6bd Binary files /dev/null and b/modular_skyrat/modules/lobbyscreen/icons/skyrat_lobbyscreen.png differ diff --git a/modular_skyrat/modules/lobbyscreen/readme.md b/modular_skyrat/modules/lobbyscreen/readme.md new file mode 100644 index 00000000000..713eee38319 --- /dev/null +++ b/modular_skyrat/modules/lobbyscreen/readme.md @@ -0,0 +1,10 @@ +## Title: Lobby screens! + +MODULE ID: lobbyscreen + +### Description: + +Adds a brand new look to the lobby screen, adds a splash screen too, since that shit is awesome. Inspired by TauCeti, heavily modified by me. + +### Credits: +Gandalf2k15 & TauCeti diff --git a/tgstation.dme b/tgstation.dme index 30118cf6e83..b7f2b14d51f 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -3561,6 +3561,7 @@ #include "modular_skyrat\master_files\code\modules\language\language_holders.dm" #include "modular_skyrat\master_files\code\modules\mob\living\emote_popup.dm" #include "modular_skyrat\master_files\code\modules\mob\living\carbon\carbon_say.dm" +#include "modular_skyrat\master_files\code\modules\mob\living\dead\new_player\new_player.dm" #include "modular_skyrat\master_files\code\modules\mob\living\simple_animal\friendly\bumbles.dm" #include "modular_skyrat\master_files\code\modules\power\lighting.dm" #include "modular_skyrat\master_files\code\modules\projectiles\guns\gun.dm" @@ -4024,6 +4025,9 @@ #include "modular_skyrat\modules\jungle\code\game\objects\structures\flora.dm" #include "modular_skyrat\modules\large_doors\code\large_doors.dm" #include "modular_skyrat\modules\layer_shift\code\modules\mob\mob_movement.dm" +#include "modular_skyrat\modules\lobbyscreen\code\change_titlescreen.dm" +#include "modular_skyrat\modules\lobbyscreen\code\lobby.dm" +#include "modular_skyrat\modules\lobbyscreen\code\title_screen.dm" #include "modular_skyrat\modules\mapping\code\dungeon.dm" #include "modular_skyrat\modules\mapping\code\furniture.dm" #include "modular_skyrat\modules\mapping\code\genpop.dm"