diff --git a/code/__DEFINES/dcs/signals/signals_hud.dm b/code/__DEFINES/dcs/signals/signals_hud.dm new file mode 100644 index 0000000000..c771204773 --- /dev/null +++ b/code/__DEFINES/dcs/signals/signals_hud.dm @@ -0,0 +1,4 @@ +/// Sent from /atom/movable/screen/lobby/button/collapse/proc/collapse_buttons() : () +#define COMSIG_HUD_LOBBY_COLLAPSED "hud_lobby_collapsed" +/// Sent from /atom/movable/screen/lobby/button/collapse/proc/expand_buttons() : () +#define COMSIG_HUD_LOBBY_EXPANDED "hud_lobby_expanded" diff --git a/code/__DEFINES/layers_planes.dm b/code/__DEFINES/layers_planes.dm index b4c616243f..578dfe87e5 100644 --- a/code/__DEFINES/layers_planes.dm +++ b/code/__DEFINES/layers_planes.dm @@ -187,8 +187,14 @@ #define ABOVE_HUD_LAYER 30 #define ABOVE_HUD_RENDER_TARGET "ABOVE_HUD_PLANE" -#define LOBBY_BACKGROUND_LAYER 3 -#define LOBBY_BUTTON_LAYER 4 +///Layer for lobby menu collapse button +#define LOBBY_BELOW_MENU_LAYER 2 +///Layer for lobby menu background image and main buttons (Join/Ready, Observe, Charater Prefs) +#define LOBBY_MENU_LAYER 3 +///Layer for lobby menu shutter, which covers up the menu to collapse/expand it +#define LOBBY_SHUTTER_LAYER 4 +///Layer for lobby menu buttons that are hanging away from and lower than the main panel +#define LOBBY_BOTTOM_BUTTON_LAYER 5 #define SPLASHSCREEN_LAYER 90 #define SPLASHSCREEN_PLANE 90 diff --git a/code/__byond_version_compat.dm b/code/__byond_version_compat.dm new file mode 100644 index 0000000000..aed9bbf176 --- /dev/null +++ b/code/__byond_version_compat.dm @@ -0,0 +1,34 @@ +// So we want to have compile time guarantees these methods exist on local type, unfortunately 515 killed the .proc/procname and .verb/verbname syntax so we have to use nameof() +// For the record: GLOBAL_VERB_REF would be useless as verbs can't be global. + +#if DM_VERSION < 515 + +/// Call by name proc references, checks if the proc exists on either this type or as a global proc. +#define PROC_REF(X) (.proc/##X) +/// Call by name verb references, checks if the verb exists on either this type or as a global verb. +#define VERB_REF(X) (.verb/##X) + +/// Call by name proc reference, checks if the proc exists on either the given type or as a global proc +#define TYPE_PROC_REF(TYPE, X) (##TYPE.proc/##X) +/// Call by name verb reference, checks if the verb exists on either the given type or as a global verb +#define TYPE_VERB_REF(TYPE, X) (##TYPE.verb/##X) + +/// Call by name proc reference, checks if the proc is an existing global proc +#define GLOBAL_PROC_REF(X) (/proc/##X) + +#else + +/// Call by name proc references, checks if the proc exists on either this type or as a global proc. +#define PROC_REF(X) (nameof(.proc/##X)) +/// Call by name verb references, checks if the verb exists on either this type or as a global verb. +#define VERB_REF(X) (nameof(.verb/##X)) + +/// Call by name proc reference, checks if the proc exists on either the given type or as a global proc +#define TYPE_PROC_REF(TYPE, X) (nameof(##TYPE.proc/##X)) +/// Call by name verb reference, checks if the verb exists on either the given type or as a global verb +#define TYPE_VERB_REF(TYPE, X) (nameof(##TYPE.verb/##X)) + +/// Call by name proc reference, checks if the proc is an existing global proc +#define GLOBAL_PROC_REF(X) (/proc/##X) + +#endif diff --git a/code/_onclick/hud/new_player.dm b/code/_onclick/hud/new_player.dm index b426db1aac..4eff9cd7e6 100644 --- a/code/_onclick/hud/new_player.dm +++ b/code/_onclick/hud/new_player.dm @@ -1,12 +1,20 @@ +#define SHUTTER_MOVEMENT_DURATION 0.4 SECONDS +#define SHUTTER_WAIT_DURATION 0.2 SECONDS + /datum/hud/new_player + ///Whether the menu is currently on the client's screen or not + var/menu_hud_status = TRUE /datum/hud/new_player/proc/populate_buttons(mob/dead/new_player/owner) var/list/buttons = subtypesof(/atom/movable/screen/lobby) for(var/button_type in buttons) - var/atom/movable/screen/lobby/lobbyscreen = new button_type() + var/atom/movable/screen/lobby/lobbyscreen = new button_type(our_hud = src) lobbyscreen.SlowInit() lobbyscreen.hud = src static_inventory += lobbyscreen + if(!lobbyscreen.always_shown) + lobbyscreen.RegisterSignal(src, COMSIG_HUD_LOBBY_COLLAPSED, TYPE_PROC_REF(/atom/movable/screen/lobby, collapse_button)) + lobbyscreen.RegisterSignal(src, COMSIG_HUD_LOBBY_EXPANDED, TYPE_PROC_REF(/atom/movable/screen/lobby, expand_button)) if(istype(lobbyscreen, /atom/movable/screen/lobby/button)) var/atom/movable/screen/lobby/button/lobby_button = lobbyscreen lobby_button.owner = REF(owner) @@ -14,15 +22,35 @@ /atom/movable/screen/lobby plane = SPLASHSCREEN_PLANE - layer = LOBBY_BUTTON_LAYER + layer = LOBBY_MENU_LAYER screen_loc = "TOP,CENTER" + ///Whether this HUD element can be hidden from the client's "screen" (moved off-screen) or not + var/always_shown = FALSE + +/atom/movable/screen/lobby/New(loc, datum/hud/our_hud, ...) + if(our_hud) + hud = our_hud + return ..() /// Run sleeping actions after initialize /atom/movable/screen/lobby/proc/SlowInit() return +///Animates moving the button off-screen +/atom/movable/screen/lobby/proc/collapse_button() + SIGNAL_HANDLER + //wait for the shutter to come down + animate(src, transform = transform, time = SHUTTER_MOVEMENT_DURATION + SHUTTER_WAIT_DURATION) + //then pull the buttons up with the shutter + animate(transform = transform.Translate(x = 0, y = 146), time = SHUTTER_MOVEMENT_DURATION, easing = CUBIC_EASING|EASE_IN) + +///Animates moving the button back into place +/atom/movable/screen/lobby/proc/expand_button() + SIGNAL_HANDLER + //the buttons are off-screen, so we sync them up to come down with the shutter + animate(src, transform = matrix(), time = SHUTTER_MOVEMENT_DURATION, easing = CUBIC_EASING|EASE_OUT) + /atom/movable/screen/lobby/background - layer = LOBBY_BACKGROUND_LAYER icon = 'icons/hud/lobby/background.dmi' icon_state = "background" screen_loc = "TOP,CENTER:-61" @@ -73,6 +101,7 @@ return icon_state = base_icon_state +///Updates the button's status: TRUE to enable interaction with the button, FALSE to disable /atom/movable/screen/lobby/button/proc/set_button_status(status) if(status == enabled) return FALSE @@ -82,6 +111,7 @@ ///Prefs menu /atom/movable/screen/lobby/button/character_setup + name = "View Character Setup" screen_loc = "TOP:-70,CENTER:-54" icon = 'icons/hud/lobby/character_setup.dmi' icon_state = "character_setup" @@ -96,10 +126,12 @@ ///Button that appears before the game has started /atom/movable/screen/lobby/button/ready + name = "Toggle Readiness" screen_loc = "TOP:-8,CENTER:-65" icon = 'icons/hud/lobby/ready.dmi' icon_state = "not_ready" base_icon_state = "not_ready" + ///Whether we are readied up for the round or not var/ready = FALSE /atom/movable/screen/lobby/button/ready/Initialize(mapload) @@ -141,6 +173,7 @@ ///Shown when the game has started /atom/movable/screen/lobby/button/join + name = "Join Game" screen_loc = "TOP:-13,CENTER:-58" icon = 'icons/hud/lobby/join.dmi' icon_state = "" //Default to not visible @@ -204,6 +237,7 @@ RegisterSignal(SSticker, COMSIG_TICKER_ENTER_SETTING_UP, .proc/show_join_button) /atom/movable/screen/lobby/button/observe + name = "Observe" screen_loc = "TOP:-40,CENTER:-54" icon = 'icons/hud/lobby/observe.dmi' icon_state = "observe_disabled" @@ -230,13 +264,18 @@ set_button_status(TRUE) UnregisterSignal(SSticker, COMSIG_TICKER_ENTER_PREGAME, .proc/enable_observing) -/atom/movable/screen/lobby/button/settings +//Subtype the bottom buttons away so the collapse/expand shutter goes behind them +/atom/movable/screen/lobby/button/bottom + layer = LOBBY_BOTTOM_BUTTON_LAYER icon = 'icons/hud/lobby/bottom_buttons.dmi' + +/atom/movable/screen/lobby/button/bottom/settings + name = "View Game Preferences" icon_state = "settings" base_icon_state = "settings" - screen_loc = "TOP:-122,CENTER:+30" + screen_loc = "TOP:-122,CENTER:+29" -/atom/movable/screen/lobby/button/settings/Click(location, control, params) +/atom/movable/screen/lobby/button/bottom/settings/Click(location, control, params) . = ..() if(!.) return @@ -244,39 +283,38 @@ hud.mymob.client.prefs.current_tab = GAME_PREFERENCES_TAB hud.mymob.client.prefs.ShowChoices(hud.mymob) -/atom/movable/screen/lobby/button/changelog_button - icon = 'icons/hud/lobby/bottom_buttons.dmi' +/atom/movable/screen/lobby/button/bottom/changelog_button + name = "View Changelog" icon_state = "changelog" base_icon_state = "changelog" - screen_loc ="TOP:-122,CENTER:+58" + screen_loc ="TOP:-122,CENTER:+57" +/atom/movable/screen/lobby/button/bottom/changelog_button/Click(location, control, params) + . = ..() + usr.client?.changelog() -/atom/movable/screen/lobby/button/crew_manifest - icon = 'icons/hud/lobby/bottom_buttons.dmi' +/atom/movable/screen/lobby/button/bottom/crew_manifest + name = "View Crew Manifest" icon_state = "crew_manifest" base_icon_state = "crew_manifest" screen_loc = "TOP:-122,CENTER:+2" -/atom/movable/screen/lobby/button/crew_manifest/Click(location, control, params) +/atom/movable/screen/lobby/button/bottom/crew_manifest/Click(location, control, params) . = ..() if(!.) return var/mob/dead/new_player/new_player = hud.mymob new_player.ViewManifest() -/atom/movable/screen/lobby/button/changelog_button/Click(location, control, params) - . = ..() - usr.client?.changelog() - -/atom/movable/screen/lobby/button/poll - icon = 'icons/hud/lobby/bottom_buttons.dmi' +/atom/movable/screen/lobby/button/bottom/poll + name = "View Available Polls" icon_state = "poll" base_icon_state = "poll" screen_loc = "TOP:-122,CENTER:-26" - + ///Whether the button should have a New Poll notification overlay var/new_poll = FALSE -/atom/movable/screen/lobby/button/poll/SlowInit(mapload) +/atom/movable/screen/lobby/button/bottom/poll/SlowInit(mapload) . = ..() if(!usr) return @@ -320,14 +358,89 @@ set_button_status(FALSE) return -/atom/movable/screen/lobby/button/poll/update_overlays() +/atom/movable/screen/lobby/button/bottom/poll/update_overlays() . = ..() if(new_poll) . += mutable_appearance('icons/hud/lobby/poll_overlay.dmi', "new_poll") -/atom/movable/screen/lobby/button/poll/Click(location, control, params) +/atom/movable/screen/lobby/button/bottom/poll/Click(location, control, params) . = ..() if(!.) return var/mob/dead/new_player/new_player = hud.mymob new_player.handle_player_polling() + +/atom/movable/screen/lobby/button/collapse + name = "Collapse Lobby Menu" + icon = 'icons/hud/lobby/collapse_expand.dmi' + icon_state = "collapse" + base_icon_state = "collapse" + layer = LOBBY_BELOW_MENU_LAYER + screen_loc = "TOP:-82,CENTER:-54" + always_shown = TRUE + +/atom/movable/screen/lobby/button/collapse/Click(location, control, params) + . = ..() + if(!.) + return + + if(!istype(hud, /datum/hud/new_player)) + return + var/datum/hud/new_player/our_hud = hud + base_icon_state = our_hud.menu_hud_status ? "expand" : "collapse" + name = "[our_hud.menu_hud_status ? "Expand" : "Collapse"] Lobby Menu" + set_button_status(FALSE) + + //get the shutter object used by our hud + var/atom/movable/screen/lobby/shutter/menu_shutter = locate(/atom/movable/screen/lobby/shutter) in hud.static_inventory + + //animate the shutter + menu_shutter.setup_shutter_animation() + //animate bottom buttons' movement + if(our_hud.menu_hud_status) + collapse_menu() + else + expand_menu() + our_hud.menu_hud_status = !our_hud.menu_hud_status + + //re-enable clicking the button when the shutter animation finishes + //we use sleep here so it can work during game setup, as addtimer would not work until the game would finish setting up + sleep(2 * SHUTTER_MOVEMENT_DURATION + SHUTTER_WAIT_DURATION) + set_button_status(TRUE) + +///Moves the button to the top of the screen, leaving only the screen part in view +///Sends a signal on the hud for the menu hud elements to listen to +/atom/movable/screen/lobby/button/collapse/proc/collapse_menu() + SEND_SIGNAL(hud, COMSIG_HUD_LOBBY_COLLAPSED) + //wait for the shutter to come down + animate(src, transform = transform, time = SHUTTER_MOVEMENT_DURATION + SHUTTER_WAIT_DURATION) + //then pull the button up with the shutter and leave it on the edge of the screen + animate(transform = transform.Translate(x = 0, y = 134), time = SHUTTER_MOVEMENT_DURATION, easing = CUBIC_EASING|EASE_IN) + +///Extends the button back to its usual spot +///Sends a signal on the hud for the menu hud elements to listen to +/atom/movable/screen/lobby/button/collapse/proc/expand_menu() + SEND_SIGNAL(hud, COMSIG_HUD_LOBBY_EXPANDED) + animate(src, transform = matrix(), time = SHUTTER_MOVEMENT_DURATION, easing = CUBIC_EASING|EASE_OUT) + +/atom/movable/screen/lobby/shutter + icon = 'icons/hud/lobby/shutter.dmi' + icon_state = "shutter" + base_icon_state = "shutter" + screen_loc = "TOP:+143,CENTER:-73" //"home" position is off-screen + layer = LOBBY_SHUTTER_LAYER + always_shown = TRUE + +///Sets up the shutter pulling down and up. It's the same animation for both collapsing and expanding the menu. +/atom/movable/screen/lobby/shutter/proc/setup_shutter_animation() + //bring down the shutter + animate(src, transform = transform.Translate(x = 0, y = -143), time = SHUTTER_MOVEMENT_DURATION, easing = CUBIC_EASING|EASE_OUT) + + //wait a little bit before bringing the shutter up + animate(transform = transform, time = SHUTTER_WAIT_DURATION) + + //pull the shutter back off-screen + animate(transform = matrix(), time = SHUTTER_MOVEMENT_DURATION, easing = CUBIC_EASING|EASE_IN) + +#undef SHUTTER_MOVEMENT_DURATION +#undef SHUTTER_WAIT_DURATION diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index 3e3a7c2c51..9b9cceee84 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -1,6 +1,9 @@ +///Cooldown for the Reset Lobby Menu HUD verb +#define RESET_HUD_INTERVAL 15 SECONDS /mob/dead/new_player var/ready = 0 - var/spawning = 0//Referenced when you want to delete the new_player later on in the code. + ///Referenced when you want to delete the new_player later on in the code. + var/spawning = 0 flags_1 = NONE @@ -11,13 +14,16 @@ hud_type = /datum/hud/new_player hud_possible = list() - var/mob/living/new_character //for instant transfer once the round is set up + ///For instant transfer once the round is set up + var/mob/living/new_character - //Used to make sure someone doesn't get spammed with messages if they're ineligible for roles + ///Used to make sure someone doesn't get spammed with messages if they're ineligible for roles var/ineligible_for_roles = FALSE - //is there a result we want to read from the age gate + ///Is there a result we want to read from the age gate var/age_gate_result + ///Cooldown for the Reset Lobby Menu HUD verb + COOLDOWN_DECLARE(reset_hud_cooldown) /mob/dead/new_player/Initialize(mapload) if(client && SSticker.state == GAME_STATE_STARTUP) @@ -34,6 +40,7 @@ . = ..() GLOB.new_player_list += src + add_verb(src, /mob/dead/new_player/proc/reset_menu_hud) /mob/dead/new_player/Destroy() GLOB.new_player_list -= src @@ -351,6 +358,11 @@ return to_chat(src, "Vote successful.") +/mob/dead/new_player/get_status_tab_items() + . = ..() + if(!SSticker.HasRoundStarted()) //only show this when the round hasn't started yet + . += "Readiness status: [ready ? "" : "Not "]Readied Up!" + //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) @@ -579,14 +591,14 @@ if(job_datum && IsJobUnavailable(job_datum.title, TRUE) == JOB_AVAILABLE) // Get currently occupied slots var/num_positions_current = job_datum.current_positions - + // Get total slots that can be occupied var/num_positions_total = job_datum.total_positions - + // Change to lemniscate for infinite-slot jobs // This variable should only used to display text! num_positions_total = (num_positions_total == -1 ? "∞" : num_positions_total) - + var/command_bold = "" if(job in GLOB.command_positions) command_bold = " command" @@ -752,3 +764,21 @@ return FALSE //This is the only case someone should actually be completely blocked from antag rolling as well return TRUE + +///Resets the Lobby Menu HUD, recreating and reassigning it to the new player +/mob/dead/new_player/proc/reset_menu_hud() + set name = "Reset Lobby Menu HUD" + set category = "OOC" + var/mob/dead/new_player/new_player = usr + if(!COOLDOWN_FINISHED(new_player, reset_hud_cooldown)) + to_chat(new_player, span_warning("You must wait [DisplayTimeText(COOLDOWN_TIMELEFT(new_player, reset_hud_cooldown))] before resetting the Lobby Menu HUD again!")) + return + if(!new_player?.client) + return + COOLDOWN_START(new_player, reset_hud_cooldown, RESET_HUD_INTERVAL) + qdel(new_player.hud_used) + create_mob_hud() + to_chat(new_player, span_info("Lobby Menu HUD reset. You may reset the HUD again in [DisplayTimeText(RESET_HUD_INTERVAL)].")) + hud_used.show_hud(hud_used.hud_version) + +#undef RESET_HUD_INTERVAL diff --git a/icons/hud/lobby/background.dmi b/icons/hud/lobby/background.dmi index baae06fc1b..554543ecf3 100644 Binary files a/icons/hud/lobby/background.dmi and b/icons/hud/lobby/background.dmi differ diff --git a/icons/hud/lobby/bottom_buttons.dmi b/icons/hud/lobby/bottom_buttons.dmi index d0aa1228c7..6cbebb6e68 100644 Binary files a/icons/hud/lobby/bottom_buttons.dmi and b/icons/hud/lobby/bottom_buttons.dmi differ diff --git a/icons/hud/lobby/collapse_expand.dmi b/icons/hud/lobby/collapse_expand.dmi new file mode 100644 index 0000000000..03f9f02f3d Binary files /dev/null and b/icons/hud/lobby/collapse_expand.dmi differ diff --git a/icons/hud/lobby/shutter.dmi b/icons/hud/lobby/shutter.dmi new file mode 100644 index 0000000000..baecaca421 Binary files /dev/null and b/icons/hud/lobby/shutter.dmi differ diff --git a/tgstation.dme b/tgstation.dme index bc69b85cdf..37db397453 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -16,6 +16,7 @@ // BEGIN_INCLUDE #include "_maps\_basemap.dm" #include "_maps\map_files\FestiveBall\doorButtonOrganizer.dm" +#include "code\__byond_version_compat.dm" #include "code\_compile_options.dm" #include "code\world.dm" #include "code\__DEFINES\_auxtools.dm" @@ -159,6 +160,7 @@ #include "code\__DEFINES\dcs\flags.dm" #include "code\__DEFINES\dcs\helpers.dm" #include "code\__DEFINES\dcs\signals.dm" +#include "code\__DEFINES\dcs\signals\signals_hud.dm" #include "code\__DEFINES\dcs\signals\signals_painting.dm" #include "code\__DEFINES\dcs\signals\signals_screentips.dm" #include "code\__DEFINES\dcs\signals\signals_medical.dm"