From 1080e9b08ff0b3f09eb5b84c09f013901e1164db Mon Sep 17 00:00:00 2001 From: Mihai Dumitrescu Date: Fri, 13 Mar 2026 21:34:15 +0200 Subject: [PATCH 1/6] Implement level system Signed-off-by: Mihai Dumitrescu --- src/Rpg/mainCharacter/LevelSystem.cpp | 48 +++++++++++++++++++++++++++ src/Rpg/mainCharacter/LevelSystem.h | 27 +++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 src/Rpg/mainCharacter/LevelSystem.cpp create mode 100644 src/Rpg/mainCharacter/LevelSystem.h diff --git a/src/Rpg/mainCharacter/LevelSystem.cpp b/src/Rpg/mainCharacter/LevelSystem.cpp new file mode 100644 index 0000000..c8cf7c2 --- /dev/null +++ b/src/Rpg/mainCharacter/LevelSystem.cpp @@ -0,0 +1,48 @@ +#include "LevelSystem.h" +#include +#include "../inventory/items/TowerBlueprintEpic.h" + + +LevelSystem::LevelSystem(Inventory* inventory, int maxLevel) + : mInventory(inventory), mCurrentXp(0), mCurrentLevel(0), mMaxLevel(maxLevel) { + +} + +void LevelSystem::addXp(int xp) { + if (mCurrentLevel < mMaxLevel) { + mCurrentXp += xp; + checkLevelUp(); + } +} + +void LevelSystem::checkLevelUp() { + while (mCurrentLevel < mMaxLevel && mCurrentXp >= getXpForNextLevel()) { + mCurrentXp -= getXpForNextLevel(); + mCurrentLevel++; + + grantRewards(mCurrentLevel); + } +} + +void LevelSystem::grantRewards(int level) { + std::cout << "Leveled up!" << std::endl; +} + +int LevelSystem::getCurrentXp() const { + return mCurrentXp; +} + +int LevelSystem::getLevel() const { + return mCurrentLevel; +} + +int LevelSystem::getXpForNextLevel() const { + return static_cast(100.f * std::pow(mCurrentLevel, 1.25f)); +} + +float LevelSystem::getXpPercentage() const { + if (mCurrentLevel >= mMaxLevel) + return 1.f; + + return static_cast(mCurrentXp) / static_cast(getXpForNextLevel()); +} diff --git a/src/Rpg/mainCharacter/LevelSystem.h b/src/Rpg/mainCharacter/LevelSystem.h new file mode 100644 index 0000000..77efa2c --- /dev/null +++ b/src/Rpg/mainCharacter/LevelSystem.h @@ -0,0 +1,27 @@ +#pragma once +#include +#include +#include "../inventory/Inventory.h" + +class LevelSystem { +public: + LevelSystem(Inventory* inventory, int maxLevel = 50); + + void addXp(int xp); + + int getLevel() const; + int getCurrentXp() const; + int getXpForNextLevel() const; + float getXpPercentage() const; + + void grantRewards(int level); + +private: + void checkLevelUp(); + + int mCurrentLevel; + int mCurrentXp; + int mMaxLevel; + + Inventory* mInventory; +}; From bf6f3c2b33d71df822b915257f8a95b97d62829f Mon Sep 17 00:00:00 2001 From: Mihai Dumitrescu Date: Sat, 14 Mar 2026 23:44:26 +0200 Subject: [PATCH 2/6] Add level system to main character Signed-off-by: Mihai Dumitrescu --- src/Rpg/gamengine/RPGEngine.cpp | 2 +- src/Rpg/mainCharacter/LevelSystem.cpp | 8 ++++++++ src/Rpg/mainCharacter/MainCharacter.cpp | 8 ++++++-- src/Rpg/mainCharacter/MainCharacter.h | 8 +++++++- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/Rpg/gamengine/RPGEngine.cpp b/src/Rpg/gamengine/RPGEngine.cpp index ae0a900..a1eaf25 100755 --- a/src/Rpg/gamengine/RPGEngine.cpp +++ b/src/Rpg/gamengine/RPGEngine.cpp @@ -47,7 +47,7 @@ static bool intersects(const sf::FloatRect& rect1, const sf::FloatRect& rect2) { RPGEngine::RPGEngine(sf::RenderWindow& window, GameManager* gameManager) : mWindow(window), mTimeSystem(0.36f), - mCharacter(sf::Vector2f(295.f, 290.f)), + mCharacter(sf::Vector2f(295.f, 290.f), &mInventory), mView(sf::Vector2f(400.f, 300.f), sf::Vector2f(740.f, 420.f)), mFixedCamera(sf::Vector2f(0.f, 0.f), sf::Vector2f(740.f, 420.f)), mCameraFixedPosition(sf::Vector2f(0.f, 0.f)), diff --git a/src/Rpg/mainCharacter/LevelSystem.cpp b/src/Rpg/mainCharacter/LevelSystem.cpp index c8cf7c2..671d6ca 100644 --- a/src/Rpg/mainCharacter/LevelSystem.cpp +++ b/src/Rpg/mainCharacter/LevelSystem.cpp @@ -26,6 +26,14 @@ void LevelSystem::checkLevelUp() { void LevelSystem::grantRewards(int level) { std::cout << "Leveled up!" << std::endl; + if (level == 2) { + std::unique_ptr towerBlueprintItem = std::make_unique(); + mInventory->addItem(std::move(towerBlueprintItem), 1); + + std::cout << "Leveled up!" << std::endl; + } else if (level == 3) { + + } } int LevelSystem::getCurrentXp() const { diff --git a/src/Rpg/mainCharacter/MainCharacter.cpp b/src/Rpg/mainCharacter/MainCharacter.cpp index eee1901..fa09010 100644 --- a/src/Rpg/mainCharacter/MainCharacter.cpp +++ b/src/Rpg/mainCharacter/MainCharacter.cpp @@ -1,9 +1,10 @@ #include "MainCharacter.h" +#include "LevelSystem.h" #include #include -MainCharacter::MainCharacter(const sf::Vector2f& position) - : mPosition(position), mSpeed(142.0f), mPriority(0) { +MainCharacter::MainCharacter(const sf::Vector2f& position, Inventory* inventory) + : mPosition(position), mSpeed(142.0f), mPriority(0), mLevelSystem(inventory) { mCollisionZone.setSize(sf::Vector2f(24.f, 16.f)); mCollisionZone.setPosition(sf::Vector2f(mPosition.x + 21.f, mPosition.y + 47.f)); mCollisionZone.setFillColor(sf::Color::Red); @@ -164,3 +165,6 @@ int MainCharacter::getAnimation() { return 0; } +LevelSystem& MainCharacter::getLevelSystem() { + return mLevelSystem; +} diff --git a/src/Rpg/mainCharacter/MainCharacter.h b/src/Rpg/mainCharacter/MainCharacter.h index f2ad8fc..1427f77 100644 --- a/src/Rpg/mainCharacter/MainCharacter.h +++ b/src/Rpg/mainCharacter/MainCharacter.h @@ -2,10 +2,12 @@ #include #include "../../Animation.h" #include "../map/entities/DrawableEntity.h" +#include "../inventory/Inventory.h" +#include "LevelSystem.h" class MainCharacter : public DrawableEntity { public: - MainCharacter(const sf::Vector2f& position); + MainCharacter(const sf::Vector2f& position, Inventory* inventory); void update(float dt, bool inDialogue); void render(sf::RenderWindow& window) override; @@ -23,6 +25,8 @@ class MainCharacter : public DrawableEntity { void setAnimation(int animation); int getAnimation(); + LevelSystem& getLevelSystem(); + private: enum class AnimationIndex { IdleUp, @@ -39,6 +43,8 @@ class MainCharacter : public DrawableEntity { float mSpeed; int mPriority; + LevelSystem mLevelSystem; + sf::Keyboard::Key mLastDirection = sf::Keyboard::A; sf::Sprite mSprite; Animation mAnimations[int(AnimationIndex::Count)]; From bf4e985a6149a9ec9a3486bbd066baf4fcc8cfa0 Mon Sep 17 00:00:00 2001 From: Mihai Dumitrescu Date: Sun, 15 Mar 2026 13:35:26 +0200 Subject: [PATCH 3/6] Refactored LevelCompleteMenu to work for level up Signed-off-by: Mihai Dumitrescu --- .../dialogueSystem/DialogueActionExecutor.cpp | 2 +- src/Rpg/gamengine/RPGEngine.cpp | 176 +++++++++--------- src/Rpg/gamengine/RPGEngine.h | 4 +- src/Rpg/mainCharacter/LevelSystem.cpp | 16 +- src/Rpg/mainCharacter/LevelSystem.h | 4 +- src/Rpg/mainCharacter/MainCharacter.cpp | 4 +- src/Rpg/mainCharacter/MainCharacter.h | 3 +- src/Rpg/menues/ShopMenu.cpp | 6 +- src/TowerDefense/gamengine/GameEngine.cpp | 2 +- src/TowerDefense/menues/LevelCompleteMenu.cpp | 98 +++++++--- src/TowerDefense/menues/LevelCompleteMenu.h | 23 ++- src/TowerDefense/menues/RewardSystem.cpp | 22 ++- src/TowerDefense/menues/RewardSystem.h | 1 + 13 files changed, 221 insertions(+), 140 deletions(-) diff --git a/src/Rpg/dialogueSystem/DialogueActionExecutor.cpp b/src/Rpg/dialogueSystem/DialogueActionExecutor.cpp index aae8a1d..b6f8809 100644 --- a/src/Rpg/dialogueSystem/DialogueActionExecutor.cpp +++ b/src/Rpg/dialogueSystem/DialogueActionExecutor.cpp @@ -54,7 +54,7 @@ void DialogueActionExecutor::executeAction(const DialogueAction& action) { if (itemId != -1) mInventory.removeItemById(itemId, action.value); } else if (action.type == "change_crystals") { - mRpgEngine.changeCrystals(action.value); + mRpgEngine.addCrystals(action.value); } else if (action.type == "set_chapter") { mStoryManager.setChapter(action.value); } else { diff --git a/src/Rpg/gamengine/RPGEngine.cpp b/src/Rpg/gamengine/RPGEngine.cpp index a1eaf25..8a3984e 100755 --- a/src/Rpg/gamengine/RPGEngine.cpp +++ b/src/Rpg/gamengine/RPGEngine.cpp @@ -47,7 +47,8 @@ static bool intersects(const sf::FloatRect& rect1, const sf::FloatRect& rect2) { RPGEngine::RPGEngine(sf::RenderWindow& window, GameManager* gameManager) : mWindow(window), mTimeSystem(0.36f), - mCharacter(sf::Vector2f(295.f, 290.f), &mInventory), + mLevelCompleteMenu(window, nullptr, this, gameManager, 2, false), + mCharacter(sf::Vector2f(295.f, 290.f), &mInventory, &mLevelCompleteMenu), mView(sf::Vector2f(400.f, 300.f), sf::Vector2f(740.f, 420.f)), mFixedCamera(sf::Vector2f(0.f, 0.f), sf::Vector2f(740.f, 420.f)), mCameraFixedPosition(sf::Vector2f(0.f, 0.f)), @@ -57,7 +58,7 @@ RPGEngine::RPGEngine(sf::RenderWindow& window, GameManager* gameManager) mSaveNumber(0), mMiraStanton(sf::Vector2f(1000.0f, 900.0f), "mira_stanton"), mElliotMarlowe(sf::Vector2f(100.0f, 0.0f), "elliot_marlowe"), - mGarrickStone(sf::Vector2f(-100.0f, 0.0f), "garrick_stone",gameManager), + mGarrickStone(sf::Vector2f(-100.0f, 0.0f), "garrick_stone", gameManager), mVincentHale(sf::Vector2f(600.0f, 400.0f), "vincent_hale"), mSeraphinaLumeris(sf::Vector2f(-20.0f, 980.0f), "seraphina_lumeris"), mNPCManager(mStoryManager, mDialogueDatabase, *this, mInventory), @@ -363,6 +364,8 @@ void RPGEngine::processEvents() { if (mShowChestMenu) mChestMenu.handleMouseClick(mousePos); + mLevelCompleteMenu.handleMouseClick(mousePos); + if(!mShowMenu && !mShowStartMenu && !mShowBankMenu && !mShowShopMenu && !mShowAnalyzeMenu && !mShowChestMenu && !mShowDialogue) { int slot = mHotbar.contains(mousePos); mHotbar.setHoveredSlot(slot); @@ -384,115 +387,120 @@ void RPGEngine::update() { if (!mShowShopMenu) { if (!mShowAnalyzeMenu) { if (!mShowChestMenu) { - sf::Vector2f previousPosition = mCharacter.getPosition(); + if (!mLevelCompleteMenu.isActive()) { + sf::Vector2f previousPosition = mCharacter.getPosition(); - if (!mShowDialogue) { - mHotbar.update(); - } + if (!mShowDialogue) { + mHotbar.update(); + } - mTransitionSystem.update(dt); + mTransitionSystem.update(dt); - mTimeSystem.update(dt); + mTimeSystem.update(dt); - if (mTimeSystem.getHour() == 0 && mTimeSystem.getMinute() == 0) - mShopMenu.regenerateIds(); + if (mTimeSystem.getHour() == 0 && mTimeSystem.getMinute() == 0) + mShopMenu.regenerateIds(); - if (mTransitionSystem.isTransitioning()) - return; + if (mTransitionSystem.isTransitioning()) + return; - mCharacter.update(dt, mShowDialogue); - mZoneManager.update(mCharacter.getPosition()); + mCharacter.update(dt, mShowDialogue); + mZoneManager.update(mCharacter.getPosition()); - if (mZoneManager.checkCollision(mCharacter.getBounds())) - mCharacter.setPosition(previousPosition); + if (mZoneManager.checkCollision(mCharacter.getBounds())) + mCharacter.setPosition(previousPosition); - for (auto& npc : mNPCManager.getNPCs()) { - if (npc->getBounds().intersects(mCharacter.getBounds())) { - sf::Vector2f npcPos = npc->getPosition(); - sf::Vector2f direction = previousPosition - npcPos; - float distance = std::sqrt(direction.x * direction.x + direction.y * direction.y); + for (auto& npc : mNPCManager.getNPCs()) { + if (npc->getBounds().intersects(mCharacter.getBounds())) { + sf::Vector2f npcPos = npc->getPosition(); + sf::Vector2f direction = previousPosition - npcPos; + float distance = std::sqrt(direction.x * direction.x + direction.y * direction.y); - if (distance < 10.0f) { // Push the player away from the npc with a threshold - direction /= distance; - previousPosition += direction * 5.0f * dt; - mCharacter.setPosition(previousPosition); + if (distance < 10.0f) { // Push the player away from the npc with a threshold + direction /= distance; + previousPosition += direction * 5.0f * dt; + mCharacter.setPosition(previousPosition); + } } - } - if (npc->isPlayerClose(mCharacter.getPosition())) { - if (mShowDialogue) - npc->setInteract(false); + if (npc->isPlayerClose(mCharacter.getPosition())) { + if (mShowDialogue) + npc->setInteract(false); + else + npc->setInteract(true); + } else - npc->setInteract(true); + npc->setInteract(false); } - else - npc->setInteract(false); - } - mNPCManager.update(dt); - mView.setCenter(mCharacter.getCenterPosition()); + mNPCManager.update(dt); + mView.setCenter(mCharacter.getCenterPosition()); - if (mCameraFixedPosition.x != 0.f || mCameraFixedPosition.y != 0.f) - mFixedCamera.setCenter(mCameraFixedPosition); - else - mFixedCamera.setCenter(mCharacter.getCenterPosition()); + if (mCameraFixedPosition.x != 0.f || mCameraFixedPosition.y != 0.f) + mFixedCamera.setCenter(mCameraFixedPosition); + else + mFixedCamera.setCenter(mCharacter.getCenterPosition()); - if (!mNPCManager.playerClose(mCharacter.getPosition())) { - mShowDialogue = false; - } + if (!mNPCManager.playerClose(mCharacter.getPosition())) { + mShowDialogue = false; + } - sf::FloatRect playerBounds = mCharacter.getBounds(); - sf::Vector2f playerCenter = {playerBounds.left + playerBounds.width / 2.f, playerBounds.top + playerBounds.height / 2.f}; - - for (auto it = mDroppedItems.begin(); it != mDroppedItems.end();) { - sf::Vector2f itemCenter = it->getCenterPosition(); - float distance = std::sqrt( - std::pow(playerCenter.x - itemCenter.x, 2.f) + - std::pow(playerCenter.y - itemCenter.y, 2.f) - ); - - if (it->getPickUpCap()) { - if (distance < 28.f) { - auto itemClone = it->getItem()->clone(); - mInventory.addItem(std::move(itemClone), it->getQuantity()); - it = mDroppedItems.erase(it); - continue; + sf::FloatRect playerBounds = mCharacter.getBounds(); + sf::Vector2f playerCenter = {playerBounds.left + playerBounds.width / 2.f, playerBounds.top + playerBounds.height / 2.f}; + + for (auto it = mDroppedItems.begin(); it != mDroppedItems.end();) { + sf::Vector2f itemCenter = it->getCenterPosition(); + float distance = std::sqrt( + std::pow(playerCenter.x - itemCenter.x, 2.f) + + std::pow(playerCenter.y - itemCenter.y, 2.f) + ); + + if (it->getPickUpCap()) { + if (distance < 28.f) { + auto itemClone = it->getItem()->clone(); + mInventory.addItem(std::move(itemClone), it->getQuantity()); + it = mDroppedItems.erase(it); + continue; + } + } else { + if (distance > 28.f) + it->setPickUpCap(true); } - } else { - if (distance > 28.f) - it->setPickUpCap(true); + ++it; } - ++it; - } - mShowInteract = false; + mShowInteract = false; + + for (auto& entity : mZoneManager.getEntities()) { + if (!entity->isInteractable()) + continue; - for (auto& entity : mZoneManager.getEntities()) { - if (!entity->isInteractable()) - continue; + if (entity->getInteractBounds().intersects(mCharacter.getInteractBounds())) { + mShowInteract = true; - if (entity->getInteractBounds().intersects(mCharacter.getInteractBounds())) { - mShowInteract = true; + mInteractPos = entity->getInteractPosition(); - mInteractPos = entity->getInteractPosition(); + mInteractCircle.setPosition({mInteractPos.x + + entity->getInteractBounds().width + 1.5f, mInteractPos.y - 12.f}); - mInteractCircle.setPosition({mInteractPos.x + - entity->getInteractBounds().width + 1.5f, mInteractPos.y - 12.f}); + mInteractText.setPosition({ mInteractCircle.getPosition().x + 5.9f, + mInteractCircle.getPosition().y + 2.8f}); - mInteractText.setPosition({ mInteractCircle.getPosition().x + 5.9f, - mInteractCircle.getPosition().y + 2.8f}); + break; + } + } - break; + if (!mShowInteract) { + mInteractPos = { 0.f, 0.f }; + mInteractCircle.setPosition(mInteractPos); + mInteractText.setPosition(mInteractPos); } - } - if (!mShowInteract) { - mInteractPos = { 0.f, 0.f }; - mInteractCircle.setPosition(mInteractPos); - mInteractText.setPosition(mInteractPos); + mAnalyzeMenu.update(); + } else { + sf::Vector2f mousePos = mWindow.mapPixelToCoords(sf::Mouse::getPosition(mWindow)); + mLevelCompleteMenu.updateHover(mousePos); } - - mAnalyzeMenu.update(); } else { sf::Vector2f mousePos = mWindow.mapPixelToCoords(sf::Mouse::getPosition(mWindow)); mChestMenu.updateHover(mousePos); @@ -644,6 +652,8 @@ void RPGEngine::render() { if(!mShowDialogue) mHotbar.render(mWindow); + mLevelCompleteMenu.render(mWindow); + mTransitionSystem.render(mWindow); renderDateTime(mWindow, mFont, currentDate, currentTime); @@ -1105,7 +1115,7 @@ void RPGEngine::setFlag(std::string name, bool value) { mShowChestMenu = value; } -void RPGEngine::changeCrystals(int value) { +void RPGEngine::addCrystals(int value) { mCrystals += value; } diff --git a/src/Rpg/gamengine/RPGEngine.h b/src/Rpg/gamengine/RPGEngine.h index 32e439b..f18bf5a 100644 --- a/src/Rpg/gamengine/RPGEngine.h +++ b/src/Rpg/gamengine/RPGEngine.h @@ -26,6 +26,7 @@ #include "../menues/ShopMenu.h" #include "../menues/AnalyzeMenu.h" #include "../menues/ChestMenu.h" +#include "../../TowerDefense/menues/LevelCompleteMenu.h" #include "../map/entities/DrawableEntity.h" #include "../map/buildings/MCHouse.h" #include "../map/buildings/MCHouseInt.h" @@ -59,7 +60,7 @@ class RPGEngine { void newGame(); void setSaveNumber(int saveNumber); void setFlag(std::string name, bool value); - void changeCrystals(int value); + void addCrystals(int value); void setCrystals(int crystals); void initialize(); @@ -118,6 +119,7 @@ class RPGEngine { BankMenu mBankMenu; AnalyzeMenu mAnalyzeMenu; ChestMenu mChestMenu; + LevelCompleteMenu mLevelCompleteMenu; NPC* mCurrentInteractingNPC; TimeSystem mTimeSystem; diff --git a/src/Rpg/mainCharacter/LevelSystem.cpp b/src/Rpg/mainCharacter/LevelSystem.cpp index 671d6ca..3d12724 100644 --- a/src/Rpg/mainCharacter/LevelSystem.cpp +++ b/src/Rpg/mainCharacter/LevelSystem.cpp @@ -3,8 +3,9 @@ #include "../inventory/items/TowerBlueprintEpic.h" -LevelSystem::LevelSystem(Inventory* inventory, int maxLevel) - : mInventory(inventory), mCurrentXp(0), mCurrentLevel(0), mMaxLevel(maxLevel) { +LevelSystem::LevelSystem(Inventory* inventory, LevelCompleteMenu* levelCompleteMenu, int maxLevel) + : mInventory(inventory), mLevelCompleteMenu(levelCompleteMenu), mCurrentXp(0), + mCurrentLevel(0), mMaxLevel(maxLevel) { } @@ -25,15 +26,8 @@ void LevelSystem::checkLevelUp() { } void LevelSystem::grantRewards(int level) { - std::cout << "Leveled up!" << std::endl; - if (level == 2) { - std::unique_ptr towerBlueprintItem = std::make_unique(); - mInventory->addItem(std::move(towerBlueprintItem), 1); - - std::cout << "Leveled up!" << std::endl; - } else if (level == 3) { - - } + mLevelCompleteMenu->setLevel(level); + mLevelCompleteMenu->setActive(true); } int LevelSystem::getCurrentXp() const { diff --git a/src/Rpg/mainCharacter/LevelSystem.h b/src/Rpg/mainCharacter/LevelSystem.h index 77efa2c..3c3d25a 100644 --- a/src/Rpg/mainCharacter/LevelSystem.h +++ b/src/Rpg/mainCharacter/LevelSystem.h @@ -2,10 +2,11 @@ #include #include #include "../inventory/Inventory.h" +#include "../../TowerDefense/menues/LevelCompleteMenu.h" class LevelSystem { public: - LevelSystem(Inventory* inventory, int maxLevel = 50); + LevelSystem(Inventory* inventory, LevelCompleteMenu* levelCompleteMenu, int maxLevel = 50); void addXp(int xp); @@ -24,4 +25,5 @@ class LevelSystem { int mMaxLevel; Inventory* mInventory; + LevelCompleteMenu* mLevelCompleteMenu; }; diff --git a/src/Rpg/mainCharacter/MainCharacter.cpp b/src/Rpg/mainCharacter/MainCharacter.cpp index fa09010..ccee590 100644 --- a/src/Rpg/mainCharacter/MainCharacter.cpp +++ b/src/Rpg/mainCharacter/MainCharacter.cpp @@ -3,8 +3,8 @@ #include #include -MainCharacter::MainCharacter(const sf::Vector2f& position, Inventory* inventory) - : mPosition(position), mSpeed(142.0f), mPriority(0), mLevelSystem(inventory) { +MainCharacter::MainCharacter(const sf::Vector2f& position, Inventory* inventory, LevelCompleteMenu* levelCompleteMenu) + : mPosition(position), mSpeed(142.0f), mPriority(0), mLevelSystem(inventory, levelCompleteMenu) { mCollisionZone.setSize(sf::Vector2f(24.f, 16.f)); mCollisionZone.setPosition(sf::Vector2f(mPosition.x + 21.f, mPosition.y + 47.f)); mCollisionZone.setFillColor(sf::Color::Red); diff --git a/src/Rpg/mainCharacter/MainCharacter.h b/src/Rpg/mainCharacter/MainCharacter.h index 1427f77..e390064 100644 --- a/src/Rpg/mainCharacter/MainCharacter.h +++ b/src/Rpg/mainCharacter/MainCharacter.h @@ -4,10 +4,11 @@ #include "../map/entities/DrawableEntity.h" #include "../inventory/Inventory.h" #include "LevelSystem.h" +#include "../../TowerDefense/menues/LevelCompleteMenu.h" class MainCharacter : public DrawableEntity { public: - MainCharacter(const sf::Vector2f& position, Inventory* inventory); + MainCharacter(const sf::Vector2f& position, Inventory* inventory, LevelCompleteMenu* levelCompleteMenu); void update(float dt, bool inDialogue); void render(sf::RenderWindow& window) override; diff --git a/src/Rpg/menues/ShopMenu.cpp b/src/Rpg/menues/ShopMenu.cpp index 8d4db9a..7fc4ba9 100755 --- a/src/Rpg/menues/ShopMenu.cpp +++ b/src/Rpg/menues/ShopMenu.cpp @@ -378,9 +378,9 @@ void ShopMenu::updateTooltip(int slot, int id) { std::string tooltipText; if (id == 1) tooltipText = "Cost: 5\nWood\nA piece of wood, useful for crafting."; else if (id == 2) tooltipText = "Cost: 50\nTower Blueprint\nCan be used to unlock towers!"; - else if (id == 3) tooltipText = "Cost: 100\nTower Blueprint Rare\nCan be used to unlock rare towers!"; - else if (id == 4) tooltipText = "Cost: 150\nTower Blueprint Epic\nCan be used to unlock epic towers!"; - else if (id == 5) tooltipText = "Cost: 250\nTower Blueprint Mythic\nCan be used to unlock mythic towers!"; + else if (id == 3) tooltipText = "Cost: 100\nRare Tower Blueprint\nCan be used to unlock rare towers!"; + else if (id == 4) tooltipText = "Cost: 150\nEpic Tower Blueprint\nCan be used to unlock epic towers!"; + else if (id == 5) tooltipText = "Cost: 250\nMythic Tower Blueprint\nCan be used to unlock mythic towers!"; else tooltipText = "Nothing here!"; mTooltipText.setString(tooltipText); diff --git a/src/TowerDefense/gamengine/GameEngine.cpp b/src/TowerDefense/gamengine/GameEngine.cpp index a9926dd..794b849 100644 --- a/src/TowerDefense/gamengine/GameEngine.cpp +++ b/src/TowerDefense/gamengine/GameEngine.cpp @@ -34,7 +34,7 @@ GameEngine::GameEngine(sf::RenderWindow& window, GameManager* gameManager) mShowText2(false), mGameManager(gameManager), mSmallMenu(mWindow, this, gameManager, mCurrentLevel, mAvailableTowers), - mLevelCompleteMenu(mWindow, this, gameManager, mCurrentLevel), + mLevelCompleteMenu(mWindow, this, nullptr, gameManager, mCurrentLevel, true), mGameOverMenu(mWindow, this, gameManager, mCurrentLevel, mCrystals, mAvailableTowers) { if (!mFont.loadFromFile("assets/fonts/gameFont.ttf")) diff --git a/src/TowerDefense/menues/LevelCompleteMenu.cpp b/src/TowerDefense/menues/LevelCompleteMenu.cpp index 94fe925..8d29f8a 100644 --- a/src/TowerDefense/menues/LevelCompleteMenu.cpp +++ b/src/TowerDefense/menues/LevelCompleteMenu.cpp @@ -1,22 +1,24 @@ #include "LevelCompleteMenu.h" #include "../gamengine/GameEngine.h" +#include "../../Rpg/gamengine/RPGEngine.h" #include "../../GameManager.h" #include "../../Rpg/inventory/items/Wood.h" #include "../../Rpg/inventory/items/TowerBlueprint.h" #include "../../Rpg/inventory/items/TowerBlueprintRare.h" #include "../../Rpg/inventory/items/TowerBlueprintEpic.h" #include "../../Rpg/inventory/items/TowerBlueprintMythic.h" +#include "RewardSystem.h" #include -LevelCompleteMenu::LevelCompleteMenu(sf::RenderWindow& window, GameEngine* game, - GameManager* gameManager, int level) - : mGame(game), mGameManager(gameManager), mLevel(level), - continueButton(sf::Vector2f(0, 0), sf::Vector2f(165, 40), "Continue") { +LevelCompleteMenu::LevelCompleteMenu(sf::RenderWindow& window, GameEngine* towerGame, + RPGEngine* rpgGame, GameManager* gameManager, int level, bool isTowerLevel) + : mTowerGame(towerGame), mRpgGame(rpgGame), mGameManager(gameManager), mLevel(level), mActive(false), + mIsTowerLevel(isTowerLevel), mContinueButton(sf::Vector2f(0, 0), sf::Vector2f(165, 40), "Continue") { if (!mFont.loadFromFile("assets/fonts/gameFont.ttf")) std::cerr << "Failed to load font for AnalyzeMenu!" << std::endl; - mMenuShape.setSize(sf::Vector2f(window.getSize().x / 5.5f, window.getSize().y / 3.f)); + mMenuShape.setSize(sf::Vector2f(window.getSize().x / 5.3f, window.getSize().y / 2.3f)); mMenuShape.setFillColor(sf::Color(50, 50, 50, 255)); mMenuShape.setPosition((window.getSize().x - mMenuShape.getSize().x) / 2, (window.getSize().y - mMenuShape.getSize().y) / 2); @@ -24,28 +26,44 @@ LevelCompleteMenu::LevelCompleteMenu(sf::RenderWindow& window, GameEngine* game, mBackground.setSize(sf::Vector2f(window.getSize().x, window.getSize().y)); mBackground.setFillColor(sf::Color(50, 50, 50, 185)); mBackground.setPosition(sf::Vector2f(0, 0)); - continueButton.setPosition(sf::Vector2f(mMenuShape.getPosition().x + (mMenuShape.getSize().x - continueButton.getSize().x) / 2.f, - mMenuShape.getPosition().y + mMenuShape.getSize().y * 0.1f)); - mReward = RewardSystem::generateReward(level); - continueButton.setCallback([this, game, gameManager]() { - if (mGameManager) { + if (isTowerLevel) + mLevelCompleteText.setString("Level completed!"); + else + mLevelCompleteText.setString("Level up!"); + mLevelCompleteText.setFont(mFont); + mLevelCompleteText.setCharacterSize(18); + mLevelCompleteText.setFillColor(sf::Color::White); + mLevelCompleteText.setPosition(sf::Vector2f(mMenuShape.getPosition().x + (mMenuShape.getSize().x - mLevelCompleteText.getLocalBounds().width) / 2.f, + mMenuShape.getPosition().y + mMenuShape.getSize().y * 0.05f)); + + if (isTowerLevel) + mReward = RewardSystem::generateTowerLevelReward(level); + else + mReward = RewardSystem::generateReward(level); + + mContinueButton.setCallback([this]() { + if (mIsTowerLevel) { + if (mGameManager) { + if (mReward.itemId == 0) + mGameManager->switchToRPG(mTowerGame->getCrystals() + mReward.quantity); + else + mGameManager->switchToRPG(mTowerGame->getCrystals()); + } else + std::cerr << "Error: GameManager is nullptr in continueButton callback." << std::endl; + } else { if (mReward.itemId == 0) - mGameManager->switchToRPG(game->getCrystals() + mReward.quantity); - else - mGameManager->switchToRPG(game->getCrystals()); - } else - std::cerr << "Error: GameManager is nullptr in continueButton callback." << std::endl; + mRpgGame->addCrystals(mReward.quantity); + mActive = false; + } }); - mButtons.push_back(continueButton); - - mRewardShape.setSize(sf::Vector2f(mMenuShape.getSize().x * 0.6f, mMenuShape.getSize().y * 0.55f)); + mRewardShape.setSize(sf::Vector2f(mMenuShape.getSize().x * 0.63f, mMenuShape.getSize().y * 0.56f)); mRewardShape.setFillColor(sf::Color::Transparent); mRewardShape.setOutlineColor(sf::Color::White); mRewardShape.setOutlineThickness(1.5f); mRewardShape.setPosition(sf::Vector2f(mMenuShape.getPosition().x + (mMenuShape.getSize().x - mRewardShape.getSize().x) / 2.f, - mMenuShape.getPosition().y + mMenuShape.getSize().y * 0.9f - mRewardShape.getSize().y)); + mMenuShape.getPosition().y + mMenuShape.getSize().y * 0.18f)); mRewardText.setFont(mFont); mRewardText.setString(mReward.name); @@ -84,29 +102,55 @@ LevelCompleteMenu::LevelCompleteMenu(sf::RenderWindow& window, GameEngine* game, } mItemIcon.setPosition(sf::Vector2f(mRewardShape.getPosition().x + (mRewardShape.getSize().x - mItemIcon.getSize().x) / 2.f, mRewardShape.getPosition().y + mRewardShape.getSize().y * 0.1f)); + + mContinueButton.setPosition(sf::Vector2f(mMenuShape.getPosition().x + (mMenuShape.getSize().x - mContinueButton.getSize().x) / 2.f, + mRewardShape.getPosition().y + mRewardShape.getSize().y * 1.15f)); } void LevelCompleteMenu::render(sf::RenderWindow& window) { + if (!mIsTowerLevel && !mActive) + return; + window.draw(mBackground); window.draw(mMenuShape); + + window.draw(mLevelCompleteText); window.draw(mRewardShape); window.draw(mRewardText); window.draw(mQuantityText); window.draw(mItemIcon); - for (auto& button : mButtons) - button.render(window); + mContinueButton.render(window); } void LevelCompleteMenu::handleMouseClick(const sf::Vector2f& mousePos) { - for (auto& button : mButtons) { - if (button.isMouseOver(mousePos)) - button.onClick(); - } + if (!mIsTowerLevel && !mActive) + return; + + if (mContinueButton.isMouseOver(mousePos)) + mContinueButton.onClick(); } void LevelCompleteMenu::updateHover(const sf::Vector2f& mousePos) { - for (auto& button : mButtons) - button.updateHover(mousePos); + if (!mIsTowerLevel && !mActive) + return; + + mContinueButton.updateHover(mousePos); +} + +bool LevelCompleteMenu::isActive() const { + return mActive; +} + +void LevelCompleteMenu::setActive(bool state) { + mActive = state; +} + +int LevelCompleteMenu::getLevel() const { + return mLevel; +} + +void LevelCompleteMenu::setLevel(int level) { + mLevel = level; } diff --git a/src/TowerDefense/menues/LevelCompleteMenu.h b/src/TowerDefense/menues/LevelCompleteMenu.h index 4451270..4b8261e 100644 --- a/src/TowerDefense/menues/LevelCompleteMenu.h +++ b/src/TowerDefense/menues/LevelCompleteMenu.h @@ -5,32 +5,43 @@ #include class GameEngine; +class RPGEngine; class GameManager; +// Used for both tower defense level completion and main character level progression class LevelCompleteMenu { public: - LevelCompleteMenu(sf::RenderWindow& window, GameEngine* game, - GameManager* gameManager, int level); + LevelCompleteMenu(sf::RenderWindow& window, GameEngine* towerGame, RPGEngine* rpgGame, + GameManager* gameManager, int level, bool isTowerLevel); void render(sf::RenderWindow& window); void handleMouseClick(const sf::Vector2f& mousePos); void updateHover(const sf::Vector2f& mousePos); + bool isActive() const; + void setActive(bool state); + + int getLevel() const; + void setLevel(int level); + private: sf::RectangleShape mMenuShape; sf::RectangleShape mBackground; - - std::vector