a (not so) mini update
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
#include "play.hpp"
|
||||
#include "play/style.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <glm/glm.hpp>
|
||||
@@ -11,12 +12,25 @@
|
||||
#include "../util/math.hpp"
|
||||
|
||||
using namespace game::resource;
|
||||
using namespace game::resource::xml;
|
||||
using namespace game::util;
|
||||
using namespace game::state::play;
|
||||
using namespace glm;
|
||||
|
||||
namespace game::state
|
||||
{
|
||||
namespace
|
||||
{
|
||||
int durability_animation_index_get(const resource::xml::Item& schema, const resource::xml::Anm2& anm2, int durability,
|
||||
int durabilityMax)
|
||||
{
|
||||
if (durability >= durabilityMax) return -1;
|
||||
|
||||
auto animationName = schema.animations.chew + std::to_string(std::max(0, durability));
|
||||
return anm2.animationMap.contains(animationName) ? anm2.animationMap.at(animationName) : -1;
|
||||
}
|
||||
}
|
||||
|
||||
World::Focus Play::focus_get()
|
||||
{
|
||||
if (!isWindows) return World::CENTER;
|
||||
@@ -40,9 +54,10 @@ namespace game::state
|
||||
|
||||
character =
|
||||
entity::Character(data, vec2(World::BOUNDS.x + World::BOUNDS.z * 0.5f, World::BOUNDS.w - World::BOUNDS.y));
|
||||
character.digestionRate = glm::clamp(data.digestionRateMin, character.digestionRate, data.digestionRateMax);
|
||||
character.eatSpeed = glm::clamp(data.eatSpeedMin, character.eatSpeed, data.eatSpeedMax);
|
||||
character.capacity = glm::clamp(data.capacityMin, character.capacity, data.capacityMax);
|
||||
character.digestionRate =
|
||||
glm::clamp(character.digestionRate, (float)data.digestionRateMin, (float)data.digestionRateMax);
|
||||
character.eatSpeed = glm::clamp(character.eatSpeed, (float)data.eatSpeedMin, (float)data.eatSpeedMax);
|
||||
character.capacity = glm::clamp(character.capacity, (float)data.capacityMin, (float)data.capacityMax);
|
||||
|
||||
auto isAlternateSpritesheet =
|
||||
(game == NEW_GAME && math::random_percent_roll(data.alternateSpritesheet.chanceOnNewGame));
|
||||
@@ -71,29 +86,34 @@ namespace game::state
|
||||
for (auto& item : saveData.items)
|
||||
{
|
||||
auto& anm2 = itemSchema.anm2s.at(item.id);
|
||||
auto chewAnimation = itemSchema.animations.chew + std::to_string(item.chewCount);
|
||||
auto animationIndex = item.chewCount > 0 ? anm2.animationMap[chewAnimation] : -1;
|
||||
auto& schemaItem = itemSchema.items.at(item.id);
|
||||
auto durabilityMax = schemaItem.durability.value_or(itemSchema.durability);
|
||||
auto animationIndex = durability_animation_index_get(itemSchema, anm2, item.durability, durabilityMax);
|
||||
auto& saveItem = itemSchema.anm2s.at(item.id);
|
||||
itemManager.items.emplace_back(saveItem, item.position, item.id, item.chewCount, animationIndex, item.velocity,
|
||||
itemManager.items.emplace_back(saveItem, item.position, item.id, item.durability, animationIndex, item.velocity,
|
||||
item.rotation);
|
||||
}
|
||||
|
||||
imgui::style::rounding_set(menuSchema.rounding);
|
||||
imgui::widget::sounds_set(&menuSchema.sounds.hover, &menuSchema.sounds.select);
|
||||
menu.color_set_check(resources, character);
|
||||
play::style::color_set(resources, character);
|
||||
|
||||
menu.skillCheck = SkillCheck(character);
|
||||
menu.skillCheck.totalPlays = saveData.totalPlays;
|
||||
menu.skillCheck.highScore = saveData.highScore;
|
||||
menu.skillCheck.bestCombo = saveData.bestCombo;
|
||||
menu.skillCheck.gradeCounts = saveData.gradeCounts;
|
||||
menu.skillCheck.isHighScoreAchieved = saveData.highScore > 0 ? true : false;
|
||||
menu.isChat = character.data.dialogue.help.is_valid() || character.data.dialogue.random.is_valid();
|
||||
menu.arcade = Arcade(character);
|
||||
menu.arcade.skillCheck.totalPlays = saveData.totalPlays;
|
||||
menu.arcade.skillCheck.highScore = saveData.highScore;
|
||||
menu.arcade.skillCheck.bestCombo = saveData.bestCombo;
|
||||
menu.arcade.skillCheck.gradeCounts = saveData.gradeCounts;
|
||||
menu.arcade.skillCheck.isHighScoreAchieved = saveData.highScore > 0 ? true : false;
|
||||
|
||||
text.entry = nullptr;
|
||||
text.isEnabled = false;
|
||||
|
||||
#if DEBUG
|
||||
menu.isCheats = true;
|
||||
#else
|
||||
menu.isCheats = false;
|
||||
#endif
|
||||
|
||||
isPostgame = saveData.isPostgame;
|
||||
if (character.stage_get() >= character.stage_max_get()) isPostgame = true;
|
||||
if (isPostgame) menu.isCheats = true;
|
||||
@@ -190,7 +210,7 @@ namespace game::state
|
||||
menu.isCheats = true;
|
||||
cheatCodeIndex = 0;
|
||||
cheatCodeStartTime = 0.0;
|
||||
toasts.push("Cheats unlocked!");
|
||||
toasts.push(character.data.strings.get(Strings::ToastCheatsUnlocked));
|
||||
character.data.menuSchema.sounds.cheatsActivated.play();
|
||||
}
|
||||
}
|
||||
@@ -338,10 +358,10 @@ namespace game::state
|
||||
save.digestionTimer = character.digestionTimer;
|
||||
save.totalCaloriesConsumed = character.totalCaloriesConsumed;
|
||||
save.totalFoodItemsEaten = character.totalFoodItemsEaten;
|
||||
save.totalPlays = menu.skillCheck.totalPlays;
|
||||
save.highScore = menu.skillCheck.highScore;
|
||||
save.bestCombo = menu.skillCheck.bestCombo;
|
||||
save.gradeCounts = menu.skillCheck.gradeCounts;
|
||||
save.totalPlays = menu.arcade.skillCheck.totalPlays;
|
||||
save.highScore = menu.arcade.skillCheck.highScore;
|
||||
save.bestCombo = menu.arcade.skillCheck.bestCombo;
|
||||
save.gradeCounts = menu.arcade.skillCheck.gradeCounts;
|
||||
save.isPostgame = isPostgame;
|
||||
save.isAlternateSpritesheet = character.spritesheetType == entity::Character::ALTERNATE;
|
||||
|
||||
@@ -352,7 +372,7 @@ namespace game::state
|
||||
}
|
||||
|
||||
for (auto& item : itemManager.items)
|
||||
save.items.emplace_back(item.schemaID, item.chewCount, item.position, item.velocity,
|
||||
save.items.emplace_back(item.schemaID, item.durability, item.position, item.velocity,
|
||||
*item.overrides[item.rotationOverrideID].frame.rotation);
|
||||
|
||||
save.isValid = true;
|
||||
@@ -360,6 +380,6 @@ namespace game::state
|
||||
resources.character_save_set(characterIndex, save);
|
||||
save.serialize(character.data.save_path_get());
|
||||
|
||||
toasts.push("Saving...");
|
||||
toasts.push(character.data.strings.get(Strings::ToastSaving));
|
||||
}
|
||||
};
|
||||
|
||||
76
src/state/play/arcade.cpp
Normal file
76
src/state/play/arcade.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
#include "arcade.hpp"
|
||||
|
||||
#include "../../util/imgui/widget.hpp"
|
||||
|
||||
using namespace game::util::imgui;
|
||||
using namespace game::resource::xml;
|
||||
|
||||
namespace game::state::play
|
||||
{
|
||||
Arcade::Arcade(entity::Character& character) : skillCheck(character) {}
|
||||
|
||||
void Arcade::tick() { skillCheck.tick(); }
|
||||
|
||||
void Arcade::update(Resources& resources, entity::Character& character, Inventory& inventory, Text& text)
|
||||
{
|
||||
auto available = ImGui::GetContentRegionAvail();
|
||||
auto& strings = character.data.strings;
|
||||
|
||||
if (view == SKILL_CHECK)
|
||||
{
|
||||
if (skillCheck.update(resources, character, inventory, text)) view = MENU;
|
||||
return;
|
||||
}
|
||||
|
||||
auto buttonHeight = ImGui::GetFrameHeightWithSpacing();
|
||||
auto childSize = ImVec2(available.x, std::max(0.0f, available.y - buttonHeight));
|
||||
|
||||
if (ImGui::BeginChild("##Arcade Child", childSize))
|
||||
{
|
||||
if (view == MENU)
|
||||
{
|
||||
auto buttonWidth = (ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.x) * 0.5f;
|
||||
|
||||
ImGui::PushFont(ImGui::GetFont(), resource::Font::HEADER_2);
|
||||
ImGui::TextUnformatted(strings.get(Strings::ArcadeSkillCheckName).c_str());
|
||||
ImGui::PopFont();
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::TextWrapped("%s", strings.get(Strings::ArcadeSkillCheckDescription).c_str());
|
||||
ImGui::Separator();
|
||||
|
||||
if (WIDGET_FX(ImGui::Button(strings.get(Strings::ArcadePlayButton).c_str(), ImVec2(buttonWidth, 0))))
|
||||
view = SKILL_CHECK;
|
||||
ImGui::SameLine();
|
||||
if (WIDGET_FX(ImGui::Button(strings.get(Strings::ArcadeStatsButton).c_str(), ImVec2(buttonWidth, 0))))
|
||||
view = SKILL_CHECK_STATS;
|
||||
}
|
||||
else if (view == SKILL_CHECK_STATS)
|
||||
{
|
||||
auto& schema = character.data.skillCheckSchema;
|
||||
|
||||
ImGui::PushFont(ImGui::GetFont(), resource::Font::HEADER_2);
|
||||
ImGui::TextUnformatted(strings.get(Strings::ArcadeSkillCheckName).c_str());
|
||||
ImGui::PopFont();
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::Text(strings.get(Strings::ArcadeBestFormat).c_str(), skillCheck.highScore, skillCheck.bestCombo);
|
||||
ImGui::Text(strings.get(Strings::ArcadeTotalSkillChecksFormat).c_str(), skillCheck.totalPlays);
|
||||
|
||||
for (int i = 0; i < (int)schema.grades.size(); i++)
|
||||
{
|
||||
auto& grade = schema.grades[i];
|
||||
ImGui::Text("%s: %i", grade.namePlural.c_str(), skillCheck.gradeCounts[i]);
|
||||
}
|
||||
|
||||
ImGui::Text(strings.get(Strings::ArcadeAccuracyFormat).c_str(), skillCheck.accuracy_score_get(character));
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
if (view == SKILL_CHECK_STATS)
|
||||
{
|
||||
if (WIDGET_FX(ImGui::Button(strings.get(Strings::ArcadeBackButton).c_str()))) view = MENU;
|
||||
}
|
||||
}
|
||||
}
|
||||
26
src/state/play/arcade.hpp
Normal file
26
src/state/play/arcade.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include "arcade/skill_check.hpp"
|
||||
|
||||
namespace game::state::play
|
||||
{
|
||||
class Arcade
|
||||
{
|
||||
public:
|
||||
enum View
|
||||
{
|
||||
MENU,
|
||||
SKILL_CHECK,
|
||||
SKILL_CHECK_STATS
|
||||
};
|
||||
|
||||
SkillCheck skillCheck{};
|
||||
View view{MENU};
|
||||
|
||||
Arcade() = default;
|
||||
Arcade(entity::Character&);
|
||||
|
||||
void tick();
|
||||
void update(Resources&, entity::Character&, Inventory&, Text&);
|
||||
};
|
||||
}
|
||||
@@ -6,13 +6,16 @@
|
||||
#include "../../../util/imgui/widget.hpp"
|
||||
#include "../../../util/math.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <format>
|
||||
#include <ranges>
|
||||
|
||||
using namespace game::util;
|
||||
using namespace game::entity;
|
||||
using namespace game::resource;
|
||||
using namespace game::resource::xml;
|
||||
using namespace glm;
|
||||
|
||||
namespace game::state::play
|
||||
@@ -69,7 +72,7 @@ namespace game::state::play
|
||||
actor.tick();
|
||||
}
|
||||
|
||||
void SkillCheck::update(Resources& resources, entity::Character& character, Inventory& inventory, Text& text)
|
||||
bool SkillCheck::update(Resources& resources, entity::Character& character, Inventory& inventory, Text& text)
|
||||
{
|
||||
static constexpr auto BG_COLOR_MULTIPLIER = 0.5f;
|
||||
static constexpr ImVec4 LINE_COLOR = ImVec4(1, 1, 1, 1);
|
||||
@@ -82,25 +85,31 @@ namespace game::state::play
|
||||
auto& dialogue = character.data.dialogue;
|
||||
auto& schema = character.data.skillCheckSchema;
|
||||
auto& itemSchema = character.data.itemSchema;
|
||||
auto& strings = character.data.strings;
|
||||
auto& style = ImGui::GetStyle();
|
||||
auto drawList = ImGui::GetWindowDrawList();
|
||||
auto position = ImGui::GetCursorScreenPos();
|
||||
auto size = ImGui::GetContentRegionAvail();
|
||||
auto spacing = ImGui::GetTextLineHeightWithSpacing();
|
||||
auto& io = ImGui::GetIO();
|
||||
auto menuButtonHeight = ImGui::GetFrameHeightWithSpacing();
|
||||
size.y = std::max(0.0f, size.y - menuButtonHeight);
|
||||
|
||||
auto cursorPos = ImGui::GetCursorPos();
|
||||
|
||||
ImGui::Text("Score: %i pts (%ix)", score, combo);
|
||||
auto bestString = std::format("Best: {} pts({}x)", highScore, bestCombo);
|
||||
ImGui::Text(strings.get(Strings::SkillCheckScoreFormat).c_str(), score, combo);
|
||||
std::array<char, 128> bestBuffer{};
|
||||
std::snprintf(bestBuffer.data(), bestBuffer.size(), strings.get(Strings::SkillCheckBestFormat).c_str(), highScore,
|
||||
bestCombo);
|
||||
auto bestString = std::string(bestBuffer.data());
|
||||
ImGui::SetCursorPos(ImVec2(size.x - ImGui::CalcTextSize(bestString.c_str()).x, cursorPos.y));
|
||||
|
||||
ImGui::Text("Best: %i pts (%ix)", highScore, bestCombo);
|
||||
ImGui::Text(strings.get(Strings::SkillCheckBestFormat).c_str(), highScore, bestCombo);
|
||||
|
||||
if (score == 0 && isActive)
|
||||
{
|
||||
ImGui::SetCursorPos(ImVec2(style.WindowPadding.x, size.y - style.WindowPadding.y));
|
||||
ImGui::TextWrapped("Match the line to the colored areas with Space/click! Better performance, better rewards!");
|
||||
ImGui::TextWrapped("%s", strings.get(Strings::SkillCheckInstructions).c_str());
|
||||
}
|
||||
|
||||
auto barMin = ImVec2(position.x + (size.x * 0.5f) - (spacing * 0.5f), position.y + (spacing * 2.0f));
|
||||
@@ -193,8 +202,11 @@ namespace game::state::play
|
||||
score--;
|
||||
schema.sounds.scoreLoss.play();
|
||||
auto toastMessagePosition =
|
||||
ImVec2(barMin.x - ImGui::CalcTextSize("-1").x - ImGui::GetTextLineHeightWithSpacing(), lineMin.y);
|
||||
toasts.emplace_back("-1", toastMessagePosition, schema.endTimerMax, schema.endTimerMax);
|
||||
ImVec2(barMin.x - ImGui::CalcTextSize(strings.get(Strings::SkillCheckScoreLoss).c_str()).x -
|
||||
ImGui::GetTextLineHeightWithSpacing(),
|
||||
lineMin.y);
|
||||
toasts.emplace_back(strings.get(Strings::SkillCheckScoreLoss), toastMessagePosition, schema.endTimerMax,
|
||||
schema.endTimerMax);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,10 +270,10 @@ namespace game::state::play
|
||||
}
|
||||
|
||||
auto toastMessagePosition =
|
||||
ImVec2(barMin.x - ImGui::CalcTextSize("Fantastic score!\nCongratulations!").x -
|
||||
ImVec2(barMin.x - ImGui::CalcTextSize(strings.get(Strings::SkillCheckRewardToast).c_str()).x -
|
||||
ImGui::GetTextLineHeightWithSpacing(),
|
||||
lineMin.y + (ImGui::GetTextLineHeightWithSpacing() + ImGui::GetStyle().ItemSpacing.y));
|
||||
toasts.emplace_back("Fantastic score! Congratulations!", toastMessagePosition, schema.endTimerMax,
|
||||
toasts.emplace_back(strings.get(Strings::SkillCheckRewardToast), toastMessagePosition, schema.endTimerMax,
|
||||
schema.endTimerMax);
|
||||
}
|
||||
|
||||
@@ -274,9 +286,11 @@ namespace game::state::play
|
||||
isHighScoreAchievedThisRun = true;
|
||||
schema.sounds.highScore.play();
|
||||
auto toastMessagePosition =
|
||||
ImVec2(barMin.x - ImGui::CalcTextSize("High Score!").x - ImGui::GetTextLineHeightWithSpacing(),
|
||||
ImVec2(barMin.x - ImGui::CalcTextSize(strings.get(Strings::SkillCheckHighScoreToast).c_str()).x -
|
||||
ImGui::GetTextLineHeightWithSpacing(),
|
||||
lineMin.y + ImGui::GetTextLineHeightWithSpacing());
|
||||
toasts.emplace_back("High Score!", toastMessagePosition, schema.endTimerMax, schema.endTimerMax);
|
||||
toasts.emplace_back(strings.get(Strings::SkillCheckHighScoreToast), toastMessagePosition,
|
||||
schema.endTimerMax, schema.endTimerMax);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,10 +351,10 @@ namespace game::state::play
|
||||
{
|
||||
score = 0;
|
||||
combo = 0;
|
||||
if (isHighScoreAchieved) schema.sounds.highScoreLoss.play();
|
||||
if (isHighScoreAchievedThisRun) schema.sounds.highScoreLoss.play();
|
||||
if (highScore > 0) isHighScoreAchieved = true;
|
||||
isRewardScoreAchieved = false;
|
||||
isHighScoreAchievedThisRun = true;
|
||||
isHighScoreAchievedThisRun = false;
|
||||
highScoreStart = highScore;
|
||||
isGameOver = true;
|
||||
}
|
||||
@@ -351,7 +365,9 @@ namespace game::state::play
|
||||
|
||||
queuedChallenge = challenge_generate(character);
|
||||
|
||||
auto string = grade.isFailure ? grade.name : std::format("{} (+{})", grade.name, grade.value);
|
||||
auto string = grade.isFailure ? grade.name
|
||||
: std::vformat(strings.get(Strings::SkillCheckGradeSuccessTemplate),
|
||||
std::make_format_args(grade.name, grade.value));
|
||||
auto toastMessagePosition =
|
||||
ImVec2(barMin.x - ImGui::CalcTextSize(string.c_str()).x - ImGui::GetTextLineHeightWithSpacing(), lineMin.y);
|
||||
toasts.emplace_back(string, toastMessagePosition, endTimerMax, endTimerMax);
|
||||
@@ -429,5 +445,8 @@ namespace game::state::play
|
||||
if (fallingItem.position.y > position.y + size.y) items.erase(items.begin() + i--);
|
||||
}
|
||||
ImGui::PopClipRect();
|
||||
|
||||
ImGui::SetCursorScreenPos(ImVec2(position.x, position.y + size.y + ImGui::GetStyle().ItemSpacing.y));
|
||||
return WIDGET_FX(ImGui::Button(strings.get(Strings::SkillCheckMenuButton).c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ namespace game::state::play
|
||||
SkillCheck(entity::Character&);
|
||||
Challenge challenge_generate(entity::Character&);
|
||||
void tick();
|
||||
void update(Resources&, entity::Character&, Inventory&, Text&);
|
||||
bool update(Resources&, entity::Character&, Inventory&, Text&);
|
||||
float accuracy_score_get(entity::Character&);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -89,14 +89,18 @@ namespace game::state::play
|
||||
interact_area_override_tick, interactArea.scaleEffectCycles));
|
||||
}
|
||||
|
||||
if (interactArea.pool.is_valid() && text.is_interruptible())
|
||||
text.set(dialogue.get(interactArea.pool), character);
|
||||
if (text.is_interruptible())
|
||||
{
|
||||
auto& pool = character.is_over_capacity() && interactArea.poolFull.is_valid() ? interactArea.poolFull
|
||||
: interactArea.pool;
|
||||
if (pool.is_valid())
|
||||
text.set(dialogue.get(pool), character);
|
||||
}
|
||||
}
|
||||
|
||||
if (isInteracting)
|
||||
{
|
||||
cursor.state = entity::Cursor::ACTION;
|
||||
character.queue_interact_area_animation(interactArea);
|
||||
cursor.queue_play({interactArea.animationCursorActive});
|
||||
|
||||
if (interactArea.digestionBonusRub > 0 && character.calories > 0 && !character.isDigesting)
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
#include "chat.hpp"
|
||||
|
||||
#include "../../util/imgui/widget.hpp"
|
||||
|
||||
using namespace game::resource;
|
||||
using namespace game::util::imgui;
|
||||
|
||||
namespace game::state::play
|
||||
{
|
||||
void Chat::update(Resources&, Text& text, entity::Character& character)
|
||||
{
|
||||
auto& dialogue = character.data.dialogue;
|
||||
auto size = ImGui::GetContentRegionAvail();
|
||||
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::HEADER_2);
|
||||
|
||||
if (dialogue.random.is_valid())
|
||||
if (WIDGET_FX(ImGui::Button("Let's chat!", ImVec2(size.x, 0))))
|
||||
text.set(dialogue.get(dialogue.random), character);
|
||||
|
||||
ImGui::PopFont();
|
||||
|
||||
if (dialogue.help.is_valid())
|
||||
if (WIDGET_FX(ImGui::Button("Help", ImVec2(size.x, 0)))) text.set(dialogue.get(dialogue.help), character);
|
||||
|
||||
auto stage = glm::clamp(0, character.stage_get(), character.stage_max_get());
|
||||
auto& pool = stage > 0 ? character.data.stages.at(stage - 1).pool : character.data.pool;
|
||||
|
||||
if (pool.is_valid())
|
||||
if (WIDGET_FX(ImGui::Button("How are you feeling?", ImVec2(size.x, 0)))) text.set(dialogue.get(pool), character);
|
||||
}
|
||||
}
|
||||
@@ -8,82 +8,50 @@
|
||||
|
||||
using namespace game::util::imgui;
|
||||
using namespace game::util;
|
||||
using namespace game::resource::xml;
|
||||
|
||||
namespace game::state::play
|
||||
{
|
||||
void Cheats::update(Resources&, entity::Character& character, Inventory& inventory, Text& text)
|
||||
void Cheats::update(Resources&, entity::Character& character, Inventory& inventory)
|
||||
{
|
||||
static constexpr auto FEED_INCREMENT = 100.0f;
|
||||
auto& strings = character.data.strings;
|
||||
|
||||
if (ImGui::BeginChild("##Cheats"))
|
||||
{
|
||||
|
||||
if (WIDGET_FX(ImGui::Button("Feed")))
|
||||
{
|
||||
character.calories = std::min(character.calories + FEED_INCREMENT, character.max_capacity());
|
||||
character.queue_idle_animation();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (WIDGET_FX(ImGui::Button("Starve")))
|
||||
{
|
||||
character.calories = std::max(0.0f, character.calories - FEED_INCREMENT);
|
||||
character.queue_idle_animation();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (WIDGET_FX(ImGui::Button("Digest"))) character.digestionProgress = entity::Character::DIGESTION_MAX;
|
||||
|
||||
auto stage = character.stage + 1;
|
||||
if (WIDGET_FX(ImGui::SliderInt("Stage", &stage, 1, (int)character.data.stages.size() + 1)))
|
||||
|
||||
auto weight_update = [&]() { character.queue_idle_animation(); };
|
||||
|
||||
WIDGET_FX(ImGui::SliderFloat(strings.get(Strings::CheatsCalories).c_str(), &character.calories, 0,
|
||||
character.max_capacity(), "%0.0f kcal"));
|
||||
WIDGET_FX(ImGui::SliderFloat(strings.get(Strings::CheatsCapacity).c_str(), &character.capacity,
|
||||
character.data.capacityMin, character.data.capacityMax, "%0.0f kcal"));
|
||||
|
||||
if (WIDGET_FX(ImGui::SliderFloat(strings.get(Strings::CheatsWeight).c_str(), &character.weight,
|
||||
character.data.weight, character.data.weightMax,
|
||||
strings.get(Strings::CheatsWeightFormat).c_str())))
|
||||
weight_update();
|
||||
|
||||
if (WIDGET_FX(ImGui::SliderInt(strings.get(Strings::CheatsStage).c_str(), &stage, 1,
|
||||
(int)character.data.stages.size() + 1)))
|
||||
{
|
||||
character.stage = glm::clamp(0, stage - 1, (int)character.data.stages.size());
|
||||
character.weight =
|
||||
character.stage == 0 ? character.data.weight : character.data.stages.at(character.stage - 1).threshold;
|
||||
character.queue_idle_animation();
|
||||
weight_update();
|
||||
}
|
||||
|
||||
WIDGET_FX(ImGui::SliderFloat("Capacity", &character.capacity, character.data.capacityMin,
|
||||
character.data.capacityMax, "%0.0f kcal"));
|
||||
WIDGET_FX(ImGui::SliderFloat(strings.get(Strings::CheatsDigestionRate).c_str(), &character.digestionRate,
|
||||
character.data.digestionRateMin, character.data.digestionRateMax,
|
||||
strings.get(Strings::CheatsDigestionRateFormat).c_str()));
|
||||
WIDGET_FX(ImGui::SliderFloat(strings.get(Strings::CheatsEatSpeed).c_str(), &character.eatSpeed,
|
||||
character.data.eatSpeedMin, character.data.eatSpeedMax,
|
||||
strings.get(Strings::CheatsEatSpeedFormat).c_str()));
|
||||
|
||||
WIDGET_FX(ImGui::SliderFloat("Digestion Rate", &character.digestionRate, character.data.digestionRateMin,
|
||||
character.data.digestionRateMax, "%0.2f% / tick"));
|
||||
WIDGET_FX(ImGui::SliderFloat("Eat Speed", &character.eatSpeed, character.data.eatSpeedMin,
|
||||
character.data.eatSpeedMax, "%0.2fx"));
|
||||
if (WIDGET_FX(ImGui::Button(strings.get(Strings::CheatsDigestButton).c_str())))
|
||||
character.digestionProgress = entity::Character::DIGESTION_MAX;
|
||||
|
||||
ImGui::SeparatorText("Animations");
|
||||
ImGui::Text("Now Playing: %s", character.animationMapReverse.at(character.animationIndex).c_str());
|
||||
|
||||
auto childSize = ImVec2(0, ImGui::GetContentRegionAvail().y / 3);
|
||||
|
||||
if (ImGui::BeginChild("##Animations", childSize, ImGuiChildFlags_Borders))
|
||||
{
|
||||
for (int i = 0; i < (int)character.animations.size(); i++)
|
||||
{
|
||||
auto& animation = character.animations[i];
|
||||
ImGui::PushID(i);
|
||||
if (WIDGET_FX(ImGui::Selectable(animation.name.c_str())))
|
||||
character.play(animation.name.c_str(), entity::Actor::PLAY_FORCE);
|
||||
ImGui::SetItemTooltip("%s", animation.name.c_str());
|
||||
ImGui::PopID();
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::SeparatorText("Dialogue");
|
||||
|
||||
if (ImGui::BeginChild("##Dialogue", childSize, ImGuiChildFlags_Borders))
|
||||
{
|
||||
for (int i = 0; i < (int)character.data.dialogue.entries.size(); i++)
|
||||
{
|
||||
auto& entry = character.data.dialogue.entries[i];
|
||||
ImGui::PushID(i);
|
||||
if (WIDGET_FX(ImGui::Selectable(entry.name.c_str()))) text.set(&entry, character);
|
||||
ImGui::SetItemTooltip("%s", entry.name.c_str());
|
||||
ImGui::PopID();
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::SeparatorText("Inventory");
|
||||
ImGui::SeparatorText(strings.get(Strings::CheatsInventory).c_str());
|
||||
|
||||
if (ImGui::BeginChild("##Inventory", ImGui::GetContentRegionAvail(), ImGuiChildFlags_Borders))
|
||||
{
|
||||
|
||||
@@ -10,7 +10,6 @@ namespace game::state::play
|
||||
class Cheats
|
||||
{
|
||||
public:
|
||||
|
||||
void update(Resources&, entity::Character&, Inventory&, Text&);
|
||||
void update(Resources&, entity::Character&, Inventory&);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5,31 +5,68 @@
|
||||
#include <ranges>
|
||||
|
||||
using namespace game::util::imgui;
|
||||
using namespace game::resource::xml;
|
||||
|
||||
namespace game::state::play
|
||||
{
|
||||
void Debug::update(entity::Character& character, entity::Cursor& cursor, ItemManager& itemManager, Canvas& canvas)
|
||||
void Debug::update(entity::Character& character, entity::Cursor& cursor, ItemManager& itemManager, Canvas& canvas,
|
||||
Text& text)
|
||||
{
|
||||
auto& strings = character.data.strings;
|
||||
auto cursorPosition = canvas.screen_position_convert(cursor.position);
|
||||
|
||||
ImGui::Text("Cursor Pos (Screen): %0.0f, %0.0f", cursor.position.x, cursor.position.y);
|
||||
ImGui::Text("Cursor Pos (World): %0.0f, %0.0f", cursorPosition.x, cursorPosition.y);
|
||||
ImGui::Text(strings.get(Strings::DebugCursorScreenFormat).c_str(), cursor.position.x, cursor.position.y);
|
||||
ImGui::Text(strings.get(Strings::DebugCursorWorldFormat).c_str(), cursorPosition.x, cursorPosition.y);
|
||||
|
||||
WIDGET_FX(ImGui::Checkbox("Show Nulls (Hitboxes)", &character.isShowNulls));
|
||||
WIDGET_FX(ImGui::Checkbox("Show World Bounds", &isBoundsDisplay));
|
||||
ImGui::SeparatorText(strings.get(Strings::DebugAnimations).c_str());
|
||||
ImGui::Text(strings.get(Strings::DebugNowPlayingFormat).c_str(), character.animationMapReverse.at(character.animationIndex).c_str());
|
||||
|
||||
auto childSize = ImVec2(0, ImGui::GetContentRegionAvail().y / 3);
|
||||
|
||||
if (ImGui::BeginChild("##Animations", childSize, ImGuiChildFlags_Borders))
|
||||
{
|
||||
for (int i = 0; i < (int)character.animations.size(); i++)
|
||||
{
|
||||
auto& animation = character.animations[i];
|
||||
ImGui::PushID(i);
|
||||
if (WIDGET_FX(ImGui::Selectable(animation.name.c_str())))
|
||||
character.play(animation.name.c_str(), entity::Actor::PLAY_FORCE);
|
||||
ImGui::SetItemTooltip("%s", animation.name.c_str());
|
||||
ImGui::PopID();
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::SeparatorText(strings.get(Strings::DebugDialogue).c_str());
|
||||
|
||||
if (ImGui::BeginChild("##Dialogue", childSize, ImGuiChildFlags_Borders))
|
||||
{
|
||||
for (int i = 0; i < (int)character.data.dialogue.entries.size(); i++)
|
||||
{
|
||||
auto& entry = character.data.dialogue.entries[i];
|
||||
ImGui::PushID(i);
|
||||
if (WIDGET_FX(ImGui::Selectable(entry.name.c_str()))) text.set(&entry, character);
|
||||
ImGui::SetItemTooltip("%s", entry.name.c_str());
|
||||
ImGui::PopID();
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
WIDGET_FX(ImGui::Checkbox(strings.get(Strings::DebugShowNulls).c_str(), &character.isShowNulls));
|
||||
WIDGET_FX(ImGui::Checkbox(strings.get(Strings::DebugShowWorldBounds).c_str(), &isBoundsDisplay));
|
||||
|
||||
if (!itemManager.items.empty())
|
||||
{
|
||||
ImGui::SeparatorText("Item");
|
||||
ImGui::SeparatorText(strings.get(Strings::DebugItem).c_str());
|
||||
|
||||
for (int i = 0; i < (int)itemManager.items.size(); i++)
|
||||
{
|
||||
auto& item = itemManager.items[i];
|
||||
if (itemManager.heldItemIndex == i) ImGui::Text("Held");
|
||||
ImGui::Text("Type: %i", item.schemaID);
|
||||
ImGui::Text("Position: %0.0f, %0.0f", item.position.x, item.position.y);
|
||||
ImGui::Text("Velocity: %0.0f, %0.0f", item.velocity.x, item.velocity.y);
|
||||
ImGui::Text("Chew Count: %i", item.chewCount);
|
||||
if (itemManager.heldItemIndex == i) ImGui::TextUnformatted(strings.get(Strings::DebugHeld).c_str());
|
||||
ImGui::Text(strings.get(Strings::DebugItemTypeFormat).c_str(), item.schemaID);
|
||||
ImGui::Text(strings.get(Strings::DebugItemPositionFormat).c_str(), item.position.x, item.position.y);
|
||||
ImGui::Text(strings.get(Strings::DebugItemVelocityFormat).c_str(), item.velocity.x, item.velocity.y);
|
||||
ImGui::Text(strings.get(Strings::DebugItemDurabilityFormat).c_str(), item.durability);
|
||||
ImGui::Separator();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "../../entity/cursor.hpp"
|
||||
|
||||
#include "item_manager.hpp"
|
||||
#include "text.hpp"
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
@@ -14,6 +15,6 @@ namespace game::state::play
|
||||
public:
|
||||
bool isBoundsDisplay{};
|
||||
|
||||
void update(entity::Character&, entity::Cursor& cursor, ItemManager&, Canvas& canvas);
|
||||
void update(entity::Character&, entity::Cursor&, ItemManager&, Canvas&, Text&);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <format>
|
||||
|
||||
using namespace game::resource;
|
||||
using namespace game::resource::xml;
|
||||
using namespace game::util;
|
||||
|
||||
namespace game::state::play
|
||||
@@ -18,6 +19,7 @@ namespace game::state::play
|
||||
static constexpr auto WIDTH_MULTIPLIER = 0.30f;
|
||||
static constexpr auto HEIGHT_MULTIPLIER = 4.0f;
|
||||
|
||||
auto& strings = character.data.strings;
|
||||
auto& style = ImGui::GetStyle();
|
||||
auto windowSize = imgui::to_ivec2(ImGui::GetMainViewport()->Size);
|
||||
|
||||
@@ -45,26 +47,29 @@ namespace game::state::play
|
||||
auto unitString = (system == measurement::IMPERIAL ? "lbs" : "kg");
|
||||
|
||||
auto weightString = util::string::format_commas(weight, 2) + " " + unitString;
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::ABOVE_AVERAGE);
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::HEADER_1);
|
||||
ImGui::TextUnformatted(weightString.c_str());
|
||||
ImGui::SetItemTooltip("%s", weightString.c_str());
|
||||
ImGui::PopFont();
|
||||
|
||||
auto stageProgress = character.stage_progress_get();
|
||||
ImGui::ProgressBar(stageProgress, ImVec2(ImGui::GetContentRegionAvail().x, 0),
|
||||
stage >= stageMax ? "MAX" : "To Next Stage");
|
||||
strings.get(stage >= stageMax ? Strings::InfoProgressMax
|
||||
: Strings::InfoProgressToNextStage)
|
||||
.c_str());
|
||||
if (ImGui::BeginItemTooltip())
|
||||
{
|
||||
ImGui::Text("Stage: %i/%i (%0.1f%%)", stage + 1, stageMax + 1, math::to_percent(stageProgress));
|
||||
ImGui::Text(strings.get(Strings::InfoStageProgressFormat).c_str(), stage + 1, stageMax + 1,
|
||||
math::to_percent(stageProgress));
|
||||
ImGui::Separator();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, imgui::to_imvec4(color::GRAY));
|
||||
if (stage >= stageMax)
|
||||
ImGui::Text("Maxed out!");
|
||||
ImGui::TextUnformatted(strings.get(Strings::InfoMaxedOut).c_str());
|
||||
else
|
||||
{
|
||||
ImGui::Text("Start: %0.2f %s", stageWeight, unitString);
|
||||
ImGui::Text("Current: %0.2f %s", weight, unitString);
|
||||
ImGui::Text("Next: %0.2f %s", stageNextWeight, unitString);
|
||||
ImGui::Text(strings.get(Strings::InfoStageStartFormat).c_str(), stageWeight, unitString);
|
||||
ImGui::Text(strings.get(Strings::InfoStageCurrentFormat).c_str(), weight, unitString);
|
||||
ImGui::Text(strings.get(Strings::InfoStageNextFormat).c_str(), stageNextWeight, unitString);
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::EndTooltip();
|
||||
@@ -82,7 +87,7 @@ namespace game::state::play
|
||||
auto overstuffedPercent = std::max(0.0f, (calories - capacity) / (character.max_capacity() - capacity));
|
||||
auto caloriesColor = ImVec4(1.0f, 1.0f - overstuffedPercent, 1.0f - overstuffedPercent, 1.0f);
|
||||
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::ABOVE_AVERAGE);
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::HEADER_1);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, caloriesColor);
|
||||
auto caloriesString = std::format("{:.0f} kcal / {:.0f} kcal", calories,
|
||||
character.is_over_capacity() ? character.max_capacity() : character.capacity);
|
||||
@@ -95,14 +100,16 @@ namespace game::state::play
|
||||
? (float)character.digestionTimer / character.data.digestionTimerMax
|
||||
: character.digestionProgress / entity::Character::DIGESTION_MAX;
|
||||
ImGui::ProgressBar(digestionProgress, ImVec2(ImGui::GetContentRegionAvail().x, 0),
|
||||
character.isDigesting ? "Digesting..." : "Digestion");
|
||||
strings.get(character.isDigesting ? Strings::InfoDigesting
|
||||
: Strings::InfoDigestion)
|
||||
.c_str());
|
||||
|
||||
if (ImGui::BeginItemTooltip())
|
||||
{
|
||||
if (character.isDigesting)
|
||||
ImGui::TextUnformatted("Digestion in progress...");
|
||||
ImGui::TextUnformatted(strings.get(Strings::InfoDigestionInProgress).c_str());
|
||||
else if (digestionProgress <= 0.0f)
|
||||
ImGui::TextUnformatted("Give food to start digesting!");
|
||||
ImGui::TextUnformatted(strings.get(Strings::InfoGiveFoodToStartDigesting).c_str());
|
||||
else
|
||||
ImGui::Text("%0.2f%%", math::to_percent(digestionProgress));
|
||||
|
||||
@@ -110,8 +117,8 @@ namespace game::state::play
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetColorU32(imgui::to_imvec4(color::GRAY)));
|
||||
|
||||
ImGui::Text("Rate: %0.2f%% / sec", character.digestion_rate_get());
|
||||
ImGui::Text("Eating Speed: %0.2fx", character.eatSpeed);
|
||||
ImGui::Text(strings.get(Strings::InfoDigestionRateFormat).c_str(), character.digestion_rate_get());
|
||||
ImGui::Text(strings.get(Strings::InfoEatingSpeedFormat).c_str(), character.eatSpeed);
|
||||
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
|
||||
57
src/state/play/interact.cpp
Normal file
57
src/state/play/interact.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
#include "interact.hpp"
|
||||
|
||||
#include "../../util/imgui/widget.hpp"
|
||||
#include "../../util/measurement.hpp"
|
||||
|
||||
using namespace game::resource;
|
||||
using namespace game::resource::xml;
|
||||
using namespace game::util;
|
||||
using namespace game::util::imgui;
|
||||
|
||||
namespace game::state::play
|
||||
{
|
||||
void Interact::update(Resources& resources, Text& text, entity::Character& character)
|
||||
{
|
||||
auto& dialogue = character.data.dialogue;
|
||||
auto& strings = character.data.strings;
|
||||
auto size = ImGui::GetContentRegionAvail();
|
||||
|
||||
ImGui::PushFont(ImGui::GetFont(), resource::Font::HEADER_2);
|
||||
|
||||
if (dialogue.random.is_valid())
|
||||
if (WIDGET_FX(ImGui::Button(strings.get(Strings::InteractChatButton).c_str(), ImVec2(size.x, 0))))
|
||||
text.set(dialogue.get(dialogue.random), character);
|
||||
|
||||
ImGui::PopFont();
|
||||
|
||||
if (dialogue.help.is_valid())
|
||||
if (WIDGET_FX(ImGui::Button(strings.get(Strings::InteractHelpButton).c_str(), ImVec2(size.x, 0))))
|
||||
text.set(dialogue.get(dialogue.help), character);
|
||||
|
||||
auto stage = glm::clamp(0, character.stage_get(), character.stage_max_get());
|
||||
auto& pool = stage > 0 ? character.data.stages.at(stage - 1).pool : character.data.pool;
|
||||
|
||||
if (pool.is_valid())
|
||||
if (WIDGET_FX(
|
||||
ImGui::Button(strings.get(Strings::InteractFeelingButton).c_str(), ImVec2(size.x, 0))))
|
||||
text.set(dialogue.get(pool), character);
|
||||
|
||||
ImGui::PushFont(ImGui::GetFont(), resource::Font::HEADER_1);
|
||||
ImGui::SeparatorText(character.data.name.c_str());
|
||||
ImGui::PopFont();
|
||||
|
||||
auto& system = resources.settings.measurementSystem;
|
||||
auto weight = character.weight_get(system);
|
||||
auto weightUnit = system == measurement::IMPERIAL ? "lbs" : "kg";
|
||||
|
||||
ImGui::Text(strings.get(Strings::InteractWeightFormat).c_str(), weight, weightUnit,
|
||||
character.stage_get() + 1);
|
||||
ImGui::Text(strings.get(Strings::InteractCapacityFormat).c_str(), character.capacity,
|
||||
character.max_capacity());
|
||||
ImGui::Text(strings.get(Strings::InteractDigestionRateFormat).c_str(), character.digestion_rate_get());
|
||||
ImGui::Text(strings.get(Strings::InteractEatingSpeedFormat).c_str(), character.eatSpeed);
|
||||
ImGui::Separator();
|
||||
ImGui::Text(strings.get(Strings::InteractTotalCaloriesFormat).c_str(), character.totalCaloriesConsumed);
|
||||
ImGui::Text(strings.get(Strings::InteractTotalFoodItemsFormat).c_str(), character.totalFoodItemsEaten);
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
namespace game::state::play
|
||||
{
|
||||
class Chat
|
||||
class Interact
|
||||
{
|
||||
public:
|
||||
void update(Resources&, Text&, entity::Character&);
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "inventory.hpp"
|
||||
#include "style.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <format>
|
||||
@@ -7,6 +8,7 @@
|
||||
|
||||
#include "../../util/color.hpp"
|
||||
#include "../../util/imgui.hpp"
|
||||
#include "../../util/imgui/style.hpp"
|
||||
#include "../../util/imgui/widget.hpp"
|
||||
#include "../../util/math.hpp"
|
||||
|
||||
@@ -18,6 +20,8 @@ using namespace glm;
|
||||
|
||||
namespace game::state::play
|
||||
{
|
||||
using Strings = resource::xml::Strings;
|
||||
|
||||
void Inventory::tick()
|
||||
{
|
||||
for (auto& [i, actor] : actors)
|
||||
@@ -29,6 +33,7 @@ namespace game::state::play
|
||||
static constexpr auto INFO_CHILD_HEIGHT_MULTIPLIER = 1.0f / 3.0f;
|
||||
|
||||
auto& schema = character.data.itemSchema;
|
||||
auto& strings = character.data.strings;
|
||||
|
||||
auto quantity_get = [&](int itemID) -> int&
|
||||
{
|
||||
@@ -46,6 +51,77 @@ namespace game::state::play
|
||||
auto is_able_to_upgrade_get = [&](const resource::xml::Item::Entry& item, int quantity)
|
||||
{ return is_possible_to_upgrade_get(item) && quantity >= *item.upgradeCount; };
|
||||
|
||||
auto item_summary_draw = [&](const resource::xml::Item::Entry& item, int quantity)
|
||||
{
|
||||
auto& category = schema.categories[item.categoryID];
|
||||
auto& rarity = schema.rarities[item.rarityID];
|
||||
auto durability = item.durability.value_or(schema.durability);
|
||||
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::HEADER_2);
|
||||
ImGui::TextWrapped("%s (x%i)", item.name.c_str(), quantity);
|
||||
ImGui::PopFont();
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetColorU32(imgui::to_imvec4(color::GRAY)));
|
||||
ImGui::TextWrapped("-- %s (%s) --", category.name.c_str(), rarity.name.c_str());
|
||||
if (item.flavorID.has_value())
|
||||
ImGui::TextWrapped(strings.get(Strings::InventoryFlavorFormat).c_str(),
|
||||
schema.flavors[*item.flavorID].name.c_str());
|
||||
if (item.calories.has_value())
|
||||
ImGui::TextWrapped(strings.get(Strings::InventoryCaloriesFormat).c_str(), *item.calories);
|
||||
ImGui::TextWrapped(strings.get(Strings::InventoryDurabilityFormat).c_str(), durability);
|
||||
if (item.capacityBonus.has_value())
|
||||
ImGui::TextWrapped(strings.get(Strings::InventoryCapacityBonusFormat).c_str(), *item.capacityBonus);
|
||||
if (item.digestionBonus.has_value())
|
||||
{
|
||||
if (*item.digestionBonus > 0)
|
||||
ImGui::TextWrapped(strings.get(Strings::InventoryDigestionRateBonusFormat).c_str(),
|
||||
*item.digestionBonus * 60.0f);
|
||||
else if (*item.digestionBonus < 0)
|
||||
ImGui::TextWrapped(strings.get(Strings::InventoryDigestionRatePenaltyFormat).c_str(),
|
||||
*item.digestionBonus * 60.0f);
|
||||
}
|
||||
if (item.eatSpeedBonus.has_value())
|
||||
{
|
||||
if (*item.eatSpeedBonus > 0)
|
||||
ImGui::TextWrapped(strings.get(Strings::InventoryEatSpeedBonusFormat).c_str(), *item.eatSpeedBonus);
|
||||
else if (*item.eatSpeedBonus < 0)
|
||||
ImGui::TextWrapped(strings.get(Strings::InventoryEatSpeedPenaltyFormat).c_str(), *item.eatSpeedBonus);
|
||||
}
|
||||
if (is_possible_to_upgrade_get(item))
|
||||
ImGui::TextWrapped(strings.get(Strings::InventoryUpgradePreviewFormat).c_str(), *item.upgradeCount,
|
||||
schema.idToStringMap.at(*item.upgradeID).c_str());
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
ImGui::Separator();
|
||||
};
|
||||
|
||||
auto item_details_draw = [&](const resource::xml::Item::Entry& item, int quantity)
|
||||
{
|
||||
item_summary_draw(item, quantity);
|
||||
|
||||
if (ImGui::BeginChild("##Info Description Child", ImGui::GetContentRegionAvail()))
|
||||
ImGui::TextWrapped("%s", item.description.c_str());
|
||||
ImGui::EndChild();
|
||||
};
|
||||
|
||||
auto item_tooltip_draw = [&](const resource::xml::Item::Entry& item, int quantity)
|
||||
{
|
||||
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 24.0f);
|
||||
item_summary_draw(item, quantity);
|
||||
ImGui::TextWrapped("%s", item.description.c_str());
|
||||
ImGui::PopTextWrapPos();
|
||||
};
|
||||
|
||||
auto item_unknown_draw = [&]()
|
||||
{
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::HEADER_2);
|
||||
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 24.0f);
|
||||
ImGui::TextWrapped("%s", strings.get(Strings::InventoryUnknown).c_str());
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::PopFont();
|
||||
};
|
||||
|
||||
auto item_use = [&](int itemID)
|
||||
{
|
||||
auto& item = schema.items[itemID];
|
||||
@@ -176,6 +252,7 @@ namespace game::state::play
|
||||
auto& item = schema.items[i];
|
||||
auto& quantity = quantity_get(i);
|
||||
auto& rarity = schema.rarities[item.rarityID];
|
||||
auto hasItemColor = item.color.has_value();
|
||||
|
||||
if (rarity.isHidden && quantity <= 0) continue;
|
||||
|
||||
@@ -185,6 +262,7 @@ namespace game::state::play
|
||||
auto cursorScreenPos = ImGui::GetCursorScreenPos();
|
||||
auto [canvas, rect] = item_canvas_get(i, size);
|
||||
auto isSelected = selectedItemID == i;
|
||||
if (hasItemColor) imgui::style::color_set(*item.color);
|
||||
|
||||
if (isSelected)
|
||||
{
|
||||
@@ -201,8 +279,16 @@ namespace game::state::play
|
||||
isAnyInventoryItemHovered = isAnyInventoryItemHovered || ImGui::IsItemHovered();
|
||||
if (isPressed) selectedItemID = i;
|
||||
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left) && quantity > 0) item_use(i);
|
||||
if (ImGui::BeginItemTooltip())
|
||||
{
|
||||
if (quantity > 0)
|
||||
item_tooltip_draw(item, quantity);
|
||||
else
|
||||
item_unknown_draw();
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::BIG);
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::HEADER_2);
|
||||
|
||||
auto text = std::format("x{}", quantity);
|
||||
auto textPos = ImVec2(cursorScreenPos.x + size.x - ImGui::CalcTextSize(text.c_str()).x,
|
||||
@@ -210,6 +296,7 @@ namespace game::state::play
|
||||
ImGui::GetWindowDrawList()->AddText(textPos, ImGui::GetColorU32(ImGui::GetStyleColorVec4(ImGuiCol_Text)),
|
||||
text.c_str());
|
||||
ImGui::PopFont();
|
||||
if (hasItemColor) style::color_set(resources, character);
|
||||
|
||||
auto increment = ImGui::GetItemRectSize().x + ImGui::GetStyle().ItemSpacing.x;
|
||||
cursorPos.x += increment;
|
||||
@@ -231,13 +318,15 @@ namespace game::state::play
|
||||
isItemSelected = selectedItemID >= 0 && selectedItemID < (int)schema.items.size();
|
||||
auto selectedQuantity = isItemSelected ? quantity_get(selectedItemID) : 0;
|
||||
auto isSelectedItemKnown = isItemSelected && selectedQuantity > 0;
|
||||
auto selectedItemHasColor = isItemSelected && schema.items[selectedItemID].color.has_value();
|
||||
|
||||
if (isInfoVisible &&
|
||||
ImGui::BeginChild("##Info Child", infoChildSize, ImGuiChildFlags_None, ImGuiWindowFlags_NoScrollbar))
|
||||
{
|
||||
if (selectedItemHasColor) imgui::style::color_set(*schema.items[selectedItemID].color);
|
||||
ImGui::Separator();
|
||||
auto isButtonChildVisible = selectedQuantity > 0;
|
||||
ImGui::PushFont(resources.font.get(), Font::BIG);
|
||||
ImGui::PushFont(resources.font.get(), Font::HEADER_2);
|
||||
auto buttonRowHeight = ImGui::GetFrameHeight();
|
||||
auto buttonChildHeight =
|
||||
isButtonChildVisible ? buttonRowHeight * 2.0f + ImGui::GetStyle().ItemSpacing.y * 5.0f : 0.0f;
|
||||
@@ -252,56 +341,18 @@ namespace game::state::play
|
||||
{
|
||||
if (!isItemSelected)
|
||||
{
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::BIG);
|
||||
ImGui::TextWrapped("%s", "Check the \"Arcade\" tab to earn rewards!");
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::HEADER_2);
|
||||
ImGui::TextWrapped("%s", strings.get(Strings::InventoryEmptyHint).c_str());
|
||||
ImGui::PopFont();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto& item = schema.items[selectedItemID];
|
||||
auto& category = schema.categories[item.categoryID];
|
||||
auto& rarity = schema.rarities[item.rarityID];
|
||||
|
||||
if (isSelectedItemKnown)
|
||||
{
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::BIG);
|
||||
ImGui::TextWrapped("%s (x%i)", item.name.c_str(), selectedQuantity);
|
||||
ImGui::PopFont();
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetColorU32(imgui::to_imvec4(color::GRAY)));
|
||||
ImGui::TextWrapped("-- %s (%s) --", category.name.c_str(), rarity.name.c_str());
|
||||
if (item.flavorID.has_value())
|
||||
ImGui::TextWrapped("Flavor: %s", schema.flavors[*item.flavorID].name.c_str());
|
||||
if (item.calories.has_value()) ImGui::TextWrapped("%0.0f kcal", *item.calories);
|
||||
if (item.digestionBonus.has_value())
|
||||
{
|
||||
if (*item.digestionBonus > 0)
|
||||
ImGui::TextWrapped("Digestion Rate Bonus: +%0.2f%% / sec", *item.digestionBonus * 60.0f);
|
||||
else if (*item.digestionBonus < 0)
|
||||
ImGui::TextWrapped("Digestion Rate Penalty: %0.2f%% / sec", *item.digestionBonus * 60.0f);
|
||||
}
|
||||
if (item.eatSpeedBonus.has_value())
|
||||
{
|
||||
if (*item.eatSpeedBonus > 0)
|
||||
ImGui::TextWrapped("Eat Speed Bonus: +%0.2f%% / sec", *item.eatSpeedBonus);
|
||||
else if (*item.eatSpeedBonus < 0)
|
||||
ImGui::TextWrapped("Eat Speed Penalty: %0.2f%% / sec", *item.eatSpeedBonus);
|
||||
}
|
||||
if (is_possible_to_upgrade_get(item))
|
||||
ImGui::TextWrapped("Upgrade: %ix -> %s", *item.upgradeCount,
|
||||
schema.idToStringMap.at(*item.upgradeID).c_str());
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::TextWrapped("%s", item.description.c_str());
|
||||
}
|
||||
item_details_draw(item, selectedQuantity);
|
||||
else
|
||||
{
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::BIG);
|
||||
ImGui::TextWrapped("%s", "???");
|
||||
ImGui::PopFont();
|
||||
}
|
||||
item_unknown_draw();
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
@@ -310,28 +361,75 @@ namespace game::state::play
|
||||
ImGui::BeginChild("##Info Actions Child", buttonChildSize, ImGuiChildFlags_None,
|
||||
ImGuiWindowFlags_NoScrollbar))
|
||||
{
|
||||
auto& selectedItem = schema.items[selectedItemID];
|
||||
auto canUseSelectedItem = true;
|
||||
auto canUpgradeSelectedItem = is_able_to_upgrade_get(schema.items[selectedItemID], selectedQuantity);
|
||||
auto canUpgradeSelectedItem = is_able_to_upgrade_get(selectedItem, selectedQuantity);
|
||||
auto rowTwoButtonSize = row_widget_size_get(2);
|
||||
|
||||
auto upgrade_item_name_get = [&]() -> std::string
|
||||
{
|
||||
if (!selectedItem.upgradeID.has_value()) return {};
|
||||
return schema.items.at(*selectedItem.upgradeID).name;
|
||||
};
|
||||
|
||||
auto upgrade_tooltip_get = [&](bool isAll)
|
||||
{
|
||||
if (!is_possible_to_upgrade_get(selectedItem))
|
||||
return strings.get(Strings::InventoryUpgradeNoPath);
|
||||
|
||||
auto upgradeItemName = upgrade_item_name_get();
|
||||
auto upgradeCount = *selectedItem.upgradeCount;
|
||||
|
||||
if (!canUpgradeSelectedItem)
|
||||
return std::vformat(strings.get(Strings::InventoryUpgradeNeedsTemplate),
|
||||
std::make_format_args(upgradeCount, upgradeItemName));
|
||||
|
||||
if (!isAll)
|
||||
return std::vformat(strings.get(Strings::InventoryUpgradeOneTemplate),
|
||||
std::make_format_args(upgradeCount, upgradeItemName));
|
||||
|
||||
auto upgradedCount = selectedQuantity / upgradeCount;
|
||||
return std::vformat(strings.get(Strings::InventoryUpgradeAllTemplate),
|
||||
std::make_format_args(upgradeCount, upgradedCount, upgradeItemName));
|
||||
};
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::Dummy(ImVec2(0, ImGui::GetStyle().ItemSpacing.y));
|
||||
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::BIG);
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::HEADER_2);
|
||||
|
||||
ImGui::BeginDisabled(!canUseSelectedItem);
|
||||
if (WIDGET_FX(ImGui::Button("Spawn", {ImGui::GetContentRegionAvail().x, 0}))) item_use(selectedItemID);
|
||||
if (WIDGET_FX(ImGui::Button(strings.get(Strings::InventorySpawnButton).c_str(),
|
||||
{ImGui::GetContentRegionAvail().x, 0})))
|
||||
item_use(selectedItemID);
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::BeginDisabled(!canUpgradeSelectedItem);
|
||||
if (WIDGET_FX(ImGui::Button("Upgrade", rowTwoButtonSize))) item_upgrade(selectedItemID, false);
|
||||
if (WIDGET_FX(
|
||||
ImGui::Button(strings.get(Strings::InventoryUpgradeButton).c_str(), rowTwoButtonSize)))
|
||||
item_upgrade(selectedItemID, false);
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled))
|
||||
{
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::NORMAL);
|
||||
ImGui::SetItemTooltip("%s", upgrade_tooltip_get(false).c_str());
|
||||
ImGui::PopFont();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (WIDGET_FX(ImGui::Button("Upgrade All", rowTwoButtonSize))) item_upgrade(selectedItemID, true);
|
||||
if (WIDGET_FX(ImGui::Button(strings.get(Strings::InventoryUpgradeAllButton).c_str(),
|
||||
rowTwoButtonSize)))
|
||||
item_upgrade(selectedItemID, true);
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled))
|
||||
{
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::NORMAL);
|
||||
ImGui::SetItemTooltip("%s", upgrade_tooltip_get(true).c_str());
|
||||
ImGui::PopFont();
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::PopFont();
|
||||
}
|
||||
if (isButtonChildVisible) ImGui::EndChild();
|
||||
if (selectedItemHasColor) style::color_set(resources, character);
|
||||
}
|
||||
if (isInfoVisible) ImGui::EndChild();
|
||||
}
|
||||
|
||||
@@ -15,6 +15,18 @@ using namespace glm;
|
||||
|
||||
namespace game::state::play
|
||||
{
|
||||
namespace
|
||||
{
|
||||
int durability_animation_index_get(const resource::xml::Item& schema, const resource::xml::Anm2& anm2, int durability,
|
||||
int durabilityMax)
|
||||
{
|
||||
if (durability >= durabilityMax) return -1;
|
||||
|
||||
auto animationName = schema.animations.chew + std::to_string(std::max(0, durability));
|
||||
return anm2.animationMap.contains(animationName) ? anm2.animationMap.at(animationName) : -1;
|
||||
}
|
||||
}
|
||||
|
||||
void ItemManager::update(entity::Character& character, entity::Cursor& cursor, AreaManager& areaManager, Text& text,
|
||||
const glm::vec4& bounds, Canvas& canvas)
|
||||
{
|
||||
@@ -70,7 +82,11 @@ namespace game::state::play
|
||||
math::random_in_range(spawnBounds.y, spawnBounds.y + spawnBounds.w));
|
||||
|
||||
auto& itemSchema = character.data.itemSchema;
|
||||
items.emplace_back(itemSchema.anm2s.at(id), position, id);
|
||||
auto& item = itemSchema.items.at(id);
|
||||
auto& anm2 = itemSchema.anm2s.at(id);
|
||||
auto durabilityMax = item.durability.value_or(itemSchema.durability);
|
||||
auto animationIndex = durability_animation_index_get(itemSchema, anm2, 0, durabilityMax);
|
||||
items.emplace_back(anm2, position, id, 0, animationIndex);
|
||||
}
|
||||
queuedItemIDs.clear();
|
||||
|
||||
@@ -97,15 +113,15 @@ namespace game::state::play
|
||||
|
||||
if (schema.categories[item.categoryID].isEdible)
|
||||
{
|
||||
auto& chewCountMax = item.chewCount.has_value() ? *item.chewCount : schema.chewCount;
|
||||
auto caloriesChew = item.calories.has_value() ? *item.calories / (chewCountMax + 1) : 0;
|
||||
auto isCanEat = character.calories + caloriesChew <= character.max_capacity();
|
||||
auto& durabilityMax = item.durability.has_value() ? *item.durability : schema.durability;
|
||||
auto caloriesPerBite = item.calories.has_value() && durabilityMax > 0 ? *item.calories / durabilityMax : 0;
|
||||
auto isCanEat = character.calories + caloriesPerBite <= character.max_capacity();
|
||||
|
||||
if (isJustItemHeld)
|
||||
{
|
||||
if (isCanEat)
|
||||
text.set(dialogue.get(isOverCapacity ? dialogue.feedFull : dialogue.feed), character);
|
||||
else if (caloriesChew > character.capacity)
|
||||
else if (caloriesPerBite > character.capacity)
|
||||
text.set(dialogue.get(dialogue.lowCapacity), character);
|
||||
else
|
||||
text.set(dialogue.get(dialogue.full), character);
|
||||
@@ -125,37 +141,44 @@ namespace game::state::play
|
||||
|
||||
if (character.playedEventID == eatArea.eventID)
|
||||
{
|
||||
heldItem->chewCount++;
|
||||
heldItem->durability++;
|
||||
character.consume_played_event();
|
||||
|
||||
auto chewAnimation = schema.animations.chew + std::to_string(heldItem->chewCount);
|
||||
auto animationIndex = heldItem->chewCount > 0 ? heldItem->animationMap[chewAnimation] : -1;
|
||||
|
||||
heldItem->play(animationIndex, entity::Actor::SET);
|
||||
|
||||
character.calories += caloriesChew;
|
||||
character.totalCaloriesConsumed += caloriesChew;
|
||||
character.calories += caloriesPerBite;
|
||||
character.totalCaloriesConsumed += caloriesPerBite;
|
||||
|
||||
if (item.capacityBonus.has_value())
|
||||
{
|
||||
character.capacity += *item.capacityBonus / durabilityMax;
|
||||
character.capacity =
|
||||
glm::clamp(character.capacity, (float)character.data.capacityMin, (float)character.data.capacityMax);
|
||||
}
|
||||
if (item.eatSpeedBonus.has_value())
|
||||
{
|
||||
character.eatSpeed += *item.eatSpeedBonus / (chewCountMax + 1);
|
||||
character.eatSpeed =
|
||||
glm::clamp(character.data.eatSpeedMin, character.eatSpeed, character.data.eatSpeedMax);
|
||||
character.eatSpeed += *item.eatSpeedBonus / durabilityMax;
|
||||
character.eatSpeed = glm::clamp(character.eatSpeed, (float)character.data.eatSpeedMin,
|
||||
(float)character.data.eatSpeedMax);
|
||||
}
|
||||
if (item.digestionBonus.has_value())
|
||||
{
|
||||
character.digestionRate += *item.digestionBonus / (chewCountMax + 1);
|
||||
character.digestionRate = glm::clamp(character.data.digestionRateMin, character.digestionRate,
|
||||
character.data.digestionRateMax);
|
||||
character.digestionRate += *item.digestionBonus / durabilityMax;
|
||||
character.digestionRate = glm::clamp(character.digestionRate, (float)character.data.digestionRateMin,
|
||||
(float)character.data.digestionRateMax);
|
||||
}
|
||||
|
||||
if (heldItem->chewCount > chewCountMax)
|
||||
if (heldItem->durability >= durabilityMax)
|
||||
{
|
||||
isQueueFinishFood = true;
|
||||
character.totalFoodItemsEaten++;
|
||||
queuedRemoveItemIndex = heldItemIndex;
|
||||
heldItemIndex = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto animationIndex =
|
||||
durability_animation_index_get(schema, *heldItem, heldItem->durability, durabilityMax);
|
||||
heldItem->play(animationIndex, entity::Actor::SET);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,7 +200,7 @@ namespace game::state::play
|
||||
|
||||
// Food stolen
|
||||
if (auto animation = character.animation_get(character.animation_name_convert(eatArea.animation));
|
||||
character.is_playing(animation->name))
|
||||
animation && character.is_playing(animation->name))
|
||||
{
|
||||
if (!math::is_point_in_rectf(rect, heldItem->position))
|
||||
text.set(dialogue.get(isOverCapacity ? dialogue.foodTakenFull : dialogue.foodTaken), character);
|
||||
@@ -232,7 +255,7 @@ namespace game::state::play
|
||||
|
||||
if (isMouseRightClicked)
|
||||
{
|
||||
if (item.chewCount > 0)
|
||||
if (item.durability > 0)
|
||||
schema.sounds.dispose.play();
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "menu.hpp"
|
||||
|
||||
#include "style.hpp"
|
||||
|
||||
#include "../../util/imgui.hpp"
|
||||
#include "../../util/imgui/style.hpp"
|
||||
#include "../../util/imgui/widget.hpp"
|
||||
@@ -8,18 +10,14 @@
|
||||
|
||||
using namespace game::util;
|
||||
using namespace game::util::imgui;
|
||||
using namespace game::resource::xml;
|
||||
|
||||
namespace game::state::play
|
||||
{
|
||||
void Menu::tick()
|
||||
{
|
||||
inventory.tick();
|
||||
skillCheck.tick();
|
||||
}
|
||||
|
||||
void Menu::color_set_check(Resources& resources, entity::Character& character)
|
||||
{
|
||||
imgui::style::color_set(resources.settings.isUseCharacterColor ? character.data.color : resources.settings.color);
|
||||
arcade.tick();
|
||||
}
|
||||
|
||||
void Menu::update(Resources& resources, ItemManager& itemManager, entity::Character& character,
|
||||
@@ -28,6 +26,7 @@ namespace game::state::play
|
||||
static constexpr auto WIDTH_MULTIPLIER = 0.30f;
|
||||
|
||||
auto& schema = character.data.menuSchema;
|
||||
auto& strings = character.data.strings;
|
||||
|
||||
auto style = ImGui::GetStyle();
|
||||
auto& io = ImGui::GetIO();
|
||||
@@ -61,47 +60,41 @@ namespace game::state::play
|
||||
if (ImGui::BeginTabBar("##Options"))
|
||||
{
|
||||
|
||||
if (isChat && WIDGET_FX(ImGui::BeginTabItem("Chat")))
|
||||
if (WIDGET_FX(ImGui::BeginTabItem(strings.get(Strings::MenuTabInteract).c_str())))
|
||||
{
|
||||
chat.update(resources, text, character);
|
||||
interact.update(resources, text, character);
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (WIDGET_FX(ImGui::BeginTabItem("Arcade")))
|
||||
if (WIDGET_FX(ImGui::BeginTabItem(strings.get(Strings::MenuTabArcade).c_str())))
|
||||
{
|
||||
skillCheck.update(resources, character, inventory, text);
|
||||
arcade.update(resources, character, inventory, text);
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (WIDGET_FX(ImGui::BeginTabItem("Inventory")))
|
||||
if (WIDGET_FX(ImGui::BeginTabItem(strings.get(Strings::MenuTabInventory).c_str())))
|
||||
{
|
||||
inventory.update(resources, itemManager, character);
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (WIDGET_FX(ImGui::BeginTabItem("Stats")))
|
||||
if (WIDGET_FX(ImGui::BeginTabItem(strings.get(Strings::MenuTabSettings).c_str())))
|
||||
{
|
||||
stats.update(resources, skillCheck, character);
|
||||
settingsMenu.update(resources, SettingsMenu::PLAY, &strings);
|
||||
if (settingsMenu.isJustColorSet) style::color_set(resources, character);
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (WIDGET_FX(ImGui::BeginTabItem("Settings")))
|
||||
if (isCheats && WIDGET_FX(ImGui::BeginTabItem(strings.get(Strings::MenuTabCheats).c_str())))
|
||||
{
|
||||
settingsMenu.update(resources, SettingsMenu::PLAY);
|
||||
if (settingsMenu.isJustColorSet) color_set_check(resources, character);
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (isCheats && WIDGET_FX(ImGui::BeginTabItem("Cheats")))
|
||||
{
|
||||
cheats.update(resources, character, inventory, text);
|
||||
cheats.update(resources, character, inventory);
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
if (WIDGET_FX(ImGui::BeginTabItem("Debug")))
|
||||
if (WIDGET_FX(ImGui::BeginTabItem(strings.get(Strings::MenuTabDebug).c_str())))
|
||||
{
|
||||
debug.update(character, cursor, itemManager, canvas);
|
||||
debug.update(character, cursor, itemManager, canvas, text);
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
#endif
|
||||
@@ -128,7 +121,9 @@ namespace game::state::play
|
||||
|
||||
if (t <= 0.0f || t >= 1.0f)
|
||||
{
|
||||
ImGui::SetItemTooltip(isOpen ? "Close Main Menu" : "Open Main Menu");
|
||||
ImGui::SetItemTooltip("%s", strings.get(isOpen ? Strings::MenuCloseTooltip
|
||||
: Strings::MenuOpenTooltip)
|
||||
.c_str());
|
||||
if (result)
|
||||
{
|
||||
isOpen = !isOpen;
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
|
||||
#include "../settings_menu.hpp"
|
||||
|
||||
#include "arcade/skill_check.hpp"
|
||||
#include "chat.hpp"
|
||||
#include "arcade.hpp"
|
||||
#include "cheats.hpp"
|
||||
#include "debug.hpp"
|
||||
#include "stats.hpp"
|
||||
#include "interact.hpp"
|
||||
#include "inventory.hpp"
|
||||
#include "text.hpp"
|
||||
|
||||
#include "../../util/imgui/window_slide.hpp"
|
||||
@@ -18,27 +18,24 @@ namespace game::state::play
|
||||
class Menu
|
||||
{
|
||||
public:
|
||||
SkillCheck skillCheck;
|
||||
Chat chat;
|
||||
Arcade arcade;
|
||||
Interact interact;
|
||||
Cheats cheats;
|
||||
Debug debug;
|
||||
Stats stats;
|
||||
Inventory inventory;
|
||||
|
||||
state::SettingsMenu settingsMenu;
|
||||
|
||||
#if DEBUG
|
||||
bool isCheats{true};
|
||||
#elif
|
||||
#else
|
||||
bool isCheats{};
|
||||
#endif
|
||||
|
||||
bool isOpen{true};
|
||||
bool isChat{true};
|
||||
util::imgui::WindowSlide slide{};
|
||||
|
||||
void tick();
|
||||
void update(Resources&, ItemManager&, entity::Character&, entity::Cursor&, Text&, Canvas&);
|
||||
void color_set_check(Resources&, entity::Character&);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
#include "stats.hpp"
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include "../../util/measurement.hpp"
|
||||
|
||||
using namespace game::resource;
|
||||
using namespace game::util;
|
||||
|
||||
namespace game::state::play
|
||||
{
|
||||
void Stats::update(Resources& resources, SkillCheck& skillCheck, entity::Character& character)
|
||||
{
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::BIG);
|
||||
ImGui::TextUnformatted(character.data.name.c_str());
|
||||
ImGui::PopFont();
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
auto& skillCheckSchema = character.data.skillCheckSchema;
|
||||
auto& system = resources.settings.measurementSystem;
|
||||
auto weight = character.weight_get(system);
|
||||
auto weightUnit = system == measurement::IMPERIAL ? "lbs" : "kg";
|
||||
|
||||
ImGui::Text("Weight: %0.2f %s (Stage: %i)", weight, weightUnit, character.stage_get() + 1);
|
||||
ImGui::Text("Capacity: %0.0f kcal (Max: %0.0f kcal)", character.capacity, character.max_capacity());
|
||||
ImGui::Text("Digestion Rate: %0.2f%%/sec", character.digestion_rate_get());
|
||||
ImGui::Text("Eating Speed: %0.2fx", character.eatSpeed);
|
||||
|
||||
ImGui::SeparatorText("Totals");
|
||||
|
||||
ImGui::Text("Total Calories Consumed: %0.0f kcal", character.totalCaloriesConsumed);
|
||||
ImGui::Text("Total Food Items Eaten: %i", character.totalFoodItemsEaten);
|
||||
|
||||
ImGui::SeparatorText("Skill Check");
|
||||
|
||||
ImGui::Text("Best: %i pts (%ix)", skillCheck.highScore, skillCheck.bestCombo);
|
||||
ImGui::Text("Total Skill Checks: %i", skillCheck.totalPlays);
|
||||
|
||||
for (int i = 0; i < (int)skillCheckSchema.grades.size(); i++)
|
||||
{
|
||||
auto& grade = skillCheckSchema.grades[i];
|
||||
ImGui::Text("%s: %i", grade.namePlural.c_str(), skillCheck.gradeCounts[i]);
|
||||
}
|
||||
|
||||
ImGui::Text("Accuracy: %0.2f%%", skillCheck.accuracy_score_get(character));
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../entity/character.hpp"
|
||||
#include "../../resources.hpp"
|
||||
|
||||
#include "arcade/skill_check.hpp"
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
namespace game::state::play
|
||||
{
|
||||
class Stats
|
||||
{
|
||||
public:
|
||||
void update(Resources&, SkillCheck&, entity::Character&);
|
||||
};
|
||||
}
|
||||
14
src/state/play/style.hpp
Normal file
14
src/state/play/style.hpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../entity/character.hpp"
|
||||
#include "../../resources.hpp"
|
||||
#include "../../util/imgui/style.hpp"
|
||||
|
||||
namespace game::state::play::style
|
||||
{
|
||||
inline void color_set(Resources& resources, const entity::Character& character)
|
||||
{
|
||||
game::util::imgui::style::color_set(resources.settings.isUseCharacterColor ? character.data.color
|
||||
: resources.settings.color);
|
||||
}
|
||||
}
|
||||
@@ -37,10 +37,12 @@ namespace game::state::play
|
||||
index = 0;
|
||||
time = 0.0f;
|
||||
isEnabled = true;
|
||||
character.isTalking = true;
|
||||
if (!dialogueEntry->animation.empty())
|
||||
character.queue_play({.animation = dialogueEntry->animation, .isInterruptible = isInterruptible});
|
||||
if (dialogueEntry->text.empty()) isEnabled = false;
|
||||
if (dialogueEntry->text.empty())
|
||||
isEnabled = false;
|
||||
else
|
||||
character.isTalking = true;
|
||||
}
|
||||
|
||||
void Text::tick(entity::Character& character)
|
||||
@@ -48,6 +50,8 @@ namespace game::state::play
|
||||
if (!entry || isFinished) return;
|
||||
|
||||
index++;
|
||||
auto blipPeriod = character.data.textBlipPeriodBase;
|
||||
if (blipPeriod > 0 && index % blipPeriod == 0) character.data.sounds.blip.play();
|
||||
|
||||
if (index >= ImTextCountCharsFromUtf8(entry->text.c_str(), entry->text.c_str() + entry->text.size()))
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
using namespace game::util;
|
||||
using namespace game::util::imgui;
|
||||
using namespace game::resource::xml;
|
||||
|
||||
namespace game::state::play
|
||||
{
|
||||
@@ -18,6 +19,7 @@ namespace game::state::play
|
||||
auto style = ImGui::GetStyle();
|
||||
auto& io = ImGui::GetIO();
|
||||
auto& schema = character.data.menuSchema;
|
||||
auto& strings = character.data.strings;
|
||||
|
||||
slide.update(isOpen, io.DeltaTime);
|
||||
|
||||
@@ -56,8 +58,9 @@ namespace game::state::play
|
||||
ImGui::PopStyleColor();
|
||||
};
|
||||
|
||||
if (WIDGET_FX(ImGui::Button("Home", buttonSize))) world.character_focus(character, canvas, focus);
|
||||
ImGui::SetItemTooltip("%s", "Reset camera view.\n(Shortcut: Home)");
|
||||
if (WIDGET_FX(ImGui::Button(strings.get(Strings::ToolsHomeButton).c_str(), buttonSize)))
|
||||
world.character_focus(character, canvas, focus);
|
||||
ImGui::SetItemTooltip("%s", strings.get(Strings::ToolsHomeTooltip).c_str());
|
||||
|
||||
for (int i = 0; i < (int)character.data.interactTypeNames.size(); i++)
|
||||
cursor_mode_button(character.data.interactTypeNames[i], i);
|
||||
@@ -82,7 +85,9 @@ namespace game::state::play
|
||||
|
||||
if (t <= 0.0f || t >= 1.0f)
|
||||
{
|
||||
ImGui::SetItemTooltip(isOpen ? "Close Tools" : "Open Tools");
|
||||
ImGui::SetItemTooltip("%s", strings.get(isOpen ? Strings::ToolsCloseTooltip
|
||||
: Strings::ToolsOpenTooltip)
|
||||
.c_str());
|
||||
if (result)
|
||||
{
|
||||
isOpen = !isOpen;
|
||||
|
||||
@@ -62,6 +62,7 @@ namespace game::state::play
|
||||
{
|
||||
static constexpr float MENU_WIDTH_MULTIPLIER = 0.30f;
|
||||
static constexpr float TOOLS_WIDTH_MULTIPLIER = 0.10f;
|
||||
static constexpr float INFO_HEIGHT_MULTIPLIER = 4.0f;
|
||||
static constexpr float PADDING = 100.0f;
|
||||
|
||||
auto rect = character.rect();
|
||||
@@ -72,13 +73,18 @@ namespace game::state::play
|
||||
|
||||
rect = {rect.x - PADDING * 0.5f, rect.y - PADDING * 0.5f, rect.z + PADDING, rect.w + PADDING};
|
||||
|
||||
auto zoomFactor = std::min((float)canvas.size.x / rect.z, (float)canvas.size.y / rect.w);
|
||||
auto infoHeightPixels =
|
||||
ImGui::GetTextLineHeightWithSpacing() * INFO_HEIGHT_MULTIPLIER + ImGui::GetStyle().WindowPadding.y * 2.0f;
|
||||
auto usableHeightPixels = std::max(1.0f, (float)canvas.size.y - infoHeightPixels);
|
||||
|
||||
auto zoomFactor = std::min((float)canvas.size.x / rect.z, usableHeightPixels / rect.w);
|
||||
canvas.zoom = glm::clamp(ZOOM_MIN, math::to_percent(zoomFactor), ZOOM_MAX);
|
||||
zoomFactor = math::to_unit(canvas.zoom);
|
||||
|
||||
auto rectCenter = glm::vec2(rect.x + rect.z * 0.5f, rect.y + rect.w * 0.5f);
|
||||
auto viewSizeWorld = glm::vec2(canvas.size) / zoomFactor;
|
||||
canvas.pan = rectCenter - (vec2(viewSizeWorld.x, viewSizeWorld.y) * 0.5f);
|
||||
auto infoHeightWorld = infoHeightPixels / zoomFactor;
|
||||
canvas.pan = rectCenter - vec2(viewSizeWorld.x * 0.5f, (viewSizeWorld.y + infoHeightWorld) * 0.5f);
|
||||
auto menuWidthWorld = (canvas.size.x * MENU_WIDTH_MULTIPLIER) / zoomFactor;
|
||||
auto toolsWidthWorld = (canvas.size.x * TOOLS_WIDTH_MULTIPLIER) / zoomFactor;
|
||||
|
||||
|
||||
@@ -47,38 +47,51 @@ namespace game::state::select
|
||||
ImGui::TextUnformatted(character.name.c_str());
|
||||
ImGui::PopFont();
|
||||
|
||||
if (!character.description.empty())
|
||||
{
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetColorU32(imgui::to_imvec4(color::GRAY)));
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::BIG);
|
||||
ImGui::TextWrapped("%s", character.description.c_str());
|
||||
ImGui::PopFont();
|
||||
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::BIG);
|
||||
|
||||
ImGui::Text("Weight: %0.2f %s", system == IMPERIAL ? weight * KG_TO_LB : weight,
|
||||
system == IMPERIAL ? "lbs" : "kg");
|
||||
ImGui::Text("Stages: %i", character.stages);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::PopFont();
|
||||
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::NORMAL);
|
||||
if (ImGui::BeginTabBar("##Preview Tabs"))
|
||||
{
|
||||
if (ImGui::BeginTabItem("Overview"))
|
||||
{
|
||||
if (!character.description.empty())
|
||||
{
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetColorU32(imgui::to_imvec4(color::GRAY)));
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetColorU32(imgui::to_imvec4(color::GRAY)));
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::HEADER_2);
|
||||
ImGui::TextWrapped("%s", character.description.c_str());
|
||||
ImGui::PopFont();
|
||||
|
||||
if (!character.author.empty()) ImGui::TextWrapped("Author: %s", character.author.c_str());
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::HEADER_2);
|
||||
|
||||
ImGui::Text("Weight: %0.2f %s", system == IMPERIAL ? weight * KG_TO_LB : weight,
|
||||
system == IMPERIAL ? "lbs" : "kg");
|
||||
ImGui::Text("Stages: %i", character.stages);
|
||||
|
||||
ImGui::PopFont();
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (ImGui::BeginTabItem("Credits"))
|
||||
{
|
||||
ImGui::Separator();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetColorU32(imgui::to_imvec4(color::GRAY)));
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::HEADER_2);
|
||||
if (!character.credits.empty())
|
||||
ImGui::TextWrapped("%s", character.credits.c_str());
|
||||
else
|
||||
ImGui::TextUnformatted("No credits listed.");
|
||||
ImGui::PopFont();
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
ImGui::PopFont();
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace game::state::select
|
||||
|
||||
auto renderSize = ImVec2(textureSize.x * scale, textureSize.y * scale);
|
||||
|
||||
ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPosX() + (availableSize.x * 0.5f) - (renderSize.y * 0.5f),
|
||||
ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPosX() + (availableSize.x * 0.5f) - (renderSize.x * 0.5f),
|
||||
ImGui::GetCursorPosY() + (availableSize.y * 0.5f) - (renderSize.y * 0.5f)));
|
||||
|
||||
ImGui::Image(character.render.id, renderSize);
|
||||
|
||||
@@ -10,47 +10,61 @@
|
||||
|
||||
using namespace game::util;
|
||||
using namespace game::util::imgui;
|
||||
using namespace game::resource::xml;
|
||||
|
||||
namespace game::state
|
||||
{
|
||||
void SettingsMenu::update(Resources& resources, Mode mode)
|
||||
void SettingsMenu::update(Resources& resources, Mode mode, const Strings* strings)
|
||||
{
|
||||
auto& settings = resources.settings;
|
||||
auto& measurementSystem = settings.measurementSystem;
|
||||
auto& volume = settings.volume;
|
||||
auto& color = settings.color;
|
||||
auto string_get = [&](Strings::Type type, const char* fallback) -> const char*
|
||||
{
|
||||
return strings ? strings->get(type).c_str() : fallback;
|
||||
};
|
||||
|
||||
isJustColorSet = false;
|
||||
|
||||
ImGui::SeparatorText("Measurement System");
|
||||
WIDGET_FX(ImGui::RadioButton("Metric", (int*)&measurementSystem, measurement::METRIC));
|
||||
ImGui::SetItemTooltip("%s", "Use kilograms (kg).");
|
||||
ImGui::SeparatorText(string_get(Strings::SettingsMeasurementSystem, "Measurement System"));
|
||||
WIDGET_FX(ImGui::RadioButton(string_get(Strings::SettingsMetric, "Metric"),
|
||||
(int*)&measurementSystem, measurement::METRIC));
|
||||
ImGui::SetItemTooltip("%s", string_get(Strings::SettingsMetricTooltip, "Use kilograms (kg)."));
|
||||
ImGui::SameLine();
|
||||
WIDGET_FX(ImGui::RadioButton("Imperial", (int*)&measurementSystem, measurement::IMPERIAL));
|
||||
ImGui::SetItemTooltip("%s", "Use pounds (lbs).");
|
||||
WIDGET_FX(ImGui::RadioButton(string_get(Strings::SettingsImperial, "Imperial"),
|
||||
(int*)&measurementSystem, measurement::IMPERIAL));
|
||||
ImGui::SetItemTooltip("%s", string_get(Strings::SettingsImperialTooltip, "Use pounds (lbs)."));
|
||||
|
||||
ImGui::SeparatorText("Sound");
|
||||
if (WIDGET_FX(ImGui::SliderInt("Volume", &volume, 0, 100, "%d%%")))
|
||||
ImGui::SeparatorText(string_get(Strings::SettingsSound, "Sound"));
|
||||
if (WIDGET_FX(
|
||||
ImGui::SliderInt(string_get(Strings::SettingsVolume, "Volume"), &volume, 0, 100, "%d%%")))
|
||||
resources.volume_set(math::to_unit((float)volume));
|
||||
ImGui::SetItemTooltip("%s", "Adjust master volume.");
|
||||
ImGui::SetItemTooltip("%s", string_get(Strings::SettingsVolumeTooltip, "Adjust master volume."));
|
||||
|
||||
ImGui::SeparatorText("Appearance");
|
||||
ImGui::SeparatorText(string_get(Strings::SettingsAppearance, "Appearance"));
|
||||
|
||||
if (WIDGET_FX(ImGui::Checkbox("Use Character Color", &settings.isUseCharacterColor))) isJustColorSet = true;
|
||||
ImGui::SetItemTooltip("When playing, the UI will use the character's preset UI color.");
|
||||
if (WIDGET_FX(ImGui::Checkbox(string_get(Strings::SettingsUseCharacterColor,
|
||||
"Use Character Color"),
|
||||
&settings.isUseCharacterColor)))
|
||||
isJustColorSet = true;
|
||||
ImGui::SetItemTooltip("%s", string_get(Strings::SettingsUseCharacterColorTooltip,
|
||||
"When playing, the UI will use the character's preset UI color."));
|
||||
ImGui::SameLine();
|
||||
ImGui::BeginDisabled(settings.isUseCharacterColor);
|
||||
if (WIDGET_FX(
|
||||
ImGui::ColorEdit3("Color", value_ptr(color), ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoTooltip)))
|
||||
ImGui::ColorEdit3(string_get(Strings::SettingsColor, "Color"), value_ptr(color),
|
||||
ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoTooltip)))
|
||||
{
|
||||
style::color_set(color);
|
||||
isJustColorSet = true;
|
||||
}
|
||||
ImGui::SetItemTooltip("%s", "Change the UI color.");
|
||||
ImGui::SetItemTooltip("%s", string_get(Strings::SettingsColorTooltip, "Change the UI color."));
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::Separator();
|
||||
if (WIDGET_FX(ImGui::Button("Reset to Default", ImVec2(-FLT_MIN, 0))))
|
||||
if (WIDGET_FX(ImGui::Button(string_get(Strings::SettingsResetButton, "Reset to Default"),
|
||||
ImVec2(-FLT_MIN, 0))))
|
||||
{
|
||||
settings = resource::xml::Settings();
|
||||
style::color_set(settings.color);
|
||||
@@ -60,11 +74,19 @@ namespace game::state
|
||||
{
|
||||
ImGui::Separator();
|
||||
|
||||
if (WIDGET_FX(ImGui::Button("Save", ImVec2(-FLT_MIN, 0)))) isSave = true;
|
||||
ImGui::SetItemTooltip("%s", "Save the game.\n(Note: the game autosaves frequently.)");
|
||||
if (WIDGET_FX(
|
||||
ImGui::Button(string_get(Strings::SettingsSaveButton, "Save"), ImVec2(-FLT_MIN, 0))))
|
||||
isSave = true;
|
||||
ImGui::SetItemTooltip(
|
||||
"%s", string_get(Strings::SettingsSaveTooltip,
|
||||
"Save the game.\n(Note: the game autosaves frequently.)"));
|
||||
|
||||
if (WIDGET_FX(ImGui::Button("Return to Characters", ImVec2(-FLT_MIN, 0)))) isGoToSelect = true;
|
||||
ImGui::SetItemTooltip("%s", "Go back to the character selection screen.\nProgress will be saved.");
|
||||
if (WIDGET_FX(ImGui::Button(
|
||||
string_get(Strings::SettingsReturnToCharactersButton, "Return to Characters"),
|
||||
ImVec2(-FLT_MIN, 0))))
|
||||
isGoToSelect = true;
|
||||
ImGui::SetItemTooltip("%s", string_get(Strings::SettingsReturnToCharactersTooltip,
|
||||
"Go back to the character selection screen.\nProgress will be saved."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../resource/xml/strings.hpp"
|
||||
#include "../resources.hpp"
|
||||
|
||||
namespace game::state
|
||||
@@ -17,6 +18,6 @@ namespace game::state
|
||||
bool isSave{};
|
||||
bool isJustColorSet{};
|
||||
|
||||
void update(Resources&, Mode = SELECT);
|
||||
void update(Resources&, Mode = SELECT, const resource::xml::Strings* = nullptr);
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user