#pragma once #include "common.h" #include "protocol.h" #include "ui.h" struct Game; // The menu's frame: a panel (header then body) centred across the top, with the item tabs' hotbars a row under it and // the gamepad hints under those. constexpr float MENU_TOP = 24; constexpr float MENU_WIDTH = 440; constexpr float HEADER_HEIGHT = 28; constexpr float BODY_HEIGHT = 240; constexpr float BAR_SPACING = 12; constexpr float BAR_Y = MENU_TOP + HEADER_HEIGHT + BODY_HEIGHT + BAR_SPACING; constexpr float HINT_GAP = 3; enum MenuTab { TAB_WEAPONS, TAB_TRINKETS, TAB_PLAY, TAB_CUSTOMIZE, TAB_SETTINGS, TAB_COUNT }; enum PlayPage { PAGE_MAIN, PAGE_RULES, PAGE_ONLINE, // A lobby's Queue a Game: the rules again, with Host for Play. PAGE_QUEUE }; constexpr int ITEM_TABS = TAB_PLAY; // Where everything in the open menu sits. Rows is how many grid rows fit on screen. struct MenuLayout { Rect body; Rect description; Rect divider; Rect grid; Rect header; Rect panel; Rect scroll; int columns = 1; int rows = 1; }; // The Tab menu. In the sandbox: browse every weapon or trinket, read about it, level it and assign it to hotbar slots, // set up and start a game from Play, change your name in Customize, and Settings. In a match: Settings and a Forfeit // button (pressed twice), or only the item tabs being chosen from while a round's countdown lets fighters choose // them, with a Ready button. On an item tab the hotbars sit under the menu. Play asks the match to start on its next // tick (through the input). On a gamepad (or the arrow keys and Enter) the focus moves between widgets, the bumpers // switch tabs and B goes back a page or closes the menu. class Menu { public: Page pages[TAB_COUNT]; int tab = TAB_WEAPONS; bool isOpen = false; // Whether the results were left this tick (by Escape or the menu control), back to the sandbox. bool isLeaving = false; void update(Game& game); void draw(Game& game); void choice_open(Game& game); void online_open(); void targets_reset(Game& game); void target_fill(Game& game); bool is_bars_open(); Rect slot_rect(bool isTrinket, int index, int count); IconSize slot_size_get(int count); bool is_choosable(Game& game, bool isTrinket); int target_get(Game& game, bool isTrinket); private: Page description; int described = -1; // A hotbar slot clicked to read about (its item shown instead of the selection) while still on the tab it was // clicked on, or -1. int pinnedSlot = -1; // Each item tab's target slot: where an item clicked a second time goes. int targets[ITEM_TABS] = {}; int pinnedTab = -1; bool isPinnedTrinket = false; bool wasReady = false; int scrolls[ITEM_TABS] = {}; int selections[ITEM_TABS] = {}; int page = PAGE_MAIN; bool isForfeitArmed = false; bool isMultiplayer = false; // The rules a game queued in a lobby is hosted with (kept apart from this screen's own single player ones). Rules queueRules = rules_get(MODE_DEATHMATCH); // The lobby code typed on the Multiplayer page. char joinCode[LOBBY_CODE_LENGTH + 1] = {}; // Which lobby copy button (code or link) was last used, and until when it says so. int copiedButton = -1; Uint64 copiedUntil = 0; MenuLayout layout_get(); Rect box_rect(int index); int tabs_get(Game& game, int* tabs); int item_count(); int row_count(); void slot_assign(Game& game, int slot); void slot_clear(Game& game, bool isTrinket, int slot); void loadout_set(Game& game, bool isTrinket, int slot, int item); void item_toggle(Game& game); void level_step(Game& game, int step, Vec2 mouse); void slot_level_step(Game& game, bool isTrinket, int slot, int step); void pad_update(Game& game); void hints_draw(Game& game, MenuLayout& layout); void header_draw(Game& game, MenuLayout& layout); void items_draw(Game& game, MenuLayout& layout); void play_draw(Game& game, MenuLayout& layout); void rules_draw(Game& game, Rect area, Rules& rules, bool isQueue); void online_draw(Game& game, Rect area); void play_button_draw(Game& game, Rect button, bool isQueue); void players_join(Game& game); void sandbox_players_join(Game& game); void crumbs_draw(Game& game, MenuLayout& layout); };