From 1024fe8305e5b0a7bb1f660a1cee077172d84534 Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Wed, 30 Nov 2016 17:54:13 -0500 Subject: quest system --- include/quest.hpp | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.cpp | 5 ++-- src/components.cpp | 36 ++++++++++++++++++++++++++- src/engine.cpp | 7 ++++-- src/quest.cpp | 46 ++++++++++++++++++++++++++++++++++ src/ui.cpp | 17 +++++++++---- src/ui_menu.cpp | 10 ++++---- 7 files changed, 178 insertions(+), 15 deletions(-) create mode 100644 include/quest.hpp create mode 100644 src/quest.cpp diff --git a/include/quest.hpp b/include/quest.hpp new file mode 100644 index 0000000..cb43eca --- /dev/null +++ b/include/quest.hpp @@ -0,0 +1,72 @@ +/** + * @file quest.hpp + * Quest handling. + */ + +#ifndef QUEST_HPP_ +#define QUEST_HPP_ + +#include + +#include +#include + +/** + * The Quest structure. + * Contains information necessary for a quest. + */ +struct Quest +{ + Quest(std::string n = "", std::string d = "") + : name(n), desc(d) {} + + std::string name; /**< the quest's title */ + std::string desc; /**< the quest's description */ +}; + +/** + * @class QuestSystem + * The quest system, handles active quests. + */ +class QuestSystem : public entityx::System { +private: + /** + * A list of all quests that are currently active. + */ + std::vector current; + +public: + void update(entityx::EntityManager &en, entityx::EventManager &ev, entityx::TimeDelta dt) override; + + /** + * Adds a quest to the current quest vector by its title. + * @param title the quest's title + * @param desc the quest's description + * @param req retrieved from XML, list of what the quest wants + * @return a possible error code + */ + int assign(std::string title, std::string desc, std::string req); + + /** + * Drops a quest through its title. + * @param title the quest's title + * @return a possible error code + */ + int drop(std::string title); + + /** + * Finishes a quest through it's title. + * @param title the quest's title + * @return a possible error code + */ + int finish(std::string title); + + /** + * Returns true if the system is currently taking the quest. + * @param title the quest's title + * @return if the quest is active. + */ + bool hasQuest(std::string title); +}; + +#endif // QUEST_HPP_ diff --git a/main.cpp b/main.cpp index c3a0a6b..a3901a3 100644 --- a/main.cpp +++ b/main.cpp @@ -259,7 +259,8 @@ void render() { const auto SCREEN_HEIGHT = game::SCREEN_HEIGHT; auto ps = game::engine.getSystem(); - offset.x = ps->getPosition().x + ps->getWidth() / 2; + auto ploc = ps->getPosition(); + offset.x = ploc.x + ps->getWidth() / 2; const auto& worldWidth = game::engine.getSystem()->getWidth(); if (worldWidth < (int)SCREEN_WIDTH) @@ -270,7 +271,7 @@ void render() { offset.x = ((worldWidth * 0.5f) - SCREEN_WIDTH / 2); // ortho y snapping - offset.y = /*std::max(player->loc.y + player->height / 2,*/ SCREEN_HEIGHT / 2.0f; /*);*/ + offset.y = std::max(ploc.y /*+ player->height / 2*/, SCREEN_HEIGHT / 2.0f); // "setup" glm::mat4 projection = glm::ortho(floor(offset.x - SCREEN_WIDTH / 2), // left diff --git a/src/components.cpp b/src/components.cpp index 38fd7a6..eb9fb0e 100644 --- a/src/components.cpp +++ b/src/components.cpp @@ -8,6 +8,7 @@ #include #include #include +#include static std::vector randomDialog (readFileA("assets/dialog_en-us")); @@ -158,9 +159,11 @@ void DialogSystem::receive(const MouseClickEvent &mce) ((mce.position.y > pos.y) & (mce.position.y < pos.y + dim.height))) { std::thread([&] { - auto exml = game::engine.getSystem()->getXML()->FirstChildElement("Dialog"); + std::string questAssignedText; int newIndex; + auto exml = game::engine.getSystem()->getXML()->FirstChildElement("Dialog"); + if (e.has_component()) d.talking = true; @@ -182,6 +185,34 @@ void DialogSystem::receive(const MouseClickEvent &mce) game::briceUpdate(); } + auto qxml = exml->FirstChildElement("quest"); + if (qxml != nullptr) { + std::string qname; + auto qsys = game::engine.getSystem(); + + do { + // assign quest + qname = qxml->StrAttribute("assign"); + if (!qname.empty()) { + questAssignedText = qname; + qsys->assign(qname, qxml->StrAttribute("desc"), "req"); // gettext() for req + } + + // check / finish quest + else { + qname = qxml->StrAttribute("check"); + if (!(qname.empty() && qsys->hasQuest(qname) && qsys->finish(qname))) { + ui::dialogBox(name.name, "", false, "Finish my quest u nug"); + ui::waitForDialog(); + return; + // oldidx = d.index; + // d.index = qxml->UnsignedAttribute("fail"); + // goto COMMONAIFUNC; + } + } + } while((qxml = qxml->NextSiblingElement())); + } + auto cxml = exml->FirstChildElement("content"); const char *content; if (cxml == nullptr) { @@ -194,6 +225,9 @@ void DialogSystem::receive(const MouseClickEvent &mce) ui::dialogBox(name.name, "", false, content); ui::waitForDialog(); + if (!questAssignedText.empty()) + ui::passiveImportantText(4000, ("Quest assigned:\n\"" + questAssignedText + "\"").c_str()); + if (exml->QueryIntAttribute("nextid", &newIndex) == XML_NO_ERROR) d.index = newIndex; } diff --git a/src/engine.cpp b/src/engine.cpp index 7c9a404..e5b2b36 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -7,6 +7,7 @@ #include #include #include +#include Engine::Engine(void) : shouldRun(true), systems(game::entities, game::events) @@ -23,6 +24,7 @@ void Engine::init(void) { //systems.add(); systems.add(); systems.add(); + systems.add(); systems.add(); systems.add(); @@ -39,7 +41,7 @@ void Engine::render(entityx::TimeDelta dt) { systems.update(dt); systems.update(dt); - //systems.update(dt); + //systems.update(dt); // doesn't do anything... ui::fadeUpdate(); } @@ -48,9 +50,10 @@ void Engine::update(entityx::TimeDelta dt) { systems.update(dt); systems.update(dt); - systems.update(dt); + //systems.update(dt); // doesn't do anything systems.update(dt); systems.update(dt); + //systems.update(dt); // doesn't do anything } diff --git a/src/quest.cpp b/src/quest.cpp new file mode 100644 index 0000000..f7548d2 --- /dev/null +++ b/src/quest.cpp @@ -0,0 +1,46 @@ +#include + +#include + +void QuestSystem::update(entityx::EntityManager &en, entityx::EventManager &ev, entityx::TimeDelta dt) +{ + (void)en; + (void)ev; + (void)dt; +} + +int QuestSystem::assign(std::string title, std::string desc, std::string req) +{ + (void)req; + current.emplace_back(title, desc); + return 0; +} + +int QuestSystem::drop(std::string title) +{ + current.erase(std::remove_if(std::begin(current), std::end(current), + [&title](const Quest& q) { return (q.name == title); })); + return 0; +} + +int QuestSystem::finish(std::string title) +{ + auto quest = std::find_if(std::begin(current), std::end(current), + [&title](const Quest& q) { return (q.name == title); }); + + if (quest == std::end(current)) + return -1; + + // TODO requirements + + drop(title); + + return 0; +} + +bool QuestSystem::hasQuest(std::string title) +{ + return (std::find_if(std::begin(current), std::end(current), + [&title](const Quest& q) { return (q.name == title); }) != std::end(current)); +} + diff --git a/src/ui.cpp b/src/ui.cpp index bc1f28c..1652f10 100644 --- a/src/ui.cpp +++ b/src/ui.cpp @@ -411,13 +411,16 @@ namespace ui { } float putStringCentered(const float x, const float y, std::string s) { - unsigned int i = 0; - float width = 0; + unsigned int i = 0, lastnl = 0; + float width = 0, yy = y; do { switch (s[i]) { case '\n': - // TODO + putString(floor(x - width / 2), yy, s.substr(0, i)); + lastnl = 1 + i; + width = 0; + yy -= fontSize * 1.15f; break; case '\b': break; @@ -429,7 +432,8 @@ namespace ui { break; } } while(s[++i]); - putString(floor(x-width/2),y,s); + + putString(floor(x - width / 2), yy, s.substr(lastnl)); return width; } @@ -478,17 +482,20 @@ namespace ui { case '!': case '?': case '.': + case ':': tadv = 10; break; case ',': + case ';': tadv = 5; break; default: tadv = 1; break; } - } else + } else { typeOutDone = true; + } } return ret; // The buffered string. diff --git a/src/ui_menu.cpp b/src/ui_menu.cpp index f6f962d..59b44e6 100644 --- a/src/ui_menu.cpp +++ b/src/ui_menu.cpp @@ -159,11 +159,11 @@ namespace ui { void init(void) { // Create the main pause menu - pauseMenu.items.push_back(ui::menu::createParentButton({-128,0},{256,75},{0.0f,0.0f,0.0f}, "Resume")); - pauseMenu.items.push_back(ui::menu::createChildButton({-128,-100},{256,75},{0.0f,0.0f,0.0f}, "Options", &optionsMenu)); - pauseMenu.items.push_back(ui::menu::createChildButton({-128,-200},{256,75},{0.0f,0.0f,0.0f}, "Controls", &controlsMenu)); - pauseMenu.items.push_back(ui::menu::createButton({-128,-300},{256,75},{0.0f,0.0f,0.0f}, "Save and Quit", ui::quitGame)); - pauseMenu.items.push_back(ui::menu::createButton({-128,-400},{256,75},{0.0f,0.0f,0.0f}, "Segfault", segFault)); + pauseMenu.items.push_back(ui::menu::createParentButton({-128,100},{256,75},{0.0f,0.0f,0.0f}, "Resume")); + pauseMenu.items.push_back(ui::menu::createChildButton({-128, 0},{256,75},{0.0f,0.0f,0.0f}, "Options", &optionsMenu)); + pauseMenu.items.push_back(ui::menu::createChildButton({-128,-100},{256,75},{0.0f,0.0f,0.0f}, "Controls", &controlsMenu)); + pauseMenu.items.push_back(ui::menu::createButton({-128,-200},{256,75},{0.0f,0.0f,0.0f}, "Save and Quit", ui::quitGame)); + pauseMenu.items.push_back(ui::menu::createButton({-128,-300},{256,75},{0.0f,0.0f,0.0f}, "Segfault", segFault)); // Create the options (sound) menu optionsMenu.items.push_back(ui::menu::createSlider({0-static_cast(game::SCREEN_WIDTH)/4,0-(512/2)}, {50,512}, {0.0f, 0.0f, 0.0f}, 0, 100, "Master", &game::config::VOLUME_MASTER)); -- cgit v1.2.3