Inventory updates, API updates, lots of file renaming
This commit is contained in:
@@ -109,10 +109,12 @@ set (TINYXML2_SOURCES ${TINYXML2_DIR}/tinyxml2.cpp)
|
||||
file(GLOB PROJECT_SRC CONFIGURE_DEPENDS
|
||||
include/*.cpp
|
||||
src/*.cpp
|
||||
src/render/*.cpp
|
||||
src/resource/*.cpp
|
||||
src/resource/xml/*.cpp
|
||||
src/state/*.cpp
|
||||
src/state/main/*.cpp
|
||||
src/state/play/*.cpp
|
||||
src/state/play/arcade/*.cpp
|
||||
src/state/select/*.cpp
|
||||
src/entity/*.cpp
|
||||
src/window/*.cpp
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
#include "../canvas.hpp"
|
||||
#include "../render/canvas.hpp"
|
||||
#include "../resource/xml/anm2.hpp"
|
||||
|
||||
namespace game::entity
|
||||
|
||||
@@ -335,12 +335,14 @@ namespace game::entity
|
||||
|
||||
void Character::queue_play(QueuedPlay play)
|
||||
{
|
||||
if (isStageUp) return;
|
||||
queuedPlay = play;
|
||||
queuedPlay.animation = animation_name_convert(queuedPlay.animation);
|
||||
}
|
||||
|
||||
void Character::queue_idle_animation()
|
||||
{
|
||||
if (isStageUp) return;
|
||||
if (data.animations.idle.empty()) return;
|
||||
queue_play(
|
||||
{is_over_capacity() && !data.animations.idleFull.empty() ? data.animations.idleFull : data.animations.idle});
|
||||
@@ -348,6 +350,7 @@ namespace game::entity
|
||||
|
||||
void Character::queue_interact_area_animation(resource::xml::Character::InteractArea& interactArea)
|
||||
{
|
||||
if (isStageUp) return;
|
||||
if (interactArea.animation.empty()) return;
|
||||
queue_play({is_over_capacity() && !interactArea.animationFull.empty() ? interactArea.animationFull
|
||||
: interactArea.animation});
|
||||
|
||||
@@ -47,6 +47,7 @@ namespace game::entity
|
||||
std::vector<int> animationBlinkDurations{};
|
||||
|
||||
bool isStageUp{};
|
||||
bool isStageUpDuring{};
|
||||
bool isJustStageUp{};
|
||||
bool isJustStageFinal{};
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "../util/interact_type.hpp"
|
||||
#include "actor.hpp"
|
||||
|
||||
namespace game::entity
|
||||
@@ -16,7 +15,7 @@ namespace game::entity
|
||||
};
|
||||
|
||||
State state{DEFAULT};
|
||||
InteractType mode{InteractType::RUB};
|
||||
int interactTypeID{-1};
|
||||
|
||||
Cursor() = default;
|
||||
Cursor(resource::xml::Anm2&);
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "util/imgui.hpp"
|
||||
#include "util/math.hpp"
|
||||
#include "../util/imgui.hpp"
|
||||
#include "../util/math.hpp"
|
||||
|
||||
using namespace glm;
|
||||
using namespace game::resource;
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <glad/glad.h>
|
||||
#endif
|
||||
|
||||
#include "resource/shader.hpp"
|
||||
#include "../resource/shader.hpp"
|
||||
#include <glm/ext/matrix_clip_space.hpp>
|
||||
#include <glm/ext/matrix_transform.hpp>
|
||||
#include <glm/glm.hpp>
|
||||
@@ -41,6 +41,8 @@ namespace game::resource::xml
|
||||
query_anm2(root, "Anm2", archive, textureRootPath, anm2);
|
||||
query_string_attribute(root, "Name", &name);
|
||||
|
||||
query_vec3(root, "ColorR", "ColorG", "ColorB", color);
|
||||
|
||||
root->QueryFloatAttribute("Weight", &weight);
|
||||
|
||||
root->QueryFloatAttribute("Capacity", &capacity);
|
||||
@@ -159,6 +161,15 @@ namespace game::resource::xml
|
||||
|
||||
if (auto element = root->FirstChildElement("InteractAreas"))
|
||||
{
|
||||
auto interact_type_id_get = [&](const std::string& typeName)
|
||||
{
|
||||
for (int i = 0; i < (int)interactTypeNames.size(); i++)
|
||||
if (interactTypeNames[i] == typeName) return i;
|
||||
|
||||
interactTypeNames.emplace_back(typeName);
|
||||
return (int)interactTypeNames.size() - 1;
|
||||
};
|
||||
|
||||
for (auto child = element->FirstChildElement("InteractArea"); child;
|
||||
child = child->NextSiblingElement("InteractArea"))
|
||||
{
|
||||
@@ -173,6 +184,7 @@ namespace game::resource::xml
|
||||
query_string_attribute(child, "AnimationCursorActive", &interactArea.animationCursorActive);
|
||||
query_sound_entry_collection(child, "Sound", archive, soundRootPath, interactArea.sound, "Path");
|
||||
dialogue.query_pool_id(child, "DialoguePoolID", interactArea.pool.id);
|
||||
query_bool_attribute(child, "IsHold", &interactArea.isHold);
|
||||
child->QueryFloatAttribute("DigestionBonusRub", &interactArea.digestionBonusRub);
|
||||
child->QueryFloatAttribute("DigestionBonusClick", &interactArea.digestionBonusClick);
|
||||
child->QueryFloatAttribute("Time", &interactArea.time);
|
||||
@@ -181,9 +193,7 @@ namespace game::resource::xml
|
||||
|
||||
std::string typeString{};
|
||||
query_string_attribute(child, "Type", &typeString);
|
||||
|
||||
for (int i = 0; i < (int)std::size(INTERACT_TYPE_STRINGS); i++)
|
||||
if (typeString == INTERACT_TYPE_STRINGS[i]) interactArea.type = (InteractType)i;
|
||||
if (!typeString.empty()) interactArea.typeID = interact_type_id_get(typeString);
|
||||
|
||||
interactAreas.emplace_back(std::move(interactArea));
|
||||
}
|
||||
@@ -210,10 +220,10 @@ namespace game::resource::xml
|
||||
else
|
||||
logger.warning(std::format("No character cursor.xml file found: {}", path.string()));
|
||||
|
||||
if (auto playSchemaPath = physfs::Path(archive + "/" + "play.xml"); playSchemaPath.is_valid())
|
||||
playSchema = Play(playSchemaPath, dialogue);
|
||||
if (auto skillCheckSchemaPath = physfs::Path(archive + "/" + "skill_check.xml"); skillCheckSchemaPath.is_valid())
|
||||
skillCheckSchema = SkillCheck(skillCheckSchemaPath, dialogue);
|
||||
else
|
||||
logger.warning(std::format("No character play.xml file found: {}", path.string()));
|
||||
logger.warning(std::format("No character skill_check.xml file found: {}", path.string()));
|
||||
|
||||
logger.info(std::format("Initialized character: {}", name));
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <filesystem>
|
||||
#include <vector>
|
||||
|
||||
#include "../../util/interact_type.hpp"
|
||||
#include "../audio.hpp"
|
||||
#include "animation_entry.hpp"
|
||||
#include "anm2.hpp"
|
||||
@@ -12,7 +11,7 @@
|
||||
#include "dialogue.hpp"
|
||||
#include "item.hpp"
|
||||
#include "menu.hpp"
|
||||
#include "play.hpp"
|
||||
#include "skill_check.hpp"
|
||||
#include "save.hpp"
|
||||
|
||||
namespace game::resource::xml
|
||||
@@ -51,7 +50,8 @@ namespace game::resource::xml
|
||||
|
||||
int nullID{-1};
|
||||
int layerID{-1};
|
||||
InteractType type{(InteractType)-1};
|
||||
int typeID{-1};
|
||||
bool isHold{};
|
||||
Dialogue::PoolReference pool{-1};
|
||||
|
||||
float digestionBonusRub{};
|
||||
@@ -97,7 +97,7 @@ namespace game::resource::xml
|
||||
Item itemSchema{};
|
||||
Menu menuSchema{};
|
||||
Cursor cursorSchema{};
|
||||
Play playSchema{};
|
||||
SkillCheck skillCheckSchema{};
|
||||
|
||||
Save save{};
|
||||
|
||||
@@ -107,9 +107,12 @@ namespace game::resource::xml
|
||||
|
||||
Sounds sounds{};
|
||||
|
||||
glm::vec3 color{0.120f, 0.515f, 0.115f};
|
||||
|
||||
std::vector<Stage> stages{};
|
||||
std::vector<ExpandArea> expandAreas{};
|
||||
std::vector<EatArea> eatAreas{};
|
||||
std::vector<std::string> interactTypeNames{};
|
||||
std::vector<InteractArea> interactAreas{};
|
||||
|
||||
AlternateSpritesheet alternateSpritesheet{};
|
||||
|
||||
@@ -42,6 +42,7 @@ namespace game::resource::xml
|
||||
query_string_attribute(root, "Name", &name);
|
||||
query_string_attribute(root, "Description", &description);
|
||||
query_string_attribute(root, "Author", &author);
|
||||
query_vec3(root, "ColorR", "ColorG", "ColorB", color);
|
||||
root->QueryFloatAttribute("Weight", &weight);
|
||||
|
||||
if (auto element = root->FirstChildElement("Stages"))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <glm/glm.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -22,6 +23,7 @@ namespace game::resource::xml
|
||||
Texture portrait{};
|
||||
Texture render{};
|
||||
Save save{};
|
||||
glm::vec3 color{0.120f, 0.515f, 0.115f};
|
||||
|
||||
int stages{1};
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@ namespace game::resource::xml
|
||||
query_int_optional_attribute(child, "UpgradeCount", item.upgradeCount);
|
||||
}
|
||||
|
||||
query_bool_attribute(child, "IsPlayReward", &item.isPlayReward);
|
||||
query_bool_attribute(child, "IsSkillCheckReward", &item.isSkillCheckReward);
|
||||
query_bool_attribute(child, "IsToggleSpritesheet", &item.isToggleSpritesheet);
|
||||
|
||||
std::string categoryString{};
|
||||
@@ -173,7 +173,7 @@ namespace game::resource::xml
|
||||
{
|
||||
auto& item = items[i];
|
||||
pools[item.rarityID].emplace_back(i);
|
||||
if (item.isPlayReward) rewardItemPool.emplace_back(i);
|
||||
if (item.isSkillCheckReward) skillCheckRewardItemPool.emplace_back(i);
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)rarities.size(); i++)
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace game::resource::xml
|
||||
std::optional<float> digestionBonus{};
|
||||
std::optional<float> gravity{};
|
||||
std::optional<int> chewCount{};
|
||||
bool isPlayReward{};
|
||||
bool isSkillCheckReward{};
|
||||
bool isToggleSpritesheet{};
|
||||
};
|
||||
|
||||
@@ -85,7 +85,7 @@ namespace game::resource::xml
|
||||
|
||||
std::vector<int> rarityIDsSortedByChance{};
|
||||
std::unordered_map<int, Pool> pools{};
|
||||
Pool rewardItemPool{};
|
||||
Pool skillCheckRewardItemPool{};
|
||||
|
||||
Animations animations{};
|
||||
Sounds sounds{};
|
||||
|
||||
@@ -22,15 +22,13 @@ namespace game::resource::xml
|
||||
XMLDocument document;
|
||||
auto pathString = path.string();
|
||||
|
||||
// Fail silently if there's no save.
|
||||
auto result = document.LoadFile(pathString.c_str());
|
||||
|
||||
if (result == XML_ERROR_FILE_NOT_FOUND || result == XML_ERROR_FILE_COULD_NOT_BE_OPENED) return;
|
||||
|
||||
if (result != XML_SUCCESS)
|
||||
{
|
||||
logger.error(
|
||||
std::format("Could not initialize character save file: {} ({})", pathString, document.ErrorStr()));
|
||||
logger.error(std::format("Could not initialize character save file: {} ({})", pathString, document.ErrorStr()));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -54,7 +52,9 @@ namespace game::resource::xml
|
||||
element->QueryIntAttribute("TotalFoodItemsEaten", &totalFoodItemsEaten);
|
||||
}
|
||||
|
||||
if (auto element = root->FirstChildElement("Play"))
|
||||
auto element = root->FirstChildElement("SkillCheck");
|
||||
if (!element) element = root->FirstChildElement("Play");
|
||||
if (element)
|
||||
{
|
||||
element->QueryIntAttribute("TotalPlays", &totalPlays);
|
||||
element->QueryIntAttribute("HighScore", &highScore);
|
||||
@@ -130,13 +130,13 @@ namespace game::resource::xml
|
||||
characterElement->SetAttribute("TotalCaloriesConsumed", totalCaloriesConsumed);
|
||||
characterElement->SetAttribute("TotalFoodItemsEaten", totalFoodItemsEaten);
|
||||
|
||||
auto playElement = element->InsertNewChildElement("Play");
|
||||
auto skillCheckElement = element->InsertNewChildElement("SkillCheck");
|
||||
|
||||
playElement->SetAttribute("TotalPlays", totalPlays);
|
||||
playElement->SetAttribute("HighScore", highScore);
|
||||
playElement->SetAttribute("BestCombo", bestCombo);
|
||||
skillCheckElement->SetAttribute("TotalPlays", totalPlays);
|
||||
skillCheckElement->SetAttribute("HighScore", highScore);
|
||||
skillCheckElement->SetAttribute("BestCombo", bestCombo);
|
||||
|
||||
auto gradesElement = playElement->InsertNewChildElement("Grades");
|
||||
auto gradesElement = skillCheckElement->InsertNewChildElement("Grades");
|
||||
|
||||
for (auto& [i, count] : gradeCounts)
|
||||
{
|
||||
|
||||
@@ -23,8 +23,7 @@ namespace game::resource::xml
|
||||
|
||||
if (document.LoadFile(pathString.c_str()) != XML_SUCCESS)
|
||||
{
|
||||
logger.error(
|
||||
std::format("Could not initialize character save file: {} ({})", pathString, document.ErrorStr()));
|
||||
logger.error(std::format("Could not initialize character save file: {} ({})", pathString, document.ErrorStr()));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -34,13 +33,10 @@ namespace game::resource::xml
|
||||
query_string_attribute(root, "MeasurementSystem", &measurementSystemString);
|
||||
measurementSystem = measurementSystemString == "Imperial" ? measurement::IMPERIAL : measurement::METRIC;
|
||||
root->QueryIntAttribute("Volume", &volume);
|
||||
root->QueryFloatAttribute("ColorR", &color.r);
|
||||
root->QueryFloatAttribute("ColorG", &color.g);
|
||||
root->QueryFloatAttribute("ColorB", &color.b);
|
||||
root->QueryFloatAttribute("WindowX", &windowPosition.x);
|
||||
root->QueryFloatAttribute("WindowY", &windowPosition.y);
|
||||
root->QueryIntAttribute("WindowW", &windowSize.x);
|
||||
root->QueryIntAttribute("WindowH", &windowSize.y);
|
||||
query_vec3(root, "ColorR", "ColorG", "ColorB", color);
|
||||
query_vec2(root, "WindowX", "WindowY", windowPosition);
|
||||
query_ivec2(root, "WindowW", "WindowH", windowSize);
|
||||
query_bool_attribute(root, "IsUseCharacterColor", &isUseCharacterColor);
|
||||
}
|
||||
|
||||
logger.info(std::format("Initialized settings: {}", pathString));
|
||||
@@ -59,13 +55,10 @@ namespace game::resource::xml
|
||||
|
||||
element->SetAttribute("MeasurementSystem", measurementSystem == measurement::IMPERIAL ? "Imperial" : "Metric");
|
||||
element->SetAttribute("Volume", volume);
|
||||
element->SetAttribute("ColorR", color.r);
|
||||
element->SetAttribute("ColorG", color.g);
|
||||
element->SetAttribute("ColorB", color.b);
|
||||
element->SetAttribute("WindowX", windowPosition.x);
|
||||
element->SetAttribute("WindowY", windowPosition.y);
|
||||
element->SetAttribute("WindowW", windowSize.x);
|
||||
element->SetAttribute("WindowH", windowSize.y);
|
||||
set_vec3_attribute(element, "ColorR", "ColorG", "ColorB", color);
|
||||
set_vec2_attribute(element, "WindowX", "WindowY", windowPosition);
|
||||
set_ivec2_attribute(element, "WindowW", "WindowH", windowSize);
|
||||
set_bool_attribute(element, "IsUseCharacterColor", isUseCharacterColor);
|
||||
|
||||
document.InsertFirstChild(element);
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ namespace game::resource::xml
|
||||
|
||||
util::measurement::System measurementSystem{util::measurement::METRIC};
|
||||
int volume{50};
|
||||
bool isUseCharacterColor{true};
|
||||
|
||||
glm::vec3 color{0.120f, 0.515f, 0.115f};
|
||||
glm::ivec2 windowSize{1600, 900};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "play.hpp"
|
||||
#include "skill_check.hpp"
|
||||
|
||||
#include "../../log.hpp"
|
||||
#include "util.hpp"
|
||||
@@ -10,7 +10,7 @@ using namespace game::util;
|
||||
|
||||
namespace game::resource::xml
|
||||
{
|
||||
Play::Play(const physfs::Path& path, Dialogue& dialogue)
|
||||
SkillCheck::SkillCheck(const physfs::Path& path, Dialogue& dialogue)
|
||||
{
|
||||
XMLDocument document;
|
||||
|
||||
@@ -62,8 +62,8 @@ namespace game::resource::xml
|
||||
}
|
||||
|
||||
isValid = true;
|
||||
logger.info(std::format("Initialized play schema: {}", path.c_str()));
|
||||
logger.info(std::format("Initialized skill check schema: {}", path.c_str()));
|
||||
}
|
||||
|
||||
bool Play::is_valid() const { return isValid; };
|
||||
bool SkillCheck::is_valid() const { return isValid; };
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
namespace game::resource::xml
|
||||
{
|
||||
class Play
|
||||
class SkillCheck
|
||||
{
|
||||
public:
|
||||
struct Grade
|
||||
@@ -48,8 +48,8 @@ namespace game::resource::xml
|
||||
|
||||
bool isValid{};
|
||||
|
||||
Play() = default;
|
||||
Play(const util::physfs::Path&, Dialogue&);
|
||||
SkillCheck() = default;
|
||||
SkillCheck(const util::physfs::Path&, Dialogue&);
|
||||
|
||||
bool is_valid() const;
|
||||
};
|
||||
@@ -12,6 +12,8 @@ using namespace game::util;
|
||||
|
||||
namespace game::resource::xml
|
||||
{
|
||||
XMLError query_result_merge(XMLError result, XMLError next) { return result == XML_SUCCESS ? next : result; }
|
||||
|
||||
XMLError query_string_attribute(XMLElement* element, const char* attribute, std::string* value)
|
||||
{
|
||||
const char* temp = nullptr;
|
||||
@@ -45,6 +47,60 @@ namespace game::resource::xml
|
||||
return result;
|
||||
}
|
||||
|
||||
XMLError query_ivec2(XMLElement* element, const char* attributeX, const char* attributeY, glm::ivec2& value)
|
||||
{
|
||||
auto result = element->QueryIntAttribute(attributeX, &value.x);
|
||||
result = query_result_merge(result, element->QueryIntAttribute(attributeY, &value.y));
|
||||
return result;
|
||||
}
|
||||
|
||||
XMLError query_vec2(XMLElement* element, const char* attributeX, const char* attributeY, glm::vec2& value)
|
||||
{
|
||||
auto result = element->QueryFloatAttribute(attributeX, &value.x);
|
||||
result = query_result_merge(result, element->QueryFloatAttribute(attributeY, &value.y));
|
||||
return result;
|
||||
}
|
||||
|
||||
XMLError query_vec3(XMLElement* element, const char* attributeX, const char* attributeY, const char* attributeZ,
|
||||
glm::vec3& value)
|
||||
{
|
||||
auto result = element->QueryFloatAttribute(attributeX, &value.x);
|
||||
result = query_result_merge(result, element->QueryFloatAttribute(attributeY, &value.y));
|
||||
result = query_result_merge(result, element->QueryFloatAttribute(attributeZ, &value.z));
|
||||
return result;
|
||||
}
|
||||
|
||||
XMLError set_bool_attribute(XMLElement* element, const char* attribute, bool value)
|
||||
{
|
||||
element->SetAttribute(attribute, value ? "true" : "false");
|
||||
return XML_SUCCESS;
|
||||
}
|
||||
|
||||
XMLError set_ivec2_attribute(XMLElement* element, const char* attributeX, const char* attributeY,
|
||||
const glm::ivec2& value)
|
||||
{
|
||||
element->SetAttribute(attributeX, value.x);
|
||||
element->SetAttribute(attributeY, value.y);
|
||||
return XML_SUCCESS;
|
||||
}
|
||||
|
||||
XMLError set_vec2_attribute(XMLElement* element, const char* attributeX, const char* attributeY,
|
||||
const glm::vec2& value)
|
||||
{
|
||||
element->SetAttribute(attributeX, value.x);
|
||||
element->SetAttribute(attributeY, value.y);
|
||||
return XML_SUCCESS;
|
||||
}
|
||||
|
||||
XMLError set_vec3_attribute(XMLElement* element, const char* attributeX, const char* attributeY,
|
||||
const char* attributeZ, const glm::vec3& value)
|
||||
{
|
||||
element->SetAttribute(attributeX, value.x);
|
||||
element->SetAttribute(attributeY, value.y);
|
||||
element->SetAttribute(attributeZ, value.z);
|
||||
return XML_SUCCESS;
|
||||
}
|
||||
|
||||
XMLError query_float_optional_attribute(XMLElement* element, const char* attribute, std::optional<float>& value)
|
||||
{
|
||||
value.emplace();
|
||||
@@ -84,102 +140,139 @@ namespace game::resource::xml
|
||||
return result;
|
||||
}
|
||||
|
||||
void query_event_id(XMLElement* element, const char* name, const Anm2& anm2, int& eventID)
|
||||
XMLError query_event_id(XMLElement* element, const char* name, const Anm2& anm2, int& eventID)
|
||||
{
|
||||
std::string string{};
|
||||
query_string_attribute(element, name, &string);
|
||||
auto result = query_string_attribute(element, name, &string);
|
||||
if (result != XML_SUCCESS) return result;
|
||||
|
||||
if (anm2.eventMap.contains(string))
|
||||
{
|
||||
eventID = anm2.eventMap.at(string);
|
||||
return XML_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.error(std::format("Could not query anm2 event ID: {} ({})", string, anm2.path));
|
||||
eventID = -1;
|
||||
return XML_ERROR_PARSING_ATTRIBUTE;
|
||||
}
|
||||
}
|
||||
|
||||
void query_layer_id(XMLElement* element, const char* name, const Anm2& anm2, int& layerID)
|
||||
XMLError query_layer_id(XMLElement* element, const char* name, const Anm2& anm2, int& layerID)
|
||||
{
|
||||
std::string string{};
|
||||
query_string_attribute(element, name, &string);
|
||||
auto result = query_string_attribute(element, name, &string);
|
||||
if (result != XML_SUCCESS) return result;
|
||||
|
||||
if (anm2.layerMap.contains(string))
|
||||
{
|
||||
layerID = anm2.layerMap.at(string);
|
||||
return XML_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.error(std::format("Could not query anm2 layer ID: {} ({})", string, anm2.path));
|
||||
layerID = -1;
|
||||
return XML_ERROR_PARSING_ATTRIBUTE;
|
||||
}
|
||||
}
|
||||
|
||||
void query_null_id(XMLElement* element, const char* name, const Anm2& anm2, int& nullID)
|
||||
XMLError query_null_id(XMLElement* element, const char* name, const Anm2& anm2, int& nullID)
|
||||
{
|
||||
std::string string{};
|
||||
query_string_attribute(element, name, &string);
|
||||
auto result = query_string_attribute(element, name, &string);
|
||||
if (result != XML_SUCCESS) return result;
|
||||
|
||||
if (anm2.nullMap.contains(string))
|
||||
{
|
||||
nullID = anm2.nullMap.at(string);
|
||||
return XML_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.error(std::format("Could not query anm2 null ID: {} ({})", string, anm2.path));
|
||||
nullID = -1;
|
||||
return XML_ERROR_PARSING_ATTRIBUTE;
|
||||
}
|
||||
}
|
||||
|
||||
void query_anm2(XMLElement* element, const char* name, const std::string& archive, const std::string& rootPath,
|
||||
Anm2& anm2, Anm2::Flags flags)
|
||||
XMLError query_anm2(XMLElement* element, const char* name, const std::string& archive, const std::string& rootPath,
|
||||
Anm2& anm2, Anm2::Flags flags)
|
||||
{
|
||||
std::string string{};
|
||||
query_string_attribute(element, name, &string);
|
||||
auto result = query_string_attribute(element, name, &string);
|
||||
if (result != XML_SUCCESS) return result;
|
||||
|
||||
anm2 = Anm2(physfs::Path(archive + "/" + rootPath + "/" + string), flags);
|
||||
return XML_SUCCESS;
|
||||
}
|
||||
|
||||
void query_texture(XMLElement* element, const char* name, const std::string& archive, const std::string& rootPath,
|
||||
Texture& texture)
|
||||
XMLError query_texture(XMLElement* element, const char* name, const std::string& archive, const std::string& rootPath,
|
||||
Texture& texture)
|
||||
{
|
||||
std::string string{};
|
||||
query_string_attribute(element, name, &string);
|
||||
auto result = query_string_attribute(element, name, &string);
|
||||
if (result != XML_SUCCESS) return result;
|
||||
|
||||
texture = Texture(physfs::Path(archive + "/" + rootPath + "/" + string));
|
||||
return XML_SUCCESS;
|
||||
}
|
||||
|
||||
void query_sound(XMLElement* element, const char* name, const std::string& archive, const std::string& rootPath,
|
||||
Audio& sound)
|
||||
XMLError query_sound(XMLElement* element, const char* name, const std::string& archive, const std::string& rootPath,
|
||||
Audio& sound)
|
||||
{
|
||||
std::string string{};
|
||||
query_string_attribute(element, name, &string);
|
||||
auto result = query_string_attribute(element, name, &string);
|
||||
if (result != XML_SUCCESS) return result;
|
||||
|
||||
sound = Audio(physfs::Path(archive + "/" + rootPath + "/" + string));
|
||||
return XML_SUCCESS;
|
||||
}
|
||||
|
||||
void query_font(XMLElement* element, const char* name, const std::string& archive, const std::string& rootPath,
|
||||
Font& font)
|
||||
XMLError query_font(XMLElement* element, const char* name, const std::string& archive, const std::string& rootPath,
|
||||
Font& font)
|
||||
{
|
||||
std::string string{};
|
||||
query_string_attribute(element, name, &string);
|
||||
auto result = query_string_attribute(element, name, &string);
|
||||
if (result != XML_SUCCESS) return result;
|
||||
|
||||
font = Font(physfs::Path(archive + "/" + rootPath + "/" + string));
|
||||
return XML_SUCCESS;
|
||||
}
|
||||
|
||||
void query_animation_entry(XMLElement* element, AnimationEntry& animationEntry)
|
||||
XMLError query_animation_entry(XMLElement* element, AnimationEntry& animationEntry)
|
||||
{
|
||||
query_string_attribute(element, "Animation", &animationEntry.animation);
|
||||
element->QueryFloatAttribute("Weight", &animationEntry.weight);
|
||||
auto result = query_string_attribute(element, "Animation", &animationEntry.animation);
|
||||
result = query_result_merge(result, element->QueryFloatAttribute("Weight", &animationEntry.weight));
|
||||
return result;
|
||||
}
|
||||
|
||||
void query_animation_entry_collection(XMLElement* element, const char* name,
|
||||
AnimationEntryCollection& animationEntryCollection)
|
||||
XMLError query_animation_entry_collection(XMLElement* element, const char* name,
|
||||
AnimationEntryCollection& animationEntryCollection)
|
||||
{
|
||||
auto result = XML_SUCCESS;
|
||||
for (auto child = element->FirstChildElement(name); child; child = child->NextSiblingElement(name))
|
||||
query_animation_entry(child, animationEntryCollection.emplace_back());
|
||||
result = query_result_merge(result, query_animation_entry(child, animationEntryCollection.emplace_back()));
|
||||
return result;
|
||||
}
|
||||
|
||||
void query_sound_entry(XMLElement* element, const std::string& archive, const std::string& rootPath,
|
||||
SoundEntry& soundEntry, const std::string& attributeName)
|
||||
XMLError query_sound_entry(XMLElement* element, const std::string& archive, const std::string& rootPath,
|
||||
SoundEntry& soundEntry, const std::string& attributeName)
|
||||
{
|
||||
query_sound(element, attributeName.c_str(), archive, rootPath, soundEntry.sound);
|
||||
element->QueryFloatAttribute("Weight", &soundEntry.weight);
|
||||
auto result = query_sound(element, attributeName.c_str(), archive, rootPath, soundEntry.sound);
|
||||
result = query_result_merge(result, element->QueryFloatAttribute("Weight", &soundEntry.weight));
|
||||
return result;
|
||||
}
|
||||
|
||||
void query_sound_entry_collection(XMLElement* element, const char* name, const std::string& archive,
|
||||
const std::string& rootPath, SoundEntryCollection& soundEntryCollection,
|
||||
const std::string& attributeName)
|
||||
XMLError query_sound_entry_collection(XMLElement* element, const char* name, const std::string& archive,
|
||||
const std::string& rootPath, SoundEntryCollection& soundEntryCollection,
|
||||
const std::string& attributeName)
|
||||
{
|
||||
auto result = XML_SUCCESS;
|
||||
for (auto child = element->FirstChildElement(name); child; child = child->NextSiblingElement(name))
|
||||
query_sound_entry(child, archive, rootPath, soundEntryCollection.emplace_back(), attributeName);
|
||||
result = query_result_merge(
|
||||
result, query_sound_entry(child, archive, rootPath, soundEntryCollection.emplace_back(), attributeName));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <tinyxml2.h>
|
||||
|
||||
#include "animation_entry.hpp"
|
||||
@@ -19,33 +20,43 @@ namespace game::resource::xml
|
||||
tinyxml2::XMLError query_bool_attribute(tinyxml2::XMLElement*, const char*, bool*);
|
||||
tinyxml2::XMLError query_path_attribute(tinyxml2::XMLElement*, const char*, std::filesystem::path*);
|
||||
tinyxml2::XMLError query_color_attribute(tinyxml2::XMLElement*, const char*, float*);
|
||||
tinyxml2::XMLError query_ivec2(tinyxml2::XMLElement*, const char*, const char*, glm::ivec2&);
|
||||
tinyxml2::XMLError query_vec2(tinyxml2::XMLElement*, const char*, const char*, glm::vec2&);
|
||||
tinyxml2::XMLError query_vec3(tinyxml2::XMLElement*, const char*, const char*, const char*, glm::vec3&);
|
||||
tinyxml2::XMLError set_bool_attribute(tinyxml2::XMLElement*, const char*, bool);
|
||||
tinyxml2::XMLError set_ivec2_attribute(tinyxml2::XMLElement*, const char*, const char*, const glm::ivec2&);
|
||||
tinyxml2::XMLError set_vec2_attribute(tinyxml2::XMLElement*, const char*, const char*, const glm::vec2&);
|
||||
tinyxml2::XMLError set_vec3_attribute(tinyxml2::XMLElement*, const char*, const char*, const char*,
|
||||
const glm::vec3&);
|
||||
tinyxml2::XMLError query_float_optional_attribute(tinyxml2::XMLElement* element, const char* attribute,
|
||||
std::optional<float>& value);
|
||||
tinyxml2::XMLError query_int_optional_attribute(tinyxml2::XMLElement* element, const char* attribute,
|
||||
std::optional<int>& value);
|
||||
|
||||
void query_event_id(tinyxml2::XMLElement* element, const char* name, const Anm2& anm2, int& eventID);
|
||||
void query_layer_id(tinyxml2::XMLElement* element, const char* name, const Anm2& anm2, int& layerID);
|
||||
void query_null_id(tinyxml2::XMLElement* element, const char* name, const Anm2& anm2, int& nullID);
|
||||
tinyxml2::XMLError query_event_id(tinyxml2::XMLElement* element, const char* name, const Anm2& anm2, int& eventID);
|
||||
tinyxml2::XMLError query_layer_id(tinyxml2::XMLElement* element, const char* name, const Anm2& anm2, int& layerID);
|
||||
tinyxml2::XMLError query_null_id(tinyxml2::XMLElement* element, const char* name, const Anm2& anm2, int& nullID);
|
||||
|
||||
void query_anm2(tinyxml2::XMLElement* element, const char* name, const std::string& archive,
|
||||
const std::string& rootPath, Anm2& anm2, Anm2::Flags flags = {});
|
||||
void query_texture(tinyxml2::XMLElement* element, const char* name, const std::string& archive,
|
||||
const std::string& rootPath, Texture& texture);
|
||||
void query_sound(tinyxml2::XMLElement* element, const char* name, const std::string& archive,
|
||||
const std::string& rootPath, Audio& sound);
|
||||
void query_font(tinyxml2::XMLElement* element, const char* name, const std::string& archive,
|
||||
const std::string& rootPath, Font& font);
|
||||
tinyxml2::XMLError query_anm2(tinyxml2::XMLElement* element, const char* name, const std::string& archive,
|
||||
const std::string& rootPath, Anm2& anm2, Anm2::Flags flags = {});
|
||||
tinyxml2::XMLError query_texture(tinyxml2::XMLElement* element, const char* name, const std::string& archive,
|
||||
const std::string& rootPath, Texture& texture);
|
||||
tinyxml2::XMLError query_sound(tinyxml2::XMLElement* element, const char* name, const std::string& archive,
|
||||
const std::string& rootPath, Audio& sound);
|
||||
tinyxml2::XMLError query_font(tinyxml2::XMLElement* element, const char* name, const std::string& archive,
|
||||
const std::string& rootPath, Font& font);
|
||||
|
||||
void query_animation_entry(tinyxml2::XMLElement* element, AnimationEntry& animationEntry);
|
||||
void query_animation_entry_collection(tinyxml2::XMLElement* element, const char* name,
|
||||
AnimationEntryCollection& animationEntryCollection);
|
||||
tinyxml2::XMLError query_animation_entry(tinyxml2::XMLElement* element, AnimationEntry& animationEntry);
|
||||
tinyxml2::XMLError query_animation_entry_collection(tinyxml2::XMLElement* element, const char* name,
|
||||
AnimationEntryCollection& animationEntryCollection);
|
||||
|
||||
void query_sound_entry(tinyxml2::XMLElement* element, const std::string& archive, const std::string& rootPath,
|
||||
SoundEntry& soundEntry, const std::string& attributeName = "Sound");
|
||||
void query_sound_entry_collection(tinyxml2::XMLElement* element, const char* name, const std::string& archive,
|
||||
const std::string& rootPath, SoundEntryCollection& soundEntryCollection,
|
||||
const std::string& attributeName = "Sound");
|
||||
tinyxml2::XMLError query_sound_entry(tinyxml2::XMLElement* element, const std::string& archive,
|
||||
const std::string& rootPath, SoundEntry& soundEntry,
|
||||
const std::string& attributeName = "Sound");
|
||||
tinyxml2::XMLError query_sound_entry_collection(tinyxml2::XMLElement* element, const char* name,
|
||||
const std::string& archive, const std::string& rootPath,
|
||||
SoundEntryCollection& soundEntryCollection,
|
||||
const std::string& attributeName = "Sound");
|
||||
|
||||
tinyxml2::XMLError document_load(const util::physfs::Path&, tinyxml2::XMLDocument&);
|
||||
}
|
||||
|
||||
@@ -31,8 +31,8 @@ namespace game
|
||||
case SELECT:
|
||||
select.tick();
|
||||
break;
|
||||
case MAIN:
|
||||
main.tick(resources);
|
||||
case PLAY:
|
||||
play.tick(resources);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -52,7 +52,7 @@ namespace game
|
||||
ImGui_ImplSDL3_ProcessEvent(&event);
|
||||
if (event.type == SDL_EVENT_QUIT)
|
||||
{
|
||||
if (type == MAIN) main.exit(resources);
|
||||
if (type == PLAY) play.exit(resources);
|
||||
isRunning = false;
|
||||
}
|
||||
if (!isRunning) return;
|
||||
@@ -68,30 +68,30 @@ namespace game
|
||||
select.update(resources);
|
||||
if (select.info.isNewGame || select.info.isContinue)
|
||||
{
|
||||
Main::Game game = select.info.isNewGame ? Main::NEW_GAME : Main::CONTINUE;
|
||||
if (game == Main::NEW_GAME) resources.character_save_set(select.characterIndex, resource::xml::Save());
|
||||
Play::Game game = select.info.isNewGame ? Play::NEW_GAME : Play::CONTINUE;
|
||||
if (game == Play::NEW_GAME) resources.character_save_set(select.characterIndex, resource::xml::Save());
|
||||
|
||||
main.set(resources, select.characterIndex, game);
|
||||
type = MAIN;
|
||||
play.set(resources, select.characterIndex, game);
|
||||
type = PLAY;
|
||||
|
||||
select.info.isNewGame = false;
|
||||
select.info.isContinue = false;
|
||||
}
|
||||
break;
|
||||
case MAIN:
|
||||
main.update(resources);
|
||||
if (main.menu.configuration.isGoToSelect)
|
||||
case PLAY:
|
||||
play.update(resources);
|
||||
if (play.menu.settingsMenu.isGoToSelect)
|
||||
{
|
||||
main.exit(resources);
|
||||
play.exit(resources);
|
||||
type = SELECT;
|
||||
main.menu.configuration.isGoToSelect = false;
|
||||
play.menu.settingsMenu.isGoToSelect = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
auto isHideCursor = type == MAIN;
|
||||
auto isHideCursor = type == PLAY;
|
||||
if (isHideCursor != isCursorHidden)
|
||||
{
|
||||
if (isHideCursor)
|
||||
@@ -104,6 +104,8 @@ namespace game
|
||||
|
||||
void State::render()
|
||||
{
|
||||
auto& color =
|
||||
resources.settings.isUseCharacterColor && type == PLAY ? play.character.data.color : resources.settings.color;
|
||||
auto windowSize = resources.settings.windowSize;
|
||||
#ifndef __EMSCRIPTEN__
|
||||
SDL_GetWindowSize(window, &windowSize.x, &windowSize.y);
|
||||
@@ -111,7 +113,7 @@ namespace game
|
||||
|
||||
canvas.bind();
|
||||
canvas.size_set(windowSize);
|
||||
canvas.clear(vec4(resources.settings.color, 1.0f));
|
||||
canvas.clear(vec4(color, 1.0f));
|
||||
canvas.unbind();
|
||||
|
||||
switch (type)
|
||||
@@ -119,8 +121,8 @@ namespace game
|
||||
case SELECT:
|
||||
select.render(resources, canvas);
|
||||
break;
|
||||
case MAIN:
|
||||
main.render(resources, canvas);
|
||||
case PLAY:
|
||||
play.render(resources, canvas);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include "canvas.hpp"
|
||||
#include "render/canvas.hpp"
|
||||
#include "resources.hpp"
|
||||
|
||||
#include "state/main.hpp"
|
||||
#include "state/play.hpp"
|
||||
#include "state/select.hpp"
|
||||
|
||||
#include "entity/cursor.hpp"
|
||||
@@ -22,7 +22,7 @@ namespace game
|
||||
|
||||
enum Type
|
||||
{
|
||||
MAIN,
|
||||
PLAY,
|
||||
SELECT
|
||||
};
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace game
|
||||
|
||||
Resources resources;
|
||||
|
||||
state::Main main;
|
||||
state::Play play;
|
||||
state::Select select;
|
||||
|
||||
void tick();
|
||||
|
||||
@@ -1,228 +0,0 @@
|
||||
#include "inventory.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <format>
|
||||
#include <ranges>
|
||||
|
||||
#include "../../util/color.hpp"
|
||||
#include "../../util/imgui.hpp"
|
||||
#include "../../util/imgui/widget.hpp"
|
||||
#include "../../util/math.hpp"
|
||||
|
||||
using namespace game::util;
|
||||
using namespace game::util::imgui;
|
||||
using namespace game::entity;
|
||||
using namespace game::resource;
|
||||
using namespace glm;
|
||||
|
||||
namespace game::state::main
|
||||
{
|
||||
void Inventory::tick()
|
||||
{
|
||||
for (auto& [i, actor] : actors)
|
||||
actor.tick();
|
||||
}
|
||||
|
||||
void Inventory::update(Resources& resources, ItemManager& itemManager, entity::Character& character)
|
||||
{
|
||||
auto& schema = character.data.itemSchema;
|
||||
|
||||
if (!itemManager.returnItemIDs.empty())
|
||||
{
|
||||
for (auto& id : itemManager.returnItemIDs)
|
||||
values[id]++;
|
||||
itemManager.returnItemIDs.clear();
|
||||
}
|
||||
|
||||
if (ImGui::BeginChild("##Inventory Child"))
|
||||
{
|
||||
auto cursorPos = ImGui::GetCursorPos();
|
||||
auto cursorStartX = ImGui::GetCursorPosX();
|
||||
|
||||
auto size = ImVec2(SIZE, SIZE);
|
||||
|
||||
for (int i = 0; i < (int)schema.items.size(); i++)
|
||||
{
|
||||
auto& item = schema.items[i];
|
||||
auto& quantity = values[i];
|
||||
auto& category = schema.categories[item.categoryID];
|
||||
auto& calories = item.calories;
|
||||
auto& digestionBonus = item.digestionBonus;
|
||||
auto& eatSpeedBonus = item.eatSpeedBonus;
|
||||
auto& rarity = schema.rarities[item.rarityID];
|
||||
|
||||
quantity = glm::clamp(0, quantity, schema.quantityMax);
|
||||
if (rarity.isHidden && quantity <= 0) continue;
|
||||
|
||||
ImGui::PushID(i);
|
||||
|
||||
ImGui::SetCursorPos(cursorPos);
|
||||
auto cursorScreenPos = ImGui::GetCursorScreenPos();
|
||||
|
||||
if (!actors.contains(i))
|
||||
{
|
||||
actors[i] = Actor(schema.anm2s[i], {}, Actor::SET);
|
||||
rects[i] = actors[i].rect();
|
||||
}
|
||||
auto& rect = rects[i];
|
||||
auto rectSize = vec2(rect.z, rect.w);
|
||||
|
||||
auto previewScale = (size.x <= 0.0f || size.y <= 0.0f || rectSize.x <= 0.0f || rectSize.y <= 0.0f ||
|
||||
!std::isfinite(rectSize.x) || !std::isfinite(rectSize.y))
|
||||
? 0.0f
|
||||
: std::min(size.x / rectSize.x, size.y / rectSize.y);
|
||||
|
||||
auto previewSize = rectSize * previewScale;
|
||||
auto canvasSize = ivec2(std::max(1.0f, previewSize.x), std::max(1.0f, previewSize.y));
|
||||
if (!canvases.contains(i)) canvases.emplace((int)i, Canvas(canvasSize, Canvas::FLIP));
|
||||
auto& canvas = canvases[i];
|
||||
bool isPossibleToUpgrade = item.upgradeID.has_value() && item.upgradeCount.has_value() &&
|
||||
schema.idToStringMap.contains(*item.upgradeID);
|
||||
bool isAbleToUpgrade = isPossibleToUpgrade && quantity >= *item.upgradeCount;
|
||||
canvas.zoom = math::to_percent(previewScale);
|
||||
canvas.pan = vec2(rect.x, rect.y);
|
||||
canvas.bind();
|
||||
canvas.size_set(canvasSize);
|
||||
canvas.clear();
|
||||
|
||||
actors[i].render(resources.shaders[shader::TEXTURE], resources.shaders[shader::RECT], canvas);
|
||||
canvas.unbind();
|
||||
|
||||
ImGui::BeginDisabled(quantity < 1);
|
||||
if (WIDGET_FX(ImGui::ImageButton("##Image Button", canvas.texture, size, ImVec2(), ImVec2(1, 1), ImVec4(),
|
||||
quantity <= 0 ? ImVec4(0, 0, 0, 1) : ImVec4(1, 1, 1, 1))) &&
|
||||
quantity > 0)
|
||||
{
|
||||
if (ImGui::IsKeyDown(ImGuiMod_Shift))
|
||||
{
|
||||
if (isAbleToUpgrade)
|
||||
{
|
||||
if (ImGui::IsKeyDown(ImGuiMod_Ctrl))
|
||||
{
|
||||
while (quantity >= *item.upgradeCount)
|
||||
{
|
||||
values.at(*item.upgradeID)++;
|
||||
quantity -= *item.upgradeCount;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
values.at(*item.upgradeID)++;
|
||||
quantity -= *item.upgradeCount;
|
||||
}
|
||||
|
||||
schema.sounds.upgrade.play();
|
||||
}
|
||||
else
|
||||
schema.sounds.upgradeFail.play();
|
||||
}
|
||||
else if (category.isEdible)
|
||||
{
|
||||
if (itemManager.items.size() + 1 >= ItemManager::LIMIT)
|
||||
character.data.itemSchema.sounds.dispose.play();
|
||||
else
|
||||
{
|
||||
character.data.itemSchema.sounds.summon.play();
|
||||
itemManager.queuedItemIDs.emplace_back(i);
|
||||
quantity--;
|
||||
}
|
||||
}
|
||||
else if (item.isToggleSpritesheet)
|
||||
{
|
||||
character.spritesheet_set(character.spritesheetType == Character::NORMAL ? Character::ALTERNATE
|
||||
: Character::NORMAL);
|
||||
character.data.alternateSpritesheet.sound.play();
|
||||
quantity--;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndDisabled();
|
||||
|
||||
if (ImGui::BeginItemTooltip())
|
||||
{
|
||||
if (quantity > 0)
|
||||
{
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::BIG);
|
||||
|
||||
ImGui::Text("%s (x%i)", item.name.c_str(), quantity);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::PopFont();
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetColorU32(imgui::to_imvec4(color::GRAY)));
|
||||
|
||||
ImGui::Text("-- %s (%s) --", category.name.c_str(), rarity.name.c_str());
|
||||
if (item.flavorID.has_value()) ImGui::Text("Flavor: %s", schema.flavors[*item.flavorID].name.c_str());
|
||||
if (calories.has_value()) ImGui::Text("%0.0f kcal", *calories);
|
||||
if (digestionBonus.has_value())
|
||||
{
|
||||
if (*digestionBonus > 0)
|
||||
ImGui::Text("Digestion Rate Bonus: +%0.2f%% / sec", *digestionBonus * 60.0f);
|
||||
else if (digestionBonus < 0)
|
||||
ImGui::Text("Digestion Rate Penalty: %0.2f%% / sec", *digestionBonus * 60.0f);
|
||||
}
|
||||
if (eatSpeedBonus.has_value())
|
||||
{
|
||||
if (*eatSpeedBonus > 0)
|
||||
ImGui::Text("Eat Speed Bonus: +%0.2f%% / sec", *eatSpeedBonus);
|
||||
else if (eatSpeedBonus < 0)
|
||||
ImGui::Text("Eat Speed Penalty: %0.2f%% / sec", *eatSpeedBonus);
|
||||
}
|
||||
|
||||
if (isPossibleToUpgrade)
|
||||
{
|
||||
ImGui::Text("Upgrade: %ix -> %s", *item.upgradeCount, schema.idToStringMap.at(*item.upgradeID).c_str());
|
||||
if (isAbleToUpgrade)
|
||||
ImGui::TextUnformatted("(Shift + Click -> Upgrade)\n(Shift + Ctrl + Click -> Upgrade All)");
|
||||
}
|
||||
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::TextUnformatted(item.description.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::BIG);
|
||||
ImGui::TextUnformatted("???");
|
||||
ImGui::PopFont();
|
||||
}
|
||||
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::BIG);
|
||||
|
||||
auto text = std::format("x{}", quantity);
|
||||
auto textPos = ImVec2(cursorScreenPos.x + size.x - ImGui::CalcTextSize(text.c_str()).x,
|
||||
cursorScreenPos.y + size.y - ImGui::GetTextLineHeightWithSpacing());
|
||||
ImGui::GetWindowDrawList()->AddText(textPos, ImGui::GetColorU32(ImGui::GetStyleColorVec4(ImGuiCol_Text)),
|
||||
text.c_str());
|
||||
ImGui::PopFont();
|
||||
|
||||
auto increment = ImGui::GetItemRectSize().x + ImGui::GetStyle().ItemSpacing.x;
|
||||
cursorPos.x += increment;
|
||||
|
||||
if (cursorPos.x + increment > ImGui::GetContentRegionAvail().x)
|
||||
{
|
||||
cursorPos.x = cursorStartX;
|
||||
cursorPos.y += increment;
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
if (count() == 0) ImGui::Text("Check the \"Play\" tab to earn rewards!");
|
||||
}
|
||||
ImGui::EndChild();
|
||||
}
|
||||
|
||||
int Inventory::count()
|
||||
{
|
||||
int count{};
|
||||
for (auto& [type, quantity] : values)
|
||||
count += quantity;
|
||||
return count;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "main.hpp"
|
||||
#include "play.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <glm/glm.hpp>
|
||||
@@ -12,12 +12,12 @@
|
||||
|
||||
using namespace game::resource;
|
||||
using namespace game::util;
|
||||
using namespace game::state::main;
|
||||
using namespace game::state::play;
|
||||
using namespace glm;
|
||||
|
||||
namespace game::state
|
||||
{
|
||||
World::Focus Main::focus_get()
|
||||
World::Focus Play::focus_get()
|
||||
{
|
||||
if (!isWindows) return World::CENTER;
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace game::state
|
||||
: World::CENTER;
|
||||
}
|
||||
|
||||
void Main::set(Resources& resources, int selectedCharacterIndex, enum Game game)
|
||||
void Play::set(Resources& resources, int selectedCharacterIndex, enum Game game)
|
||||
{
|
||||
auto& data = resources.character_get(selectedCharacterIndex);
|
||||
auto& saveData = data.save;
|
||||
@@ -35,8 +35,8 @@ namespace game::state
|
||||
auto& dialogue = data.dialogue;
|
||||
auto& menuSchema = data.menuSchema;
|
||||
this->characterIndex = selectedCharacterIndex;
|
||||
konamiCodeIndex = 0;
|
||||
konamiCodeStartTime = 0.0;
|
||||
cheatCodeIndex = 0;
|
||||
cheatCodeStartTime = 0.0;
|
||||
|
||||
character =
|
||||
entity::Character(data, vec2(World::BOUNDS.x + World::BOUNDS.z * 0.5f, World::BOUNDS.w - World::BOUNDS.y));
|
||||
@@ -58,6 +58,7 @@ namespace game::state
|
||||
characterManager = CharacterManager{};
|
||||
|
||||
cursor = entity::Cursor(character.data.cursorSchema.anm2);
|
||||
cursor.interactTypeID = character.data.interactTypeNames.empty() ? -1 : 0;
|
||||
|
||||
menu.inventory = Inventory{};
|
||||
for (auto& [id, quantity] : saveData.inventory)
|
||||
@@ -79,14 +80,14 @@ namespace game::state
|
||||
|
||||
imgui::style::rounding_set(menuSchema.rounding);
|
||||
imgui::widget::sounds_set(&menuSchema.sounds.hover, &menuSchema.sounds.select);
|
||||
menu.color_set_check(resources, character);
|
||||
|
||||
menu.play = Play(character);
|
||||
menu.play.totalPlays = saveData.totalPlays;
|
||||
menu.play.highScore = saveData.highScore;
|
||||
menu.play.bestCombo = saveData.bestCombo;
|
||||
menu.play.gradeCounts = saveData.gradeCounts;
|
||||
menu.play.isHighScoreAchieved = saveData.highScore > 0 ? true : false;
|
||||
|
||||
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();
|
||||
|
||||
text.entry = nullptr;
|
||||
@@ -114,17 +115,31 @@ namespace game::state
|
||||
isStartBegin = false;
|
||||
isStartEnd = false;
|
||||
}
|
||||
|
||||
if (isPostgame)
|
||||
{
|
||||
isEnd = true;
|
||||
isEndBegin = true;
|
||||
isEndEnd = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
isEnd = false;
|
||||
isEndBegin = false;
|
||||
isEndEnd = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Main::exit(Resources& resources)
|
||||
void Play::exit(Resources& resources)
|
||||
{
|
||||
imgui::style::color_set(resources.settings.color);
|
||||
imgui::style::rounding_set();
|
||||
imgui::widget::sounds_set(nullptr, nullptr);
|
||||
ImGui::GetIO().FontDefault = resources.font.get();
|
||||
save(resources);
|
||||
}
|
||||
|
||||
void Main::tick(Resources&)
|
||||
void Play::tick(Resources&)
|
||||
{
|
||||
character.tick();
|
||||
cursor.tick();
|
||||
@@ -136,54 +151,54 @@ namespace game::state
|
||||
item.tick();
|
||||
}
|
||||
|
||||
void Main::update(Resources& resources)
|
||||
void Play::update(Resources& resources)
|
||||
{
|
||||
static constexpr std::array<ImGuiKey, 10> KONAMI_CODE = {
|
||||
static constexpr std::array<ImGuiKey, 10> CHEAT_CODE = {
|
||||
ImGuiKey_UpArrow, ImGuiKey_UpArrow, ImGuiKey_DownArrow, ImGuiKey_DownArrow, ImGuiKey_LeftArrow,
|
||||
ImGuiKey_RightArrow, ImGuiKey_LeftArrow, ImGuiKey_RightArrow, ImGuiKey_B, ImGuiKey_A};
|
||||
static constexpr std::array<ImGuiKey, 6> KONAMI_INPUT_KEYS = {
|
||||
static constexpr std::array<ImGuiKey, 6> CHEAT_INPUT_KEYS = {
|
||||
ImGuiKey_UpArrow, ImGuiKey_DownArrow, ImGuiKey_LeftArrow, ImGuiKey_RightArrow, ImGuiKey_B, ImGuiKey_A};
|
||||
static constexpr auto KONAMI_CODE_INPUT_TIME_SECONDS = 5.0;
|
||||
static constexpr auto CHEAT_CODE_INPUT_TIME_SECONDS = 5.0;
|
||||
|
||||
auto focus = focus_get();
|
||||
auto& dialogue = character.data.dialogue;
|
||||
|
||||
if (!menu.isCheats)
|
||||
{
|
||||
for (auto key : KONAMI_INPUT_KEYS)
|
||||
for (auto key : CHEAT_INPUT_KEYS)
|
||||
{
|
||||
if (!ImGui::IsKeyPressed(key, false)) continue;
|
||||
|
||||
if (key == KONAMI_CODE[konamiCodeIndex])
|
||||
if (key == CHEAT_CODE[cheatCodeIndex])
|
||||
{
|
||||
konamiCodeIndex++;
|
||||
konamiCodeStartTime = ImGui::GetTime();
|
||||
cheatCodeIndex++;
|
||||
cheatCodeStartTime = ImGui::GetTime();
|
||||
}
|
||||
else if (key == KONAMI_CODE[0])
|
||||
else if (key == CHEAT_CODE[0])
|
||||
{
|
||||
konamiCodeIndex = 1;
|
||||
konamiCodeStartTime = ImGui::GetTime();
|
||||
cheatCodeIndex = 1;
|
||||
cheatCodeStartTime = ImGui::GetTime();
|
||||
}
|
||||
else
|
||||
{
|
||||
konamiCodeIndex = 0;
|
||||
konamiCodeStartTime = 0.0;
|
||||
cheatCodeIndex = 0;
|
||||
cheatCodeStartTime = 0.0;
|
||||
}
|
||||
|
||||
if (konamiCodeIndex >= (int)KONAMI_CODE.size())
|
||||
if (cheatCodeIndex >= (int)CHEAT_CODE.size())
|
||||
{
|
||||
menu.isCheats = true;
|
||||
konamiCodeIndex = 0;
|
||||
konamiCodeStartTime = 0.0;
|
||||
cheatCodeIndex = 0;
|
||||
cheatCodeStartTime = 0.0;
|
||||
toasts.push("Cheats unlocked!");
|
||||
character.data.menuSchema.sounds.cheatsActivated.play();
|
||||
}
|
||||
}
|
||||
|
||||
if (konamiCodeIndex > 0 && (ImGui::GetTime() - konamiCodeStartTime > KONAMI_CODE_INPUT_TIME_SECONDS))
|
||||
if (cheatCodeIndex > 0 && (ImGui::GetTime() - cheatCodeStartTime > CHEAT_CODE_INPUT_TIME_SECONDS))
|
||||
{
|
||||
konamiCodeIndex = 0;
|
||||
konamiCodeStartTime = 0.0;
|
||||
cheatCodeIndex = 0;
|
||||
cheatCodeStartTime = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,15 +279,15 @@ namespace game::state
|
||||
cursor.update();
|
||||
world.update(character, cursor, worldCanvas, focus);
|
||||
|
||||
if (autosaveTime += ImGui::GetIO().DeltaTime; autosaveTime > AUTOSAVE_TIME || menu.configuration.isSave)
|
||||
if (autosaveTime += ImGui::GetIO().DeltaTime; autosaveTime > AUTOSAVE_TIME || menu.settingsMenu.isSave)
|
||||
{
|
||||
save(resources);
|
||||
autosaveTime = 0;
|
||||
menu.configuration.isSave = false;
|
||||
menu.settingsMenu.isSave = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Main::render(Resources& resources, Canvas& canvas)
|
||||
void Play::render(Resources& resources, Canvas& canvas)
|
||||
{
|
||||
auto& textureShader = resources.shaders[shader::TEXTURE];
|
||||
auto& rectShader = resources.shaders[shader::RECT];
|
||||
@@ -309,7 +324,7 @@ namespace game::state
|
||||
canvas.unbind();
|
||||
}
|
||||
|
||||
void Main::save(Resources& resources)
|
||||
void Play::save(Resources& resources)
|
||||
{
|
||||
resource::xml::Save save;
|
||||
|
||||
@@ -323,10 +338,10 @@ namespace game::state
|
||||
save.digestionTimer = character.digestionTimer;
|
||||
save.totalCaloriesConsumed = character.totalCaloriesConsumed;
|
||||
save.totalFoodItemsEaten = character.totalFoodItemsEaten;
|
||||
save.totalPlays = menu.play.totalPlays;
|
||||
save.highScore = menu.play.highScore;
|
||||
save.bestCombo = menu.play.bestCombo;
|
||||
save.gradeCounts = menu.play.gradeCounts;
|
||||
save.totalPlays = menu.skillCheck.totalPlays;
|
||||
save.highScore = menu.skillCheck.highScore;
|
||||
save.bestCombo = menu.skillCheck.bestCombo;
|
||||
save.gradeCounts = menu.skillCheck.gradeCounts;
|
||||
save.isPostgame = isPostgame;
|
||||
save.isAlternateSpritesheet = character.spritesheetType == entity::Character::ALTERNATE;
|
||||
|
||||
@@ -2,19 +2,19 @@
|
||||
|
||||
#include "../resources.hpp"
|
||||
|
||||
#include "main/area_manager.hpp"
|
||||
#include "main/character_manager.hpp"
|
||||
#include "main/info.hpp"
|
||||
#include "main/item_manager.hpp"
|
||||
#include "main/menu.hpp"
|
||||
#include "main/text.hpp"
|
||||
#include "main/toasts.hpp"
|
||||
#include "main/tools.hpp"
|
||||
#include "main/world.hpp"
|
||||
#include "play/area_manager.hpp"
|
||||
#include "play/character_manager.hpp"
|
||||
#include "play/info.hpp"
|
||||
#include "play/item_manager.hpp"
|
||||
#include "play/menu.hpp"
|
||||
#include "play/text.hpp"
|
||||
#include "play/toasts.hpp"
|
||||
#include "play/tools.hpp"
|
||||
#include "play/world.hpp"
|
||||
|
||||
namespace game::state
|
||||
{
|
||||
class Main
|
||||
class Play
|
||||
{
|
||||
public:
|
||||
static constexpr auto AUTOSAVE_TIME = 30.0f;
|
||||
@@ -28,22 +28,22 @@ namespace game::state
|
||||
entity::Character character;
|
||||
entity::Cursor cursor;
|
||||
|
||||
main::Info info;
|
||||
main::Menu menu;
|
||||
main::Tools tools;
|
||||
main::Text text;
|
||||
main::World world;
|
||||
main::Toasts toasts;
|
||||
main::ItemManager itemManager{};
|
||||
main::CharacterManager characterManager{};
|
||||
main::AreaManager areaManager{};
|
||||
play::Info info;
|
||||
play::Menu menu;
|
||||
play::Tools tools;
|
||||
play::Text text;
|
||||
play::World world;
|
||||
play::Toasts toasts;
|
||||
play::ItemManager itemManager{};
|
||||
play::CharacterManager characterManager{};
|
||||
play::AreaManager areaManager{};
|
||||
|
||||
int characterIndex{};
|
||||
int areaIndex{};
|
||||
|
||||
float autosaveTime{};
|
||||
int konamiCodeIndex{};
|
||||
double konamiCodeStartTime{};
|
||||
int cheatCodeIndex{};
|
||||
double cheatCodeStartTime{};
|
||||
|
||||
bool isWindows{true};
|
||||
|
||||
@@ -57,15 +57,15 @@ namespace game::state
|
||||
|
||||
bool isPostgame{};
|
||||
|
||||
Canvas worldCanvas{main::World::SIZE};
|
||||
Canvas worldCanvas{play::World::SIZE};
|
||||
|
||||
Main() = default;
|
||||
Play() = default;
|
||||
void set(Resources&, int characterIndex, Game = CONTINUE);
|
||||
void exit(Resources& resources);
|
||||
void update(Resources&);
|
||||
void tick(Resources&);
|
||||
void render(Resources&, Canvas&);
|
||||
void save(Resources&);
|
||||
main::World::Focus focus_get();
|
||||
play::World::Focus focus_get();
|
||||
};
|
||||
};
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "play.hpp"
|
||||
#include "skill_check.hpp"
|
||||
|
||||
#include <imgui_internal.h>
|
||||
|
||||
#include "../../util/imgui.hpp"
|
||||
#include "../../util/imgui/widget.hpp"
|
||||
#include "../../util/math.hpp"
|
||||
#include "../../../util/imgui.hpp"
|
||||
#include "../../../util/imgui/widget.hpp"
|
||||
#include "../../../util/math.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <format>
|
||||
@@ -15,13 +15,13 @@ using namespace game::entity;
|
||||
using namespace game::resource;
|
||||
using namespace glm;
|
||||
|
||||
namespace game::state::main
|
||||
namespace game::state::play
|
||||
{
|
||||
float Play::accuracy_score_get(entity::Character& character)
|
||||
float SkillCheck::accuracy_score_get(entity::Character& character)
|
||||
{
|
||||
if (totalPlays == 0) return 0.0f;
|
||||
|
||||
auto& schema = character.data.playSchema;
|
||||
auto& schema = character.data.skillCheckSchema;
|
||||
|
||||
float combinedWeight{};
|
||||
|
||||
@@ -34,9 +34,9 @@ namespace game::state::main
|
||||
return glm::clamp(0.0f, math::to_percent(combinedWeight / totalPlays), 100.0f);
|
||||
}
|
||||
|
||||
Play::Challenge Play::challenge_generate(entity::Character& character)
|
||||
SkillCheck::Challenge SkillCheck::challenge_generate(entity::Character& character)
|
||||
{
|
||||
auto& schema = character.data.playSchema;
|
||||
auto& schema = character.data.skillCheckSchema;
|
||||
|
||||
Challenge newChallenge;
|
||||
|
||||
@@ -61,15 +61,15 @@ namespace game::state::main
|
||||
return newChallenge;
|
||||
}
|
||||
|
||||
Play::Play(entity::Character& character) { challenge = challenge_generate(character); }
|
||||
SkillCheck::SkillCheck(entity::Character& character) { challenge = challenge_generate(character); }
|
||||
|
||||
void Play::tick()
|
||||
void SkillCheck::tick()
|
||||
{
|
||||
for (auto& [i, actor] : itemActors)
|
||||
actor.tick();
|
||||
}
|
||||
|
||||
void Play::update(Resources& resources, entity::Character& character, Inventory& inventory, Text& text)
|
||||
void 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);
|
||||
@@ -80,7 +80,7 @@ namespace game::state::main
|
||||
static constexpr auto ITEM_FALL_GRAVITY = 2400.0f;
|
||||
|
||||
auto& dialogue = character.data.dialogue;
|
||||
auto& schema = character.data.playSchema;
|
||||
auto& schema = character.data.skillCheckSchema;
|
||||
auto& itemSchema = character.data.itemSchema;
|
||||
auto& style = ImGui::GetStyle();
|
||||
auto drawList = ImGui::GetWindowDrawList();
|
||||
@@ -202,7 +202,7 @@ namespace game::state::main
|
||||
auto barButtonSize = ImVec2(barMax.x - barMin.x, barMax.y - barMin.y);
|
||||
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_Space) ||
|
||||
WIDGET_FX(ImGui::InvisibleButton("##PlayBar", barButtonSize, ImGuiButtonFlags_PressedOnClick)))
|
||||
WIDGET_FX(ImGui::InvisibleButton("##SkillCheckBar", barButtonSize, ImGuiButtonFlags_PressedOnClick)))
|
||||
{
|
||||
int gradeID{};
|
||||
|
||||
@@ -234,7 +234,7 @@ namespace game::state::main
|
||||
schema.sounds.rewardScore.play();
|
||||
isRewardScoreAchieved = true;
|
||||
|
||||
for (auto& itemID : itemSchema.rewardItemPool)
|
||||
for (auto& itemID : itemSchema.skillCheckRewardItemPool)
|
||||
{
|
||||
inventory.values[itemID]++;
|
||||
if (!itemActors.contains(itemID))
|
||||
@@ -1,21 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../canvas.hpp"
|
||||
#include "../../entity/actor.hpp"
|
||||
#include "../../entity/character.hpp"
|
||||
#include "../../resources.hpp"
|
||||
#include "../../../render/canvas.hpp"
|
||||
#include "../../../entity/actor.hpp"
|
||||
#include "../../../entity/character.hpp"
|
||||
#include "../../../resources.hpp"
|
||||
|
||||
#include "inventory.hpp"
|
||||
#include "text.hpp"
|
||||
#include "../inventory.hpp"
|
||||
#include "../text.hpp"
|
||||
|
||||
#include <imgui.h>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace game::state::main
|
||||
namespace game::state::play
|
||||
{
|
||||
class Play
|
||||
class SkillCheck
|
||||
{
|
||||
|
||||
public:
|
||||
@@ -77,8 +77,8 @@ namespace game::state::main
|
||||
std::unordered_map<int, glm::vec4> itemRects{};
|
||||
std::unordered_map<int, Canvas> itemCanvases{};
|
||||
|
||||
Play() = default;
|
||||
Play(entity::Character&);
|
||||
SkillCheck() = default;
|
||||
SkillCheck(entity::Character&);
|
||||
Challenge challenge_generate(entity::Character&);
|
||||
void tick();
|
||||
void update(Resources&, entity::Character&, Inventory&, Text&);
|
||||
@@ -5,7 +5,7 @@
|
||||
using namespace game::resource;
|
||||
using namespace game::util;
|
||||
|
||||
namespace game::state::main
|
||||
namespace game::state::play
|
||||
{
|
||||
int AreaManager::get(entity::Character& character)
|
||||
{
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "../../entity/character.hpp"
|
||||
|
||||
namespace game::state::main
|
||||
namespace game::state::play
|
||||
{
|
||||
class AreaManager
|
||||
{
|
||||
@@ -8,7 +8,7 @@
|
||||
using namespace game::resource::xml;
|
||||
using namespace game::util;
|
||||
|
||||
namespace game::state::main
|
||||
namespace game::state::play
|
||||
{
|
||||
void CharacterManager::update(entity::Character& character, entity::Cursor& cursor, Text& text, Canvas& canvas)
|
||||
{
|
||||
@@ -36,12 +36,19 @@ namespace game::state::main
|
||||
|
||||
isInteractingPrevious = isInteracting;
|
||||
isHoveringPrevious = isHovering;
|
||||
isHoldInteractingPrevious = isHoldInteracting;
|
||||
isHovering = false;
|
||||
if (!isInteracting) isHoldInteracting = false;
|
||||
|
||||
if (isJustStoppedInteracting)
|
||||
if (isJustStoppedHoldInteracting)
|
||||
{
|
||||
cursor.queue_play({cursor.defaultAnimation});
|
||||
if (character.queuedPlay.empty()) character.queue_idle_animation();
|
||||
isJustStoppedHoldInteracting = false;
|
||||
}
|
||||
else if (isJustStoppedInteracting)
|
||||
{
|
||||
cursor.queue_play({cursor.defaultAnimation});
|
||||
if (cursor.mode == RUB && character.queuedPlay.empty()) character.queue_idle_animation();
|
||||
isJustStoppedInteracting = false;
|
||||
}
|
||||
|
||||
@@ -58,7 +65,7 @@ namespace game::state::main
|
||||
auto rect = character.null_frame_rect(interactArea.nullID);
|
||||
|
||||
if (cursor.state == entity::Cursor::DEFAULT && math::is_point_in_rectf(rect, cursorWorldPosition) &&
|
||||
!isImguiCaptureMouse && interactArea.type == cursor.mode)
|
||||
!isImguiCaptureMouse && interactArea.typeID == cursor.interactTypeID)
|
||||
{
|
||||
cursor.state = entity::Cursor::HOVER;
|
||||
cursor.queue_play({interactArea.animationCursorHover});
|
||||
@@ -68,8 +75,8 @@ namespace game::state::main
|
||||
if (isMouseLeftClick)
|
||||
{
|
||||
isInteracting = true;
|
||||
isHoldInteracting = interactArea.isHold;
|
||||
interactArea.sound.play();
|
||||
lastInteractType = cursor.mode;
|
||||
|
||||
if (interactArea.digestionBonusClick > 0 && character.calories > 0 && !character.isDigesting)
|
||||
character.digestionProgress += interactArea.digestionBonusClick;
|
||||
@@ -105,11 +112,13 @@ namespace game::state::main
|
||||
isImguiCaptureMouse)
|
||||
{
|
||||
isInteracting = false;
|
||||
isHoldInteracting = false;
|
||||
interactAreaID = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (isInteracting != isInteractingPrevious && !isInteracting) isJustStoppedInteracting = true;
|
||||
if (isHoldInteracting != isHoldInteractingPrevious && !isHoldInteracting) isJustStoppedHoldInteracting = true;
|
||||
if (isHovering != isHoveringPrevious && !isHovering) isJustStoppedHovering = true;
|
||||
|
||||
cursorWorldPositionPrevious = cursorWorldPosition;
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "../../entity/cursor.hpp"
|
||||
#include "text.hpp"
|
||||
|
||||
namespace game::state::main
|
||||
namespace game::state::play
|
||||
{
|
||||
class CharacterManager
|
||||
{
|
||||
@@ -15,8 +15,10 @@ namespace game::state::main
|
||||
bool isHoveringPrevious{};
|
||||
bool isJustStoppedInteracting{};
|
||||
bool isJustStoppedHovering{};
|
||||
bool isHoldInteracting{};
|
||||
bool isHoldInteractingPrevious{};
|
||||
bool isJustStoppedHoldInteracting{};
|
||||
int interactAreaID{-1};
|
||||
InteractType lastInteractType{(InteractType)-1};
|
||||
|
||||
glm::vec2 cursorWorldPositionPrevious{};
|
||||
std::string queuedAnimation{};
|
||||
@@ -5,7 +5,7 @@
|
||||
using namespace game::resource;
|
||||
using namespace game::util::imgui;
|
||||
|
||||
namespace game::state::main
|
||||
namespace game::state::play
|
||||
{
|
||||
void Chat::update(Resources&, Text& text, entity::Character& character)
|
||||
{
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
namespace game::state::main
|
||||
namespace game::state::play
|
||||
{
|
||||
class Chat
|
||||
{
|
||||
@@ -9,7 +9,7 @@
|
||||
using namespace game::util::imgui;
|
||||
using namespace game::util;
|
||||
|
||||
namespace game::state::main
|
||||
namespace game::state::play
|
||||
{
|
||||
void Cheats::update(Resources&, entity::Character& character, Inventory& inventory, Text& text)
|
||||
{
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
namespace game::state::main
|
||||
namespace game::state::play
|
||||
{
|
||||
class Cheats
|
||||
{
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
using namespace game::util::imgui;
|
||||
|
||||
namespace game::state::main
|
||||
namespace game::state::play
|
||||
{
|
||||
void Debug::update(entity::Character& character, entity::Cursor& cursor, ItemManager& itemManager, Canvas& canvas)
|
||||
{
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
namespace game::state::main
|
||||
namespace game::state::play
|
||||
{
|
||||
class Debug
|
||||
{
|
||||
@@ -11,7 +11,7 @@
|
||||
using namespace game::resource;
|
||||
using namespace game::util;
|
||||
|
||||
namespace game::state::main
|
||||
namespace game::state::play
|
||||
{
|
||||
void Info::update(Resources& resources, entity::Character& character)
|
||||
{
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
namespace game::state::main
|
||||
namespace game::state::play
|
||||
{
|
||||
class Info
|
||||
{
|
||||
348
src/state/play/inventory.cpp
Normal file
348
src/state/play/inventory.cpp
Normal file
@@ -0,0 +1,348 @@
|
||||
#include "inventory.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <format>
|
||||
#include <ranges>
|
||||
#include <tuple>
|
||||
|
||||
#include "../../util/color.hpp"
|
||||
#include "../../util/imgui.hpp"
|
||||
#include "../../util/imgui/widget.hpp"
|
||||
#include "../../util/math.hpp"
|
||||
|
||||
using namespace game::util;
|
||||
using namespace game::util::imgui;
|
||||
using namespace game::entity;
|
||||
using namespace game::resource;
|
||||
using namespace glm;
|
||||
|
||||
namespace game::state::play
|
||||
{
|
||||
void Inventory::tick()
|
||||
{
|
||||
for (auto& [i, actor] : actors)
|
||||
actor.tick();
|
||||
}
|
||||
|
||||
void Inventory::update(Resources& resources, ItemManager& itemManager, entity::Character& character)
|
||||
{
|
||||
static constexpr auto INFO_CHILD_HEIGHT_MULTIPLIER = 1.0f / 3.0f;
|
||||
|
||||
auto& schema = character.data.itemSchema;
|
||||
|
||||
auto quantity_get = [&](int itemID) -> int&
|
||||
{
|
||||
auto& quantity = values[itemID];
|
||||
quantity = glm::clamp(0, quantity, schema.quantityMax);
|
||||
return quantity;
|
||||
};
|
||||
|
||||
auto is_possible_to_upgrade_get = [&](const resource::xml::Item::Entry& item)
|
||||
{
|
||||
return item.upgradeID.has_value() && item.upgradeCount.has_value() &&
|
||||
schema.idToStringMap.contains(*item.upgradeID);
|
||||
};
|
||||
|
||||
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_use = [&](int itemID)
|
||||
{
|
||||
auto& item = schema.items[itemID];
|
||||
auto& category = schema.categories[item.categoryID];
|
||||
auto& quantity = quantity_get(itemID);
|
||||
|
||||
if (quantity <= 0) return;
|
||||
|
||||
if (category.isEdible)
|
||||
{
|
||||
if (itemManager.items.size() + 1 >= ItemManager::LIMIT)
|
||||
character.data.itemSchema.sounds.dispose.play();
|
||||
else
|
||||
{
|
||||
character.data.itemSchema.sounds.summon.play();
|
||||
itemManager.queuedItemIDs.emplace_back(itemID);
|
||||
quantity--;
|
||||
if (quantity <= 0) selectedItemID = -1;
|
||||
}
|
||||
}
|
||||
else if (item.isToggleSpritesheet)
|
||||
{
|
||||
character.spritesheet_set(character.spritesheetType == Character::NORMAL ? Character::ALTERNATE
|
||||
: Character::NORMAL);
|
||||
character.data.alternateSpritesheet.sound.play();
|
||||
quantity--;
|
||||
}
|
||||
};
|
||||
|
||||
auto item_upgrade = [&](int itemID, bool isAll)
|
||||
{
|
||||
auto& item = schema.items[itemID];
|
||||
auto& quantity = quantity_get(itemID);
|
||||
|
||||
if (!is_possible_to_upgrade_get(item))
|
||||
{
|
||||
schema.sounds.upgradeFail.play();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_able_to_upgrade_get(item, quantity))
|
||||
{
|
||||
schema.sounds.upgradeFail.play();
|
||||
return;
|
||||
}
|
||||
|
||||
if (isAll)
|
||||
{
|
||||
while (quantity >= *item.upgradeCount)
|
||||
{
|
||||
values.at(*item.upgradeID)++;
|
||||
quantity -= *item.upgradeCount;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
values.at(*item.upgradeID)++;
|
||||
quantity -= *item.upgradeCount;
|
||||
}
|
||||
|
||||
schema.sounds.upgrade.play();
|
||||
|
||||
if (quantity < *item.upgradeCount && selectedItemID == itemID) selectedItemID = *item.upgradeID;
|
||||
};
|
||||
|
||||
auto item_canvas_get = [&](int itemID, ImVec2 size)
|
||||
{
|
||||
if (!actors.contains(itemID))
|
||||
{
|
||||
actors[itemID] = Actor(schema.anm2s[itemID], {}, Actor::SET);
|
||||
rects[itemID] = actors[itemID].rect();
|
||||
}
|
||||
|
||||
auto& rect = rects[itemID];
|
||||
auto rectSize = vec2(rect.z, rect.w);
|
||||
auto previewScale = (size.x <= 0.0f || size.y <= 0.0f || rectSize.x <= 0.0f || rectSize.y <= 0.0f ||
|
||||
!std::isfinite(rectSize.x) || !std::isfinite(rectSize.y))
|
||||
? 0.0f
|
||||
: std::min(size.x / rectSize.x, size.y / rectSize.y);
|
||||
|
||||
auto previewSize = rectSize * previewScale;
|
||||
auto canvasSize = ivec2(std::max(1.0f, previewSize.x), std::max(1.0f, previewSize.y));
|
||||
if (!canvases.contains(itemID)) canvases.emplace(itemID, Canvas(canvasSize, Canvas::FLIP));
|
||||
|
||||
auto& canvas = canvases[itemID];
|
||||
canvas.zoom = math::to_percent(previewScale);
|
||||
canvas.pan = vec2(rect.x, rect.y);
|
||||
canvas.bind();
|
||||
canvas.size_set(canvasSize);
|
||||
canvas.clear();
|
||||
actors[itemID].render(resources.shaders[shader::TEXTURE], resources.shaders[shader::RECT], canvas);
|
||||
canvas.unbind();
|
||||
|
||||
return std::tuple<Canvas&, glm::vec4&>(canvas, rect);
|
||||
};
|
||||
|
||||
if (!itemManager.returnItemIDs.empty())
|
||||
{
|
||||
for (auto& id : itemManager.returnItemIDs)
|
||||
values[id]++;
|
||||
itemManager.returnItemIDs.clear();
|
||||
}
|
||||
|
||||
if (ImGui::BeginChild("##Inventory Child", ImGui::GetContentRegionAvail(), ImGuiChildFlags_None,
|
||||
ImGuiWindowFlags_NoScrollbar))
|
||||
{
|
||||
auto inventoryCount = count();
|
||||
auto available = ImGui::GetContentRegionAvail();
|
||||
auto isItemSelected = selectedItemID >= 0 && selectedItemID < (int)schema.items.size();
|
||||
auto isInfoVisible = isItemSelected || inventoryCount == 0;
|
||||
auto infoChildHeight =
|
||||
isInfoVisible ? available.y * INFO_CHILD_HEIGHT_MULTIPLIER + ImGui::GetStyle().ItemSpacing.y * 2.0f : 0.0f;
|
||||
auto inventoryChildHeight =
|
||||
isInfoVisible ? available.y - infoChildHeight - ImGui::GetStyle().ItemSpacing.y : available.y;
|
||||
auto childSize = ImVec2(available.x, inventoryChildHeight);
|
||||
auto infoChildSize = ImVec2(available.x, infoChildHeight);
|
||||
|
||||
if (ImGui::BeginChild("##Inventory List Child", childSize))
|
||||
{
|
||||
auto cursorPos = ImGui::GetCursorPos();
|
||||
auto cursorStartX = ImGui::GetCursorPosX();
|
||||
bool isAnyInventoryItemHovered{};
|
||||
|
||||
auto size = ImVec2(SIZE, SIZE);
|
||||
|
||||
for (int i = 0; i < (int)schema.items.size(); i++)
|
||||
{
|
||||
auto& item = schema.items[i];
|
||||
auto& quantity = quantity_get(i);
|
||||
auto& rarity = schema.rarities[item.rarityID];
|
||||
|
||||
if (rarity.isHidden && quantity <= 0) continue;
|
||||
|
||||
ImGui::PushID(i);
|
||||
|
||||
ImGui::SetCursorPos(cursorPos);
|
||||
auto cursorScreenPos = ImGui::GetCursorScreenPos();
|
||||
auto [canvas, rect] = item_canvas_get(i, size);
|
||||
auto isSelected = selectedItemID == i;
|
||||
|
||||
if (isSelected)
|
||||
{
|
||||
auto selectedColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered);
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, selectedColor);
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, selectedColor);
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, selectedColor);
|
||||
}
|
||||
|
||||
auto isPressed =
|
||||
WIDGET_FX(ImGui::ImageButton("##Image Button", canvas.texture, size, ImVec2(), ImVec2(1, 1), ImVec4(),
|
||||
quantity <= 0 ? ImVec4(0, 0, 0, 0.5f) : ImVec4(1, 1, 1, 1)));
|
||||
if (isSelected) ImGui::PopStyleColor(3);
|
||||
isAnyInventoryItemHovered = isAnyInventoryItemHovered || ImGui::IsItemHovered();
|
||||
if (isPressed) selectedItemID = i;
|
||||
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left) && quantity > 0) item_use(i);
|
||||
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::BIG);
|
||||
|
||||
auto text = std::format("x{}", quantity);
|
||||
auto textPos = ImVec2(cursorScreenPos.x + size.x - ImGui::CalcTextSize(text.c_str()).x,
|
||||
cursorScreenPos.y + size.y - ImGui::GetTextLineHeightWithSpacing());
|
||||
ImGui::GetWindowDrawList()->AddText(textPos, ImGui::GetColorU32(ImGui::GetStyleColorVec4(ImGuiCol_Text)),
|
||||
text.c_str());
|
||||
ImGui::PopFont();
|
||||
|
||||
auto increment = ImGui::GetItemRectSize().x + ImGui::GetStyle().ItemSpacing.x;
|
||||
cursorPos.x += increment;
|
||||
|
||||
if (cursorPos.x + increment > ImGui::GetContentRegionAvail().x)
|
||||
{
|
||||
cursorPos.x = cursorStartX;
|
||||
cursorPos.y += increment;
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
if (ImGui::IsWindowHovered() && ImGui::IsMouseClicked(ImGuiMouseButton_Left) && !isAnyInventoryItemHovered)
|
||||
selectedItemID = -1;
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
isItemSelected = selectedItemID >= 0 && selectedItemID < (int)schema.items.size();
|
||||
auto selectedQuantity = isItemSelected ? quantity_get(selectedItemID) : 0;
|
||||
auto isSelectedItemKnown = isItemSelected && selectedQuantity > 0;
|
||||
|
||||
if (isInfoVisible &&
|
||||
ImGui::BeginChild("##Info Child", infoChildSize, ImGuiChildFlags_None, ImGuiWindowFlags_NoScrollbar))
|
||||
{
|
||||
ImGui::Separator();
|
||||
auto isButtonChildVisible = selectedQuantity > 0;
|
||||
ImGui::PushFont(resources.font.get(), Font::BIG);
|
||||
auto buttonRowHeight = ImGui::GetFrameHeight();
|
||||
auto buttonChildHeight =
|
||||
isButtonChildVisible ? buttonRowHeight * 2.0f + ImGui::GetStyle().ItemSpacing.y * 5.0f : 0.0f;
|
||||
auto buttonChildSize = ImVec2(ImGui::GetContentRegionAvail().x, buttonChildHeight);
|
||||
auto infoBodySize =
|
||||
ImVec2(ImGui::GetContentRegionAvail().x,
|
||||
ImGui::GetContentRegionAvail().y - buttonChildSize.y -
|
||||
(isButtonChildVisible ? ImGui::GetStyle().ItemSpacing.y : 0.0f));
|
||||
ImGui::PopFont();
|
||||
|
||||
if (ImGui::BeginChild("##Info Content Child", infoBodySize))
|
||||
{
|
||||
if (!isItemSelected)
|
||||
{
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::BIG);
|
||||
ImGui::TextWrapped("%s", "Check the \"Arcade\" tab to earn rewards!");
|
||||
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());
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::BIG);
|
||||
ImGui::TextWrapped("%s", "???");
|
||||
ImGui::PopFont();
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
if (isButtonChildVisible &&
|
||||
ImGui::BeginChild("##Info Actions Child", buttonChildSize, ImGuiChildFlags_None,
|
||||
ImGuiWindowFlags_NoScrollbar))
|
||||
{
|
||||
auto canUseSelectedItem = true;
|
||||
auto canUpgradeSelectedItem = is_able_to_upgrade_get(schema.items[selectedItemID], selectedQuantity);
|
||||
auto rowTwoButtonSize = row_widget_size_get(2);
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::Dummy(ImVec2(0, ImGui::GetStyle().ItemSpacing.y));
|
||||
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::BIG);
|
||||
|
||||
ImGui::BeginDisabled(!canUseSelectedItem);
|
||||
if (WIDGET_FX(ImGui::Button("Spawn", {ImGui::GetContentRegionAvail().x, 0}))) item_use(selectedItemID);
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::BeginDisabled(!canUpgradeSelectedItem);
|
||||
if (WIDGET_FX(ImGui::Button("Upgrade", rowTwoButtonSize))) item_upgrade(selectedItemID, false);
|
||||
ImGui::SameLine();
|
||||
if (WIDGET_FX(ImGui::Button("Upgrade All", rowTwoButtonSize))) item_upgrade(selectedItemID, true);
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::PopFont();
|
||||
}
|
||||
if (isButtonChildVisible) ImGui::EndChild();
|
||||
}
|
||||
if (isInfoVisible) ImGui::EndChild();
|
||||
}
|
||||
ImGui::EndChild();
|
||||
}
|
||||
|
||||
int Inventory::count()
|
||||
{
|
||||
int count{};
|
||||
for (auto& [type, quantity] : values)
|
||||
count += quantity;
|
||||
return count;
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
namespace game::state::main
|
||||
namespace game::state::play
|
||||
{
|
||||
class Inventory
|
||||
{
|
||||
@@ -19,6 +19,7 @@ namespace game::state::main
|
||||
std::unordered_map<int, entity::Actor> actors{};
|
||||
std::unordered_map<int, glm::vec4> rects{};
|
||||
std::unordered_map<int, Canvas> canvases{};
|
||||
int selectedItemID{-1};
|
||||
|
||||
void tick();
|
||||
void update(Resources&, ItemManager&, entity::Character&);
|
||||
@@ -13,7 +13,7 @@ using namespace game::resource;
|
||||
using namespace game::util;
|
||||
using namespace glm;
|
||||
|
||||
namespace game::state::main
|
||||
namespace game::state::play
|
||||
{
|
||||
void ItemManager::update(entity::Character& character, entity::Cursor& cursor, AreaManager& areaManager, Text& text,
|
||||
const glm::vec4& bounds, Canvas& canvas)
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "area_manager.hpp"
|
||||
#include "text.hpp"
|
||||
|
||||
namespace game::state::main
|
||||
namespace game::state::play
|
||||
{
|
||||
class ItemManager
|
||||
{
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "menu.hpp"
|
||||
|
||||
#include "../../util/imgui.hpp"
|
||||
#include "../../util/imgui/style.hpp"
|
||||
#include "../../util/imgui/widget.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
@@ -8,12 +9,17 @@
|
||||
using namespace game::util;
|
||||
using namespace game::util::imgui;
|
||||
|
||||
namespace game::state::main
|
||||
namespace game::state::play
|
||||
{
|
||||
void Menu::tick()
|
||||
{
|
||||
inventory.tick();
|
||||
play.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);
|
||||
}
|
||||
|
||||
void Menu::update(Resources& resources, ItemManager& itemManager, entity::Character& character,
|
||||
@@ -61,13 +67,13 @@ namespace game::state::main
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (WIDGET_FX(ImGui::BeginTabItem("Play")))
|
||||
if (WIDGET_FX(ImGui::BeginTabItem("Arcade")))
|
||||
{
|
||||
play.update(resources, character, inventory, text);
|
||||
skillCheck.update(resources, character, inventory, text);
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (WIDGET_FX(ImGui::BeginTabItem("Items")))
|
||||
if (WIDGET_FX(ImGui::BeginTabItem("Inventory")))
|
||||
{
|
||||
inventory.update(resources, itemManager, character);
|
||||
ImGui::EndTabItem();
|
||||
@@ -75,13 +81,14 @@ namespace game::state::main
|
||||
|
||||
if (WIDGET_FX(ImGui::BeginTabItem("Stats")))
|
||||
{
|
||||
stats.update(resources, play, character);
|
||||
stats.update(resources, skillCheck, character);
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (WIDGET_FX(ImGui::BeginTabItem("Settings")))
|
||||
{
|
||||
configuration.update(resources, Configuration::MAIN);
|
||||
settingsMenu.update(resources, SettingsMenu::PLAY);
|
||||
if (settingsMenu.isJustColorSet) color_set_check(resources, character);
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
@@ -91,11 +98,13 @@ namespace game::state::main
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (isDebug && WIDGET_FX(ImGui::BeginTabItem("Debug")))
|
||||
#if DEBUG
|
||||
if (WIDGET_FX(ImGui::BeginTabItem("Debug")))
|
||||
{
|
||||
debug.update(character, cursor, itemManager, canvas);
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
@@ -2,37 +2,35 @@
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include "../configuration.hpp"
|
||||
#include "../settings_menu.hpp"
|
||||
|
||||
#include "arcade/skill_check.hpp"
|
||||
#include "chat.hpp"
|
||||
#include "cheats.hpp"
|
||||
#include "debug.hpp"
|
||||
#include "play.hpp"
|
||||
#include "stats.hpp"
|
||||
#include "text.hpp"
|
||||
|
||||
#include "../../util/imgui/window_slide.hpp"
|
||||
|
||||
namespace game::state::main
|
||||
namespace game::state::play
|
||||
{
|
||||
class Menu
|
||||
{
|
||||
public:
|
||||
Play play;
|
||||
SkillCheck skillCheck;
|
||||
Chat chat;
|
||||
Cheats cheats;
|
||||
Debug debug;
|
||||
Stats stats;
|
||||
Inventory inventory;
|
||||
|
||||
state::Configuration configuration;
|
||||
state::SettingsMenu settingsMenu;
|
||||
|
||||
#if DEBUG
|
||||
bool isCheats{true};
|
||||
#elif
|
||||
bool isCheats{};
|
||||
bool isDebug{true};
|
||||
#else
|
||||
bool isCheats{};
|
||||
bool isDebug{};
|
||||
#endif
|
||||
|
||||
bool isOpen{true};
|
||||
@@ -41,5 +39,6 @@ namespace game::state::main
|
||||
|
||||
void tick();
|
||||
void update(Resources&, ItemManager&, entity::Character&, entity::Cursor&, Text&, Canvas&);
|
||||
void color_set_check(Resources&, entity::Character&);
|
||||
};
|
||||
}
|
||||
@@ -7,9 +7,9 @@
|
||||
using namespace game::resource;
|
||||
using namespace game::util;
|
||||
|
||||
namespace game::state::main
|
||||
namespace game::state::play
|
||||
{
|
||||
void Stats::update(Resources& resources, Play& play, entity::Character& character)
|
||||
void Stats::update(Resources& resources, SkillCheck& skillCheck, entity::Character& character)
|
||||
{
|
||||
ImGui::PushFont(ImGui::GetFont(), Font::BIG);
|
||||
ImGui::TextUnformatted(character.data.name.c_str());
|
||||
@@ -17,7 +17,7 @@ namespace game::state::main
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
auto& playSchema = character.data.playSchema;
|
||||
auto& skillCheckSchema = character.data.skillCheckSchema;
|
||||
auto& system = resources.settings.measurementSystem;
|
||||
auto weight = character.weight_get(system);
|
||||
auto weightUnit = system == measurement::IMPERIAL ? "lbs" : "kg";
|
||||
@@ -32,17 +32,17 @@ namespace game::state::main
|
||||
ImGui::Text("Total Calories Consumed: %0.0f kcal", character.totalCaloriesConsumed);
|
||||
ImGui::Text("Total Food Items Eaten: %i", character.totalFoodItemsEaten);
|
||||
|
||||
ImGui::SeparatorText("Play");
|
||||
ImGui::SeparatorText("Skill Check");
|
||||
|
||||
ImGui::Text("Best: %i pts (%ix)", play.highScore, play.bestCombo);
|
||||
ImGui::Text("Total Plays: %i", play.totalPlays);
|
||||
ImGui::Text("Best: %i pts (%ix)", skillCheck.highScore, skillCheck.bestCombo);
|
||||
ImGui::Text("Total Skill Checks: %i", skillCheck.totalPlays);
|
||||
|
||||
for (int i = 0; i < (int)playSchema.grades.size(); i++)
|
||||
for (int i = 0; i < (int)skillCheckSchema.grades.size(); i++)
|
||||
{
|
||||
auto& grade = playSchema.grades[i];
|
||||
ImGui::Text("%s: %i", grade.namePlural.c_str(), play.gradeCounts[i]);
|
||||
auto& grade = skillCheckSchema.grades[i];
|
||||
ImGui::Text("%s: %i", grade.namePlural.c_str(), skillCheck.gradeCounts[i]);
|
||||
}
|
||||
|
||||
ImGui::Text("Accuracy: %0.2f%%", play.accuracy_score_get(character));
|
||||
ImGui::Text("Accuracy: %0.2f%%", skillCheck.accuracy_score_get(character));
|
||||
}
|
||||
}
|
||||
@@ -3,15 +3,15 @@
|
||||
#include "../../entity/character.hpp"
|
||||
#include "../../resources.hpp"
|
||||
|
||||
#include "play.hpp"
|
||||
#include "arcade/skill_check.hpp"
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
namespace game::state::main
|
||||
namespace game::state::play
|
||||
{
|
||||
class Stats
|
||||
{
|
||||
public:
|
||||
void update(Resources&, Play&, entity::Character&);
|
||||
void update(Resources&, SkillCheck&, entity::Character&);
|
||||
};
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
using namespace game::util;
|
||||
|
||||
namespace game::state::main
|
||||
namespace game::state::play
|
||||
{
|
||||
const char* utf8_advance_chars(const char* text, const char* end, int count)
|
||||
{
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include "../../resources.hpp"
|
||||
|
||||
namespace game::state::main
|
||||
namespace game::state::play
|
||||
{
|
||||
class Text
|
||||
{
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <imgui.h>
|
||||
#include <ranges>
|
||||
|
||||
namespace game::state::main
|
||||
namespace game::state::play
|
||||
{
|
||||
void Toasts::tick()
|
||||
{
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace game::state::main
|
||||
namespace game::state::play
|
||||
{
|
||||
class Toasts
|
||||
{
|
||||
@@ -8,7 +8,7 @@
|
||||
using namespace game::util;
|
||||
using namespace game::util::imgui;
|
||||
|
||||
namespace game::state::main
|
||||
namespace game::state::play
|
||||
{
|
||||
void Tools::update(entity::Character& character, entity::Cursor& cursor, World& world, World::Focus focus,
|
||||
Canvas& canvas)
|
||||
@@ -47,21 +47,20 @@ namespace game::state::main
|
||||
{
|
||||
auto buttonSize = imgui::to_imvec2(vec2(ImGui::GetContentRegionAvail().x));
|
||||
|
||||
auto cursor_mode_button = [&](const char* name, InteractType mode)
|
||||
auto cursor_mode_button = [&](const std::string& name, int interactTypeID)
|
||||
{
|
||||
auto isMode = cursor.mode == mode;
|
||||
auto isMode = cursor.interactTypeID == interactTypeID;
|
||||
ImGui::PushStyleColor(ImGuiCol_Button,
|
||||
ImGui::GetStyleColorVec4(isMode ? ImGuiCol_ButtonHovered : ImGuiCol_Button));
|
||||
if (WIDGET_FX(ImGui::Button(name, buttonSize))) cursor.mode = mode;
|
||||
if (WIDGET_FX(ImGui::Button(name.c_str(), buttonSize))) cursor.interactTypeID = interactTypeID;
|
||||
ImGui::PopStyleColor();
|
||||
};
|
||||
|
||||
if (WIDGET_FX(ImGui::Button("Home", buttonSize))) world.character_focus(character, canvas, focus);
|
||||
ImGui::SetItemTooltip("%s", "Reset camera view.\n(Shortcut: Home)");
|
||||
|
||||
cursor_mode_button("Rub", InteractType::RUB);
|
||||
cursor_mode_button("Kiss", InteractType::KISS);
|
||||
cursor_mode_button("Smack", InteractType::SMACK);
|
||||
for (int i = 0; i < (int)character.data.interactTypeNames.size(); i++)
|
||||
cursor_mode_button(character.data.interactTypeNames[i], i);
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "../../util/imgui/window_slide.hpp"
|
||||
#include "world.hpp"
|
||||
|
||||
namespace game::state::main
|
||||
namespace game::state::play
|
||||
{
|
||||
class Tools
|
||||
{
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
using namespace game::util;
|
||||
|
||||
namespace game::state::main
|
||||
namespace game::state::play
|
||||
{
|
||||
void World::set(entity::Character& character, Canvas& canvas, Focus focus)
|
||||
{
|
||||
@@ -1,12 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../canvas.hpp"
|
||||
#include "../../render/canvas.hpp"
|
||||
#include "../../entity/character.hpp"
|
||||
|
||||
#include "character_manager.hpp"
|
||||
#include "item_manager.hpp"
|
||||
|
||||
namespace game::state::main
|
||||
namespace game::state::play
|
||||
{
|
||||
class World
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../canvas.hpp"
|
||||
#include "../render/canvas.hpp"
|
||||
|
||||
#include "select/characters.hpp"
|
||||
#include "select/info.hpp"
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#include "characters.hpp"
|
||||
|
||||
#include <ranges>
|
||||
|
||||
#include "../../util/imgui/style.hpp"
|
||||
#include "../../util/imgui/widget.hpp"
|
||||
|
||||
using namespace game::util::imgui;
|
||||
using namespace game::util;
|
||||
|
||||
namespace game::state::select
|
||||
{
|
||||
@@ -39,6 +38,7 @@ namespace game::state::select
|
||||
ImGui::PushID(i);
|
||||
|
||||
ImGui::SetCursorPos(cursorPos);
|
||||
imgui::style::color_set(character.color);
|
||||
|
||||
auto isSelected = i == characterIndex;
|
||||
|
||||
@@ -64,13 +64,14 @@ namespace game::state::select
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
imgui::style::color_set(resources.settings.color);
|
||||
}
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (WIDGET_FX(ImGui::BeginTabItem("Configuration")))
|
||||
if (WIDGET_FX(ImGui::BeginTabItem("Settings")))
|
||||
{
|
||||
configuration.update(resources);
|
||||
settingsMenu.update(resources);
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
ImGui::EndTabBar();
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../resources.hpp"
|
||||
#include "../configuration.hpp"
|
||||
#include "../settings_menu.hpp"
|
||||
|
||||
namespace game::state::select
|
||||
{
|
||||
class Characters
|
||||
{
|
||||
public:
|
||||
Configuration configuration;
|
||||
SettingsMenu settingsMenu;
|
||||
|
||||
void update(Resources&, int& characterIndex);
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "../../util/color.hpp"
|
||||
#include "../../util/imgui.hpp"
|
||||
#include "../../util/imgui/style.hpp"
|
||||
#include "../../util/imgui/widget.hpp"
|
||||
#include "../../util/vector.hpp"
|
||||
|
||||
@@ -18,6 +19,7 @@ namespace game::state::select
|
||||
|
||||
auto& style = ImGui::GetStyle();
|
||||
auto viewport = ImGui::GetMainViewport();
|
||||
auto& character = resources.characterPreviews[characterIndex];
|
||||
|
||||
auto size = ImVec2(viewport->Size.x / 2.0f - (style.WindowPadding.x * 2.0f),
|
||||
(viewport->Size.y / 2.0f) - (style.WindowPadding.y * 2.0f));
|
||||
@@ -25,12 +27,12 @@ namespace game::state::select
|
||||
|
||||
ImGui::SetNextWindowSize(size);
|
||||
ImGui::SetNextWindowPos(pos);
|
||||
imgui::style::color_set(character.color);
|
||||
|
||||
if (ImGui::Begin("##Info", nullptr,
|
||||
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse |
|
||||
ImGuiWindowFlags_NoTitleBar))
|
||||
{
|
||||
auto& character = resources.characterPreviews[characterIndex];
|
||||
auto& save = character.save;
|
||||
auto& system = resources.settings.measurementSystem;
|
||||
auto& weight = save.is_valid() ? save.weight : character.weight;
|
||||
@@ -123,5 +125,6 @@ namespace game::state::select
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
imgui::style::color_set(resources.settings.color);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <cmath>
|
||||
|
||||
#include "../../util/imgui.hpp"
|
||||
#include "../../util/imgui/style.hpp"
|
||||
#include "../../util/imgui/widget.hpp"
|
||||
#include "../../util/vector.hpp"
|
||||
|
||||
@@ -25,13 +26,14 @@ namespace game::state::select
|
||||
|
||||
auto& style = ImGui::GetStyle();
|
||||
auto viewport = ImGui::GetMainViewport();
|
||||
|
||||
auto& character = resources.characterPreviews[characterIndex];
|
||||
auto size = ImVec2(viewport->Size.x / 2.0f - (style.WindowPadding.x * 2.0f),
|
||||
(viewport->Size.y / 2.0f) - (style.WindowPadding.y * 2.0f));
|
||||
auto pos = ImVec2(style.WindowPadding.x, style.WindowPadding.y);
|
||||
|
||||
ImGui::SetNextWindowSize(size);
|
||||
ImGui::SetNextWindowPos(pos);
|
||||
imgui::style::color_set(character.color);
|
||||
|
||||
if (ImGui::Begin("##Preview", nullptr,
|
||||
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse |
|
||||
@@ -39,8 +41,6 @@ namespace game::state::select
|
||||
{
|
||||
if (ImGui::BeginTabBar("##Preview Tab Bar"))
|
||||
{
|
||||
auto& character = resources.characterPreviews[characterIndex];
|
||||
|
||||
auto available = ImGui::GetContentRegionAvail();
|
||||
auto availableSize = imgui::to_vec2(available);
|
||||
auto textureSize = vec2(character.render.size);
|
||||
@@ -106,5 +106,6 @@ namespace game::state::select
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
imgui::style::color_set(resources.settings.color);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "configuration.hpp"
|
||||
#include "settings_menu.hpp"
|
||||
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <imgui.h>
|
||||
@@ -13,13 +13,15 @@ using namespace game::util::imgui;
|
||||
|
||||
namespace game::state
|
||||
{
|
||||
void Configuration::update(Resources& resources, Mode mode)
|
||||
void SettingsMenu::update(Resources& resources, Mode mode)
|
||||
{
|
||||
auto& settings = resources.settings;
|
||||
auto& measurementSystem = settings.measurementSystem;
|
||||
auto& volume = settings.volume;
|
||||
auto& color = settings.color;
|
||||
|
||||
isJustColorSet = false;
|
||||
|
||||
ImGui::SeparatorText("Measurement System");
|
||||
WIDGET_FX(ImGui::RadioButton("Metric", (int*)&measurementSystem, measurement::METRIC));
|
||||
ImGui::SetItemTooltip("%s", "Use kilograms (kg).");
|
||||
@@ -34,10 +36,18 @@ namespace game::state
|
||||
|
||||
ImGui::SeparatorText("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.");
|
||||
ImGui::SameLine();
|
||||
ImGui::BeginDisabled(settings.isUseCharacterColor);
|
||||
if (WIDGET_FX(
|
||||
ImGui::ColorEdit3("Color", value_ptr(color), ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoTooltip)))
|
||||
{
|
||||
style::color_set(color);
|
||||
isJustColorSet = true;
|
||||
}
|
||||
ImGui::SetItemTooltip("%s", "Change the UI color.");
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::Separator();
|
||||
if (WIDGET_FX(ImGui::Button("Reset to Default", ImVec2(-FLT_MIN, 0))))
|
||||
@@ -46,7 +56,7 @@ namespace game::state
|
||||
style::color_set(settings.color);
|
||||
}
|
||||
|
||||
if (mode == MAIN)
|
||||
if (mode == PLAY)
|
||||
{
|
||||
ImGui::Separator();
|
||||
|
||||
@@ -4,17 +4,18 @@
|
||||
|
||||
namespace game::state
|
||||
{
|
||||
class Configuration
|
||||
class SettingsMenu
|
||||
{
|
||||
public:
|
||||
enum Mode
|
||||
{
|
||||
SELECT,
|
||||
MAIN
|
||||
PLAY
|
||||
};
|
||||
|
||||
bool isGoToSelect{};
|
||||
bool isSave{};
|
||||
bool isJustColorSet{};
|
||||
|
||||
void update(Resources&, Mode = SELECT);
|
||||
};
|
||||
@@ -1,24 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace game
|
||||
{
|
||||
#define LIST \
|
||||
X(RUB, "Rub") \
|
||||
X(KISS, "Kiss") \
|
||||
X(SMACK, "Smack")
|
||||
|
||||
enum InteractType
|
||||
{
|
||||
#define X(symbol, string) symbol,
|
||||
LIST
|
||||
#undef X
|
||||
};
|
||||
|
||||
static constexpr const char* INTERACT_TYPE_STRINGS[] = {
|
||||
#define X(symbol, string) string,
|
||||
LIST
|
||||
#undef X
|
||||
};
|
||||
|
||||
#undef LIST
|
||||
}
|
||||
Reference in New Issue
Block a user