diff --git a/MODDING.md b/MODDING.md index 726ece3..9ca4191 100644 --- a/MODDING.md +++ b/MODDING.md @@ -32,7 +32,7 @@ There's two folders inside resources; "characters" and "font". "font" is just a font containing the font used in the selection screen. That's literally it. -"common" holds files characters share (sounds, particles, the cursor and so on). Whenever a character names a file, the game looks in the character's folder first, then in "common", so a character can use anything there as is, or replace it by having its own file at the same path. This includes the taskbar's icons, `gfx/ui/icons.anm2`: one region per icon, named after its button (`talk`, `mood`, `spawn`, `autofeed`, `home`, `stats`, `catalog`, `settings`, `help`, plus whatever `icon`s the interaction types name). A character with its own `gfx/ui/icons.anm2` gets its own icons. +"common" holds files characters share (sounds, particles, the cursor and so on). Whenever a character names a file, the game looks in the character's folder first, then in "common", so a character can use anything there as is, or replace it by having its own file at the same path. This includes the taskbar's icons, `gfx/ui/icons.anm2`: one region per icon, named after its button (`talk`, `mood`, `spawn`, `autofeed`, `home`, `stats`, `catalog`, `settings`, `cheats`, `help`, plus whatever `icon`s the interaction types name). A character with its own `gfx/ui/icons.anm2` gets its own icons. EVERYTHING ELSE is stored inside character folders in the "characters" folder; one folder per character, named however you like (the folder name is also the name of its save file). This has all data associated with characters. Think of characters more as tailored game experiences rather than literally being just the characters. Not only is there the character graphics, but backgrounds, items, parameters, etc. These are intensely customizable to suit whatever experience you'd like (within the confines of the engine, of course). diff --git a/resources/common/gfx/ui/icons.anm2 b/resources/common/gfx/ui/icons.anm2 index 8988416..d461948 100644 --- a/resources/common/gfx/ui/icons.anm2 +++ b/resources/common/gfx/ui/icons.anm2 @@ -4,20 +4,21 @@ { "path": "icons.png", "regions": [ - {"name": "talk", "crop": [0, 0], "size": [48, 48], "origin": "center"}, - {"name": "mood", "crop": [49, 0], "size": [48, 48], "origin": "center"}, - {"name": "spawn", "crop": [98, 0], "size": [48, 48], "origin": "center"}, - {"name": "autofeed", "crop": [147, 0], "size": [48, 48], "origin": "center"}, - {"name": "home", "crop": [196, 0], "size": [48, 48], "origin": "center"}, - {"name": "rub", "crop": [245, 0], "size": [48, 48], "origin": "center"}, - {"name": "smack", "crop": [294, 0], "size": [48, 48], "origin": "center"}, - {"name": "kiss", "crop": [343, 0], "size": [48, 48], "origin": "center"}, - {"name": "turn", "crop": [0, 49], "size": [48, 48], "origin": "center"}, - {"name": "stats", "crop": [49, 49], "size": [48, 48], "origin": "center"}, - {"name": "catalog", "crop": [98, 49], "size": [48, 48], "origin": "center"}, - {"name": "settings", "crop": [147, 49], "size": [48, 48], "origin": "center"}, - {"name": "help", "crop": [196, 49], "size": [48, 48], "origin": "center"}, - {"name": "close", "crop": [245, 49], "size": [48, 48], "origin": "center"} + {"name": "talk", "crop": [0, 0], "size": [64, 64], "origin": "center"}, + {"name": "mood", "crop": [65, 0], "size": [64, 64], "origin": "center"}, + {"name": "spawn", "crop": [130, 0], "size": [64, 64], "origin": "center"}, + {"name": "autofeed", "crop": [195, 0], "size": [64, 64], "origin": "center"}, + {"name": "home", "crop": [260, 0], "size": [64, 64], "origin": "center"}, + {"name": "rub", "crop": [325, 0], "size": [64, 64], "origin": "center"}, + {"name": "smack", "crop": [390, 0], "size": [64, 64], "origin": "center"}, + {"name": "kiss", "crop": [455, 0], "size": [64, 64], "origin": "center"}, + {"name": "turn", "crop": [0, 65], "size": [64, 64], "origin": "center"}, + {"name": "stats", "crop": [65, 65], "size": [64, 64], "origin": "center"}, + {"name": "catalog", "crop": [130, 65], "size": [64, 64], "origin": "center"}, + {"name": "settings", "crop": [195, 65], "size": [64, 64], "origin": "center"}, + {"name": "help", "crop": [260, 65], "size": [64, 64], "origin": "center"}, + {"name": "close", "crop": [325, 65], "size": [64, 64], "origin": "center"}, + {"name": "cheats", "crop": [390, 65], "size": [64, 64], "origin": "center"} ] } ], diff --git a/resources/common/gfx/ui/icons.png b/resources/common/gfx/ui/icons.png index 1e84258..65396ec 100644 Binary files a/resources/common/gfx/ui/icons.png and b/resources/common/gfx/ui/icons.png differ diff --git a/src/ui.cpp b/src/ui.cpp index 3b0487f..15359a8 100644 --- a/src/ui.cpp +++ b/src/ui.cpp @@ -25,23 +25,25 @@ constexpr float INDICATOR_SIZE = 0.35f; constexpr float INDICATOR_SPEED = 2; constexpr float ITEM_SIZE = 96; constexpr float BAR_WIDTH_MIN = 120; -constexpr float BUTTON_SIZE = 64; +constexpr float BUTTON_SIZE_MAX = 96; +constexpr float BUTTON_SIZE_MIN = 56; constexpr float CATALOG_DIVIDER = 2; constexpr float CATALOG_GRID = 0.55f; constexpr float COOLDOWN_ALPHA = 0.6f; constexpr float COOLDOWN_RADIUS = 0.42f; -constexpr float ICON_SIZE = 48; +constexpr float ICON_FRACTION = 0.7f; constexpr float TOGGLE_FADE_FAR = 220; constexpr float TOGGLE_FADE_NEAR = 60; constexpr float TOGGLE_HEIGHT = 28; constexpr float WINDOW_FIT = 0.9f; constexpr float WINDOW_HEIGHT = 680; constexpr float WINDOW_WIDTH = 1000; +constexpr float TASKBAR_FIT = 0.8f; constexpr int BUTTONS_FIXED = 9; constexpr float INFO_GAP = 4; constexpr int COOLDOWN_SEGMENTS = 48; -constexpr const char* PANEL_ICONS[] = {"", "stats", "catalog", "settings"}; -constexpr const char* PANEL_NAMES[] = {"", "Stats", "Catalog", "Settings"}; +constexpr const char* PANEL_ICONS[] = {"", "stats", "catalog", "settings", "cheats"}; +constexpr const char* PANEL_NAMES[] = {"", "Stats", "Catalog", "Settings", "Cheats"}; constexpr float KG_TO_G = 1000; constexpr float KG_TO_LB = 2.20462f; constexpr float LB_TO_OZ = 16; @@ -56,7 +58,7 @@ constexpr float SLIDE_TIME = 0.125f; constexpr float TEXT_BIG = 1.25f; constexpr float TEXT_HEIGHT_LINES = 5; constexpr float TEXT_SMALL = 0.75f; -constexpr float TEXT_WIDTH = 0.4f; +constexpr float TEXT_WIDTH = 0.5f; constexpr float TOOLTIP_WRAP = 24; constexpr float TRIANGLE_SIZE = 0.22f; constexpr float UNDISCOVERED_ALPHA = 0.5f; @@ -412,10 +414,10 @@ bool Ui::icon_button(const char* icon, const char* tooltip, ButtonState state) if (state == BUTTON_ACTIVE) ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered)); ImGui::BeginDisabled(state == BUTTON_DISABLED); - bool isPressed = is_fx(ImGui::Button("##Icon", {BUTTON_SIZE, BUTTON_SIZE})); + bool isPressed = is_fx(ImGui::Button("##Icon", {buttonSize, buttonSize})); ImVec2 min = ImGui::GetItemRectMin(); - float inset = (BUTTON_SIZE - ICON_SIZE) / 2; - icon_draw(icon, {min.x + inset, min.y + inset}, ICON_SIZE, ImGui::GetColorU32(ImGuiCol_Text)); + float inset = buttonSize * (1 - ICON_FRACTION) / 2; + icon_draw(icon, {min.x + inset, min.y + inset}, buttonSize * ICON_FRACTION, ImGui::GetColorU32(ImGuiCol_Text)); ImGui::EndDisabled(); if (state == BUTTON_ACTIVE) ImGui::PopStyleColor(); @@ -485,12 +487,15 @@ void Ui::taskbar_draw(Play& play, ImVec2 screen) widths[i] = std::max(BAR_WIDTH_MIN, ImGui::CalcTextSize(bars[i].c_str()).x + style.FramePadding.x * 4); used += ImGui::CalcTextSize(labels[i]).x + style.ItemSpacing.x + widths[i]; } - int count = BUTTONS_FIXED + (int)data.interactTypes.size(); + int count = BUTTONS_FIXED + (int)data.interactTypes.size() + play.isCheats; + float spacing = (count - 1) * style.ItemSpacing.x; + buttonSize = std::clamp((screen.x * TASKBAR_FIT - style.WindowPadding.x * 2 - spacing) / count, BUTTON_SIZE_MIN, + BUTTON_SIZE_MAX); float nameWidth = ImGui::CalcTextSize(data.name.c_str()).x; - float rowWidth = count * BUTTON_SIZE + (count - 1) * style.ItemSpacing.x; + float rowWidth = count * buttonSize + spacing; float infoWidth = nameWidth + used + style.ItemSpacing.x * INFO_GAP * std::size(labels); float width = std::max(rowWidth, infoWidth) + style.WindowPadding.x * 2; - float height = style.WindowPadding.y * 2 + ImGui::GetFrameHeight() + style.ItemSpacing.y * 2 + BUTTON_SIZE; + float height = style.WindowPadding.y * 2 + ImGui::GetFrameHeight() + style.ItemSpacing.y * 2 + buttonSize; slide_update(taskbarSlide, play.isTaskbarOpen && !play.text.isScene); float shown = std::pow(taskbarSlide, SLIDE_EASE) * height; float x = (screen.x - width) / 2; @@ -539,14 +544,14 @@ void Ui::taskbar_draw(Play& play, ImVec2 screen) (ImGui::GetContentRegionAvail().x - nameWidth - used) / std::size(labels)); for (int i = 0; i < (int)std::size(labels); i++) { - ImGui::SameLine(0, gap / 2); + ImGui::SameLine(0, gap); if (i > 0) { ImVec2 cursor = ImGui::GetCursorScreenPos(); + cursor.x -= gap / 2; ImGui::GetWindowDrawList()->AddLine(cursor, {cursor.x, cursor.y + ImGui::GetFrameHeight()}, ImGui::GetColorU32(ImGuiCol_Separator)); } - ImGui::SameLine(0, gap / 2); ImGui::AlignTextToFramePadding(); ImGui::TextUnformatted(labels[i]); ImGui::SameLine(); @@ -607,9 +612,11 @@ void Ui::taskbar_draw(Play& play, ImVec2 screen) play.cursorType = i; ImGui::PopID(); } - Panel panels[] = {PANEL_STATS, PANEL_CATALOG, PANEL_SETTINGS}; + Panel panels[] = {PANEL_STATS, PANEL_CATALOG, PANEL_SETTINGS, PANEL_CHEATS}; for (Panel each : panels) { + if (each == PANEL_CHEATS && !play.isCheats) + continue; ImGui::SameLine(); if (icon_button(PANEL_ICONS[each], PANEL_NAMES[each], BUTTON_NORMAL)) window_open(play, each); @@ -781,13 +788,12 @@ void Ui::settings_draw(Settings& settings) ImGui::SetItemTooltip("Go back to the character selection screen.\nProgress will be saved."); } -// The body in full (weight and stage, calories and digestion, totals), and the cheats when unlocked. +// The body in full: weight and stage, calories and digestion, and totals. void Ui::stats_draw(Play& play) { Character& data = *play.character; Body& body = play.body; Stats& stats = body.stats; - Traits& traits = data.traits; bool isMax = body.stage >= (int)data.stages.size(); ImGui::PushFont(nullptr, FONT_HEADER_2); @@ -819,12 +825,15 @@ void Ui::stats_draw(Play& play) ImGui::Text("Total Items Spawned: %i", stats.totalSpawned); ImGui::Text("Total Items Consumed: %i", stats.totalConsumed); ImGui::Text("Total Playtime: %s", playtime_format(stats.playtime).c_str()); - if (!play.isCheats) - return; +} - ImGui::PushFont(nullptr, FONT_HEADER_2); - ImGui::SeparatorText("Cheats"); - ImGui::PopFont(); +// Sliders setting the body's stats directly, unlocked by the cheat code. +void Ui::cheats_draw(Play& play) +{ + Character& data = *play.character; + Body& body = play.body; + Stats& stats = body.stats; + Traits& traits = data.traits; is_fx(ImGui::SliderFloat("Calories", &stats.calories, 0, body.capacity_max_get(), "%0.0f kcal")); is_fx(ImGui::SliderFloat("Capacity", &stats.capacity, traits.capacityMin, traits.capacityMax, "%0.0f kcal")); if (is_fx(ImGui::SliderFloat("Weight", &stats.weight, traits.weight, traits.weightMax, "%0.2f kg"))) @@ -960,6 +969,8 @@ void Ui::window_draw(Play& play, Settings& settings, ImVec2 screen) stats_draw(play); else if (panel == PANEL_CATALOG) catalog_draw(play); + else if (panel == PANEL_CHEATS) + cheats_draw(play); else settings_draw(settings); if (ImGui::IsKeyPressed(ImGuiKey_Escape)) diff --git a/src/ui.h b/src/ui.h index 802f3c2..1683440 100644 --- a/src/ui.h +++ b/src/ui.h @@ -4,10 +4,10 @@ #include "save.h" #include -constexpr float FONT_NORMAL = 26; -constexpr float FONT_HEADER_3 = 30; -constexpr float FONT_HEADER_2 = 34; -constexpr float FONT_DIALOGUE = 32; +constexpr float FONT_NORMAL = 30; +constexpr float FONT_HEADER_3 = 34; +constexpr float FONT_HEADER_2 = 40; +constexpr float FONT_DIALOGUE = 38; class Play; @@ -22,7 +22,8 @@ enum Panel PANEL_NONE, PANEL_STATS, PANEL_CATALOG, - PANEL_SETTINGS + PANEL_SETTINGS, + PANEL_CHEATS }; enum ButtonState @@ -68,6 +69,7 @@ public: Commands* commands = nullptr; Measurement* measurement = nullptr; Renderer* renderer = nullptr; + float buttonSize = 0; float taskbarSlide = 1; int characterIndex = 0; int selectedIndex = -1; @@ -89,6 +91,7 @@ private: void taskbar_draw(Play& play, ImVec2 screen); void window_draw(Play& play, Settings& settings, ImVec2 screen); void stats_draw(Play& play); + void cheats_draw(Play& play); void catalog_draw(Play& play); void settings_draw(Settings& settings); void text_draw(Play& play, ImVec2 screen);