UPGRADE! + cheats
Some checks failed
Build / Build Game (push) Has been cancelled

This commit is contained in:
2026-03-02 14:02:14 -05:00
parent 475fb5a847
commit 2a58c3b24b
10 changed files with 141 additions and 6 deletions

View File

@@ -56,7 +56,7 @@ The file path of the area's texture (background).
Gravity the area has; applies to items' velocities per tick. Gravity the area has; applies to items' velocities per tick.
#### Friction (float) #### Friction (float)
Friction of the area; applies to items' velocities when grounded or hitting walls. Friction of the area; applies to items' velocities when grounded or hitting walls.
### AirResistance (float) #### AirResistance (float)
Air resistance of the area; applies to items' velocities when airborne. Air resistance of the area; applies to items' velocities when airborne.
## character.xml ## character.xml
@@ -416,6 +416,10 @@ The additional eat speed multiplier the item will give if eaten.
The item's gravity; will use the default gravity if not available. The item's gravity; will use the default gravity if not available.
#### ChewCount (int; optional) #### ChewCount (int; optional)
An item's custom chew count. An item's custom chew count.
#### UpgradeID (string; optional)
The name of another item that this item will be able to be upgraded to.
#### UpgradeCount (int; optional)
The amount of this item it will take to upgrade to the upgrade item specified in UpgradeID.
#### IsPlayReward (bool; optional) #### IsPlayReward (bool; optional)
The item will be given out when the reward is hit in play (see play.xml) The item will be given out when the reward is hit in play (see play.xml)
#### IsToggleSpritesheet (bool; optional) #### IsToggleSpritesheet (bool; optional)
@@ -451,6 +455,10 @@ The sound that will play, based on SoundRootPath.
Will play when clicking on a widget in a menu. Will play when clicking on a widget in a menu.
#### Sound (path) #### Sound (path)
The sound that will play, based on SoundRootPath. The sound that will play, based on SoundRootPath.
### CheatsActivated
Sound that will play after entering a special code to activate cheats.
#### Sound (path)
The sound that will play, based on SoundRootPath.
## play.xml ## play.xml
Determines behavior and appearance of the "Play" minigame. Determines behavior and appearance of the "Play" minigame.

View File

@@ -87,6 +87,22 @@ namespace game::resource::xml
query_sound_entry_collection(element, "Dispose", archive, soundRootPath, sounds.dispose); query_sound_entry_collection(element, "Dispose", archive, soundRootPath, sounds.dispose);
query_sound_entry_collection(element, "Return", archive, soundRootPath, sounds.return_); query_sound_entry_collection(element, "Return", archive, soundRootPath, sounds.return_);
query_sound_entry_collection(element, "Summon", archive, soundRootPath, sounds.summon); query_sound_entry_collection(element, "Summon", archive, soundRootPath, sounds.summon);
query_sound_entry_collection(element, "Upgrade", archive, soundRootPath, sounds.upgrade);
query_sound_entry_collection(element, "UpgradeFail", archive, soundRootPath, sounds.upgradeFail);
}
if (auto element = root->FirstChildElement("Items"))
{
int id{};
for (auto child = element->FirstChildElement("Item"); child; child = child->NextSiblingElement("Item"))
{
std::string name{};
query_string_attribute(child, "Name", &name);
stringToIDMap[name] = id;
idToStringMap[id] = name;
id++;
}
} }
if (auto element = root->FirstChildElement("Items")) if (auto element = root->FirstChildElement("Items"))
@@ -108,7 +124,24 @@ namespace game::resource::xml
query_float_optional_attribute(child, "DigestionBonus", item.digestionBonus); query_float_optional_attribute(child, "DigestionBonus", item.digestionBonus);
query_float_optional_attribute(child, "EatSpeedBonus", item.eatSpeedBonus); query_float_optional_attribute(child, "EatSpeedBonus", item.eatSpeedBonus);
query_float_optional_attribute(child, "Gravity", item.gravity); query_float_optional_attribute(child, "Gravity", item.gravity);
query_int_optional_attribute(child, "ChewCount", item.chewCount); query_int_optional_attribute(child, "ChewCount", item.chewCount);
if (child->FindAttribute("UpgradeID"))
{
std::string upgradeIDString{};
query_string_attribute(child, "UpgradeID", &upgradeIDString);
if (!upgradeIDString.empty() && stringToIDMap.contains(upgradeIDString))
item.upgradeID = stringToIDMap[upgradeIDString];
else if (upgradeIDString.empty())
logger.warning(std::format("Empty UpgradeID ({})", item.name));
else
logger.warning(std::format("Could not find item ID for UpgradeID: {} ({})", upgradeIDString, item.name));
query_int_optional_attribute(child, "UpgradeCount", item.upgradeCount);
}
query_bool_attribute(child, "IsPlayReward", &item.isPlayReward); query_bool_attribute(child, "IsPlayReward", &item.isPlayReward);
query_bool_attribute(child, "IsToggleSpritesheet", &item.isToggleSpritesheet); query_bool_attribute(child, "IsToggleSpritesheet", &item.isToggleSpritesheet);

View File

@@ -42,6 +42,8 @@ namespace game::resource::xml
std::string description{UNDEFINED}; std::string description{UNDEFINED};
int categoryID{}; int categoryID{};
int rarityID{}; int rarityID{};
std::optional<int> upgradeCount{};
std::optional<int> upgradeID{};
std::optional<int> flavorID; std::optional<int> flavorID;
std::optional<float> calories{}; std::optional<float> calories{};
std::optional<float> eatSpeedBonus{}; std::optional<float> eatSpeedBonus{};
@@ -63,11 +65,15 @@ namespace game::resource::xml
SoundEntryCollection return_{}; SoundEntryCollection return_{};
SoundEntryCollection dispose{}; SoundEntryCollection dispose{};
SoundEntryCollection summon{}; SoundEntryCollection summon{};
SoundEntryCollection upgrade{};
SoundEntryCollection upgradeFail{};
}; };
std::unordered_map<std::string, int> categoryMap{}; std::unordered_map<std::string, int> categoryMap{};
std::unordered_map<std::string, int> rarityMap{}; std::unordered_map<std::string, int> rarityMap{};
std::unordered_map<std::string, int> flavorMap{}; std::unordered_map<std::string, int> flavorMap{};
std::unordered_map<std::string, int> stringToIDMap{};
std::unordered_map<int, std::string> idToStringMap{};
using Pool = std::vector<int>; using Pool = std::vector<int>;

View File

@@ -36,6 +36,7 @@ namespace game::resource::xml
query_sound_entry_collection(element, "Close", archive, soundRootPath, sounds.close); query_sound_entry_collection(element, "Close", archive, soundRootPath, sounds.close);
query_sound_entry_collection(element, "Hover", archive, soundRootPath, sounds.hover); query_sound_entry_collection(element, "Hover", archive, soundRootPath, sounds.hover);
query_sound_entry_collection(element, "Select", archive, soundRootPath, sounds.select); query_sound_entry_collection(element, "Select", archive, soundRootPath, sounds.select);
query_sound_entry_collection(element, "CheatsActivated", archive, soundRootPath, sounds.cheatsActivated);
} }
} }

View File

@@ -15,6 +15,7 @@ namespace game::resource::xml
SoundEntryCollection close{}; SoundEntryCollection close{};
SoundEntryCollection hover{}; SoundEntryCollection hover{};
SoundEntryCollection select{}; SoundEntryCollection select{};
SoundEntryCollection cheatsActivated{};
}; };
Sounds sounds{}; Sounds sounds{};

View File

@@ -1,5 +1,6 @@
#include "main.hpp" #include "main.hpp"
#include <array>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <imgui.h> #include <imgui.h>
#include <imgui_impl_opengl3.h> #include <imgui_impl_opengl3.h>
@@ -34,6 +35,8 @@ namespace game::state
auto& dialogue = data.dialogue; auto& dialogue = data.dialogue;
auto& menuSchema = data.menuSchema; auto& menuSchema = data.menuSchema;
this->characterIndex = selectedCharacterIndex; this->characterIndex = selectedCharacterIndex;
konamiCodeIndex = 0;
konamiCodeStartTime = 0.0;
character = character =
entity::Character(data, vec2(World::BOUNDS.x + World::BOUNDS.z * 0.5f, World::BOUNDS.w - World::BOUNDS.y)); entity::Character(data, vec2(World::BOUNDS.x + World::BOUNDS.z * 0.5f, World::BOUNDS.w - World::BOUNDS.y));
@@ -132,9 +135,55 @@ namespace game::state
void Main::update(Resources& resources) void Main::update(Resources& resources)
{ {
static constexpr std::array<ImGuiKey, 10> KONAMI_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 = {
ImGuiKey_UpArrow, ImGuiKey_DownArrow, ImGuiKey_LeftArrow, ImGuiKey_RightArrow, ImGuiKey_B, ImGuiKey_A};
static constexpr auto KONAMI_CODE_INPUT_TIME_SECONDS = 5.0;
auto focus = focus_get(); auto focus = focus_get();
auto& dialogue = character.data.dialogue; auto& dialogue = character.data.dialogue;
if (!menu.isCheats)
{
for (auto key : KONAMI_INPUT_KEYS)
{
if (!ImGui::IsKeyPressed(key, false)) continue;
if (key == KONAMI_CODE[konamiCodeIndex])
{
konamiCodeIndex++;
konamiCodeStartTime = ImGui::GetTime();
}
else if (key == KONAMI_CODE[0])
{
konamiCodeIndex = 1;
konamiCodeStartTime = ImGui::GetTime();
}
else
{
konamiCodeIndex = 0;
konamiCodeStartTime = 0.0;
}
if (konamiCodeIndex >= (int)KONAMI_CODE.size())
{
menu.isCheats = true;
konamiCodeIndex = 0;
konamiCodeStartTime = 0.0;
toasts.push("Cheats unlocked!");
character.data.menuSchema.sounds.cheatsActivated.play();
}
}
if (konamiCodeIndex > 0 && (ImGui::GetTime() - konamiCodeStartTime > KONAMI_CODE_INPUT_TIME_SECONDS))
{
konamiCodeIndex = 0;
konamiCodeStartTime = 0.0;
}
}
if (isWindows) if (isWindows)
{ {
menu.update(resources, itemManager, character, cursor, text, worldCanvas); menu.update(resources, itemManager, character, cursor, text, worldCanvas);

View File

@@ -42,6 +42,8 @@ namespace game::state
int areaIndex{}; int areaIndex{};
float autosaveTime{}; float autosaveTime{};
int konamiCodeIndex{};
double konamiCodeStartTime{};
bool isWindows{true}; bool isWindows{true};

View File

@@ -76,6 +76,9 @@ namespace game::state::main
auto canvasSize = ivec2(std::max(1.0f, previewSize.x), std::max(1.0f, previewSize.y)); 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)); if (!canvases.contains(i)) canvases.emplace((int)i, Canvas(canvasSize, Canvas::FLIP));
auto& canvas = canvases[i]; 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.zoom = math::to_percent(previewScale);
canvas.pan = vec2(rect.x, rect.y); canvas.pan = vec2(rect.x, rect.y);
canvas.bind(); canvas.bind();
@@ -90,7 +93,30 @@ namespace game::state::main
quantity <= 0 ? ImVec4(0, 0, 0, 1) : ImVec4(1, 1, 1, 1))) && quantity <= 0 ? ImVec4(0, 0, 0, 1) : ImVec4(1, 1, 1, 1))) &&
quantity > 0) quantity > 0)
{ {
if (category.isEdible) 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) if (itemManager.items.size() + 1 >= ItemManager::LIMIT)
character.data.itemSchema.sounds.dispose.play(); character.data.itemSchema.sounds.dispose.play();
@@ -143,6 +169,14 @@ namespace game::state::main
else if (eatSpeedBonus < 0) else if (eatSpeedBonus < 0)
ImGui::Text("Eat Speed Penalty: %0.2f%% / sec", *eatSpeedBonus); 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::PopStyleColor();
ImGui::Separator(); ImGui::Separator();

View File

@@ -28,13 +28,13 @@ namespace game::state::main
state::Configuration configuration; state::Configuration configuration;
#if DEBUG #if DEBUG
bool isCheats{true}; bool isCheats{};
bool isDebug{true}; bool isDebug{true};
#else #else
bool isCheats{}; bool isCheats{};
bool isDebug{}; bool isDebug{};
#endif #endif
bool isOpen{true}; bool isOpen{true};
bool isChat{true}; bool isChat{true};
util::imgui::WindowSlide slide{}; util::imgui::WindowSlide slide{};

View File

@@ -22,13 +22,14 @@ namespace game::state::main
auto& pan = canvas.pan; auto& pan = canvas.pan;
auto& zoom = canvas.zoom; auto& zoom = canvas.zoom;
auto& io = ImGui::GetIO(); auto& io = ImGui::GetIO();
bool isPan{true};
auto isMouseMiddleDown = ImGui::IsMouseDown(ImGuiMouseButton_Middle); auto isMouseMiddleDown = ImGui::IsMouseDown(ImGuiMouseButton_Middle);
auto isMouseLeftDown = ImGui::IsMouseDown(ImGuiMouseButton_Left);
auto isCtrlDown = ImGui::IsKeyDown(ImGuiMod_Ctrl);
auto panMultiplier = ZOOM_BASE / zoom; auto panMultiplier = ZOOM_BASE / zoom;
if (!ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow) && !ImGui::IsAnyItemActive()) if (!ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow) && !ImGui::IsAnyItemActive())
{ {
if ((isMouseMiddleDown) && isPan) if ((isMouseMiddleDown) || (isMouseLeftDown && isCtrlDown))
{ {
cursor.queue_play({cursorSchema.animations.pan.get()}); cursor.queue_play({cursorSchema.animations.pan.get()});
pan -= imgui::to_vec2(io.MouseDelta) * panMultiplier; pan -= imgui::to_vec2(io.MouseDelta) * panMultiplier;