aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authordrumsetmonkey <abelleisle@roadrunner.com>2017-04-27 21:33:13 -0400
committerdrumsetmonkey <abelleisle@roadrunner.com>2017-04-27 21:33:13 -0400
commit2de1af94cfa794ae5dd7913c797d673b58289949 (patch)
tree3acb4e822943efb714ff04d4e88307127e34f52e /src
parent40f2ab396ccca1a12cc74d18c9758da5bc2f1afc (diff)
parent00de7a4b0aa48c3cb42c45e0f203902ca034b94c (diff)
Updated sprites
Diffstat (limited to 'src')
-rw-r--r--src/attack.cpp51
-rw-r--r--src/components.cpp85
-rw-r--r--src/config.cpp5
-rw-r--r--src/engine.cpp11
-rw-r--r--src/font.cpp131
-rw-r--r--src/inventory.cpp9
-rw-r--r--src/particle.cpp4
-rw-r--r--src/player.cpp35
-rw-r--r--src/render.cpp14
-rw-r--r--src/ui.cpp857
-rw-r--r--src/ui_menu.cpp22
-rw-r--r--src/world.cpp156
12 files changed, 600 insertions, 780 deletions
diff --git a/src/attack.cpp b/src/attack.cpp
index 550b849..e91b4cd 100644
--- a/src/attack.cpp
+++ b/src/attack.cpp
@@ -1,10 +1,13 @@
#include <attack.hpp>
+
#include <components.hpp>
#include <engine.hpp>
#include <particle.hpp>
+#include <player.hpp>
+#include <world.hpp>
-constexpr int shortSlashLength = 100;
-constexpr int longSlashLength = 200;
+constexpr int shortSlashLength = 20;
+constexpr int longSlashLength = 40;
// math helpers because we don't trust stdlib
template<typename T>
@@ -20,6 +23,11 @@ bool inrange(float point, float left, float right, float range)
(point > left && point < right);
}
+bool inrange(float point, float left, float right)
+{
+ return point > left && point < right;
+}
+
void AttackSystem::receive(const AttackEvent& ae)
{
attacks.emplace_front(ae);
@@ -31,17 +39,35 @@ void AttackSystem::update(entityx::EntityManager& en, entityx::EventManager& ev,
(void)ev;
(void)dt;
+ // handle attacking entities
+ en.each<Hit, Position>([&](entityx::Entity p, Hit& hit, Position& ppos) {
+ bool die = false;
+ en.each<Health, Position, Solid>([&](entityx::Entity e, Health& health, Position& pos, Solid& dim) {
+ if (!e.has_component<Player>() && inrange(ppos.x, pos.x, pos.x + dim.width) && inrange(ppos.y, pos.y - 2, pos.y + dim.height)) {
+ health.health -= hit.damage;
+ game::engine.getSystem<ParticleSystem>()->addMultiple(15, ParticleType::SmallBlast,
+ [&](){ return vec2(pos.x + dim.width / 2, pos.y + dim.height / 2); }, 300, 7);
+ die = !hit.pierce;
+ } else if (WorldSystem::isAboveGround(vec2(ppos.x, ppos.y - 5)))
+ die = true;
+ });
+
+ if (die)
+ p.destroy();
+ });
+
+ // handle emitted attacks
for (const auto& a : attacks) {
switch (a.type) {
case AttackType::ShortSlash:
case AttackType::LongSlash:
en.each<Position, Solid, Health>(
[&a](entityx::Entity e, Position& pos, Solid& dim, Health& h) {
- (void)e;
- if (e.has_component<Player>())
+ if (!(e.has_component<Player>() ^ a.fromplayer))
return;
- if (inrange(a.pos.x, pos.x, pos.x + dim.width, shortSlashLength)) {
+ if (inrange(a.pos.x, pos.x, pos.x + dim.width, HLINES(shortSlashLength)) &&
+ inrange(a.pos.y, pos.y, pos.y + dim.height)) {
h.health -= a.power;
game::engine.getSystem<ParticleSystem>()->addMultiple(15, ParticleType::DownSlash,
[&](){ return vec2(pos.x + dim.width / 2, pos.y + dim.height / 2); }, 300, 7);
@@ -49,21 +75,6 @@ void AttackSystem::update(entityx::EntityManager& en, entityx::EventManager& ev,
}
);
break;
- case AttackType::SmallBoom:
- en.each<Position, Solid, Health>(
- [&a](entityx::Entity e, Position& pos, Solid& dim, Health& h) {
- (void)e;
- if (e.has_component<Player>())
- return;
-
- if (inrange(a.pos.x, pos.x, pos.x + dim.width, shortSlashLength)) {
- h.health -= a.power;
- game::engine.getSystem<ParticleSystem>()->addMultiple(15, ParticleType::SmallBlast,
- [&](){ return vec2(pos.x + dim.width / 2, pos.y + dim.height / 2); }, 300, 7);
- }
- }
- );
- break;
default:
break;
}
diff --git a/src/components.cpp b/src/components.cpp
index 732e21f..dcb1551 100644
--- a/src/components.cpp
+++ b/src/components.cpp
@@ -3,10 +3,12 @@
#include <entityx/entityx.h>
#include <events.hpp>
+#include <attack.hpp>
#include <render.hpp>
#include <ui.hpp>
#include <engine.hpp>
#include <error.hpp>
+#include <font.hpp>
#include <world.hpp>
#include <brice.hpp>
#include <quest.hpp>
@@ -22,13 +24,13 @@ static std::vector<std::string> randomDialog (readFileA("assets/dialog_en-us"));
void MovementSystem::update(entityx::EntityManager &en, entityx::EventManager &ev, entityx::TimeDelta dt)
{
- bool fight = false;
+ //bool fight = false;
entityx::Entity toFight;
(void)ev;
en.each<Position, Direction>([&](entityx::Entity entity, Position &position, Direction &direction) {
- position.x += direction.x * dt;
- position.y += direction.y * dt;
+ position.x += HLINES(direction.x) * dt;
+ position.y += HLINES(direction.y) * dt;
if (entity.has_component<Animate>() && entity.has_component<Sprite>()) {
auto animate = entity.component<Animate>();
@@ -38,7 +40,7 @@ void MovementSystem::update(entityx::EntityManager &en, entityx::EventManager &e
animate->updateAnimation(1, sprite->sprite, dt);
else
animate->firstFrame(1, sprite->sprite);
- }
+ }
if (entity.has_component<Dialog>() && entity.component<Dialog>()->talking) {
direction.x = 0;
} else {
@@ -48,38 +50,57 @@ void MovementSystem::update(entityx::EntityManager &en, entityx::EventManager &e
fl = (direction.x < 0);
}
- // make the entity wander
- // TODO initialX and range?
- if (0 && entity.has_component<Aggro>()) {
- auto ppos = game::engine.getSystem<PlayerSystem>()->getPosition();
- if (ppos.x > position.x && ppos.x < position.x + entity.component<Solid>()->width) {
- auto& h = entity.component<Health>()->health;
+ auto ppos = game::engine.getSystem<PlayerSystem>()->getPosition();
+ if (ppos.x > position.x && ppos.x < position.x + entity.component<Solid>()->width) {
+ if (entity.has_component<Aggro>()) {
+ auto dim = entity.component<Solid>();
+ ev.emit<AttackEvent>(vec2(position.x + dim->width, position.y + dim->height),
+ AttackType::ShortSlash, false);
+ /*auto& h = entity.component<Health>()->health;
if (h > 0) {
fight = true;
toFight = entity;
h = 0;
+ }*/
+ } else if (entity.has_component<Trigger>()) {
+ static bool triggering = false;
+ if (!triggering) {
+ triggering = true;
+ std::thread([&](entityx::Entity e) {
+ UISystem::fadeToggle();
+ UISystem::waitForCover();
+ UISystem::dialogImportant(e.component<Trigger>()->text);
+ UISystem::waitForDialog();
+ UISystem::fadeToggle();
+ e.destroy();
+ triggering = false;
+ }, entity).detach();
}
- } else
- direction.x = (ppos.x > position.x) ? .05 : -.05;
- } else if (entity.has_component<Wander>()) {
+ return;
+ }
+ }
+
+ // make the entity wander
+ // TODO initialX and range?
+ if (entity.has_component<Wander>()) {
auto& countdown = entity.component<Wander>()->countdown;
if (countdown > 0) {
countdown--;
} else {
countdown = 5000 + randGet() % 10 * 100;
- direction.x = (randGet() % 3 - 1) * 0.02f;
+ direction.x = (randGet() % 3 - 1) * 0.004f;
}
}
}
});
- if (fight) {
- ui::toggleWhiteFast();
- ui::waitForCover();
- game::engine.getSystem<WorldSystem>()->fight(toFight);
- ui::toggleWhiteFast();
- }
+// if (fight) {
+// UISystem::fadeToggleFast();
+// UISystem::waitForCover();
+ //game::engine.getSystem<WorldSystem>()->fight(toFight);
+// UISystem::fadeToggleFast();
+// }
}
void PhysicsSystem::update(entityx::EntityManager &en, entityx::EventManager &ev, entityx::TimeDelta dt)
@@ -205,8 +226,8 @@ void RenderSystem::render(void)
game::entities.each<Visible, Position, Solid, Name>([](entityx::Entity e, Visible &v, Position &pos, Solid& dim, Name &name) {
(void)e;
(void)v;
- ui::setFontZ(-5.0);
- ui::putStringCentered(pos.x + dim.width / 2, pos.y - ui::fontSize - HLINES(0.5), name.name);
+ FontSystem::setFontZ(-5.0f);
+ UISystem::putStringCentered(vec2(pos.x + dim.width / 2, pos.y - FontSystem::getSize() - HLINES(0.5)), name.name);
});
}
@@ -232,15 +253,15 @@ void DialogSystem::receive(const MouseClickEvent &mce)
std::string questAssignedText;
int newIndex;
- auto exml = game::engine.getSystem<WorldSystem>()->getXML()->FirstChildElement("Dialog");
+ auto exml = WorldSystem::getXML()->FirstChildElement("Dialog");
dialogRun.store(true);
if (e.has_component<Direction>())
d.talking = true;
if (d.index == 9999) {
- ui::dialogBox(name.name, "", false, randomDialog[d.rindex % randomDialog.size()]);
- ui::waitForDialog();
+ UISystem::dialogBox(name.name, /*"", false,*/ randomDialog[d.rindex % randomDialog.size()]);
+ UISystem::waitForDialog();
} else if (exml != nullptr) {
while (exml->StrAttribute("name") != name.name)
exml = exml->NextSiblingElement();
@@ -286,8 +307,8 @@ void DialogSystem::receive(const MouseClickEvent &mce)
if (qname != nullptr && qsys->finish(qname) == 0) {
d.index = 9999;
} else {
- ui::dialogBox(name.name, "", false, "Finish my quest u nug");
- ui::waitForDialog();
+ UISystem::dialogBox(name.name, /*"", false,*/ "Finish my quest u nug");
+ UISystem::waitForDialog();
return;
}
// oldidx = d.index;
@@ -303,6 +324,8 @@ void DialogSystem::receive(const MouseClickEvent &mce)
std::vector<int> optionNexts;
if (xxml != nullptr) {
do {
+ UISystem::dialogAddOption(xxml->StrAttribute("name"));
+
options += '\"' + xxml->StrAttribute("name");
optionNexts.emplace_back(xxml->IntAttribute("value"));
xxml = xxml->NextSiblingElement();
@@ -318,11 +341,13 @@ void DialogSystem::receive(const MouseClickEvent &mce)
while (*++content && isspace(*content));
}
- ui::dialogBox(name.name, options, false, content);
- ui::waitForDialog();
+ UISystem::dialogBox(name.name, /*options, false,*/ content);
+ UISystem::waitForDialog();
+ UISystem::waitForDialog();
if (!questAssignedText.empty())
- ui::passiveImportantText(5000, ("Quest assigned:\n\"" + questAssignedText + "\"").c_str());
+ UISystem::dialogImportant("Quest assigned:\n\"" + questAssignedText + "\"");
+ //passiveImportantText(5000, ("Quest assigned:\n\"" + questAssignedText + "\"").c_str());
if (exml->QueryIntAttribute("nextid", &newIndex) == XML_NO_ERROR)
d.index = newIndex;
diff --git a/src/config.cpp b/src/config.cpp
index 844bf39..7f0af00 100644
--- a/src/config.cpp
+++ b/src/config.cpp
@@ -22,6 +22,7 @@ namespace game {
float VOLUME_SFX;
std::string xmlFolder;
+ std::string fontFamily;
void read(void) {
xml.LoadFile("config/settings.xml");
@@ -49,8 +50,8 @@ namespace game {
if (xmlFolder.empty())
xmlFolder = "xml/";
- ui::initFonts();
- ui::setFontFace(xml.FirstChildElement("font")->Attribute("path"));
+ // FONT SETUP
+ fontFamily = xml.FirstChildElement("font")->Attribute("path");
if (xml.FirstChildElement("debug"))
ui::debug = ui::posFlag = true;
diff --git a/src/engine.cpp b/src/engine.cpp
index 640356e..dc7aa77 100644
--- a/src/engine.cpp
+++ b/src/engine.cpp
@@ -1,6 +1,7 @@
#include <engine.hpp>
#include <config.hpp>
+#include <font.hpp>
#include <world.hpp>
#include <window.hpp>
#include <ui.hpp>
@@ -38,8 +39,17 @@ void Engine::init(void) {
systems.add<WeatherSystem>();
systems.add<AttackSystem>();
+ systems.add<UISystem>();
+
systems.configure();
+ // init ui
+
+ FontSystem::init(game::config::fontFamily);
+ FontSystem::setFontSize(16);
+ FontSystem::setFontColor(1, 1, 1);
+ FontSystem::setFontZ(-6.0f);
+
ui::initSounds();
ui::menu::init();
game::config::update();
@@ -57,6 +67,7 @@ void Engine::update(entityx::TimeDelta dt)
systems.update<WeatherSystem>(dt);
systems.update<ParticleSystem>(dt);
systems.update<AttackSystem>(dt);
+ //systems.update<UISystem>(dt);
}
diff --git a/src/font.cpp b/src/font.cpp
new file mode 100644
index 0000000..adffa9c
--- /dev/null
+++ b/src/font.cpp
@@ -0,0 +1,131 @@
+#include <font.hpp>
+
+FT_Library FontSystem::ftLibrary;
+FT_Face FontSystem::ftFace;
+
+std::string FontSystem::fontFamily;
+std::map<int, std::vector<FT_Info>> FontSystem::fontData;
+
+int FontSystem::currentSize = 0;
+Color FontSystem::currentColor;
+float FontSystem::currentZ = -8.0f;
+
+void FontSystem::init(const std::string& ttf)
+{
+ FT_Init_FreeType(&ftLibrary);
+ FT_New_Face(ftLibrary, ttf.c_str(), 0, &ftFace);
+}
+
+void FontSystem::setFontSize(int size)
+{
+ auto result = fontData.try_emplace(size, 93);
+ if (result.second) {
+ FT_Set_Pixel_Sizes(ftFace, 0, size);
+
+ char c = 33;
+ for (auto& d : fontData.at(size)) {
+ glDeleteTextures(1, &d.tex);
+ glGenTextures(1, &d.tex); // Generate new texture name/locations?
+
+ // load the character from the font family file
+ FT_Load_Char(ftFace, c++, FT_LOAD_RENDER);
+
+ // transfer the character's bitmap (?) to a texture for rendering
+ glBindTexture(GL_TEXTURE_2D, d.tex);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER , GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER , GL_LINEAR);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ /**
+ * The just-created texture will render red-on-black if we don't do anything to it, so
+ * here we create a buffer 4 times the size and transform the texture into an RGBA array,
+ * making it white-on-black.
+ */
+ auto& g = ftFace->glyph;
+ std::vector<uint32_t> buf (g->bitmap.width * g->bitmap.rows, 0xFFFFFFFF);
+ for (auto j = buf.size(); j--;)
+ buf[j] ^= !g->bitmap.buffer[j] ? buf[j] : 0;
+
+ d.wh.x = g->bitmap.width;
+ d.wh.y = g->bitmap.rows;
+ d.bl.x = g->bitmap_left;
+ d.bl.y = g->bitmap_top;
+ d.ad.x = g->advance.x >> 6;
+ d.ad.y = g->advance.y >> 6;
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, g->bitmap.width, g->bitmap.rows,
+ 0, GL_RGBA, GL_UNSIGNED_BYTE, buf.data());
+ }
+ }
+
+ currentSize = size;
+}
+
+void FontSystem::setFontColor(float r, float g, float b)
+{
+ currentColor.red = r;
+ currentColor.green = g;
+ currentColor.blue = b;
+}
+
+void FontSystem::setFontZ(float z)
+{
+ currentZ = z;
+}
+
+vec2 FontSystem::putChar(float xx, float yy, char c)
+{
+ const auto& ch = fontData.at(currentSize)[c - 33];
+ int x = xx, y = yy;
+
+ // get dimensions of the rendered character
+ vec2 c1 = {
+ static_cast<float>(floor(x) + ch.bl.x),
+ static_cast<float>(floor(y) + ch.bl.y)
+ };
+ const auto& c2 = ch.wh;
+
+ Render::textShader.use();
+ Render::textShader.enable();
+
+ // draw the character
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, ch.tex);
+
+ glUniform4f(Render::textShader.uniform[WU_tex_color], 1.0f, 1.0f, 1.0f, 1.0f);
+
+ GLfloat tex_coord[] = {
+ 0.0, 1.0, // bottom left
+ 1.0, 1.0, // bottom right
+ 1.0, 0.0, // top right
+ 1.0, 0.0, // top right
+ 0.0, 0.0, // top left
+ 0.0, 1.0, // bottom left
+ };
+
+ GLfloat text_vert[] = {
+ c1.x, c1.y - c2.y, currentZ, // bottom left
+ c1.x + c2.x, c1.y - c2.y, currentZ, // bottom right
+ c1.x + c2.x, c1.y + c2.y - c2.y, currentZ, // top right
+ c1.x + c2.x, c1.y + c2.y - c2.y, currentZ, // top right
+ c1.x, c1.y + c2.y - c2.y, currentZ, // top left
+ c1.x, c1.y - c2.y, currentZ // bottom left
+ };
+
+ glUniform4f(Render::textShader.uniform[WU_tex_color],
+ currentColor.red, currentColor.green, currentColor.blue, currentColor.alpha);
+
+ glVertexAttribPointer(Render::textShader.coord, 3, GL_FLOAT, GL_FALSE, 0, text_vert);
+ glVertexAttribPointer(Render::textShader.tex, 2, GL_FLOAT, GL_FALSE, 0, tex_coord);
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+
+ glUniform4f(Render::textShader.uniform[WU_tex_color], 1.0, 1.0, 1.0, 1.0);
+
+ Render::textShader.disable();
+ Render::textShader.unuse();
+
+ // return the width.
+ return ch.ad;
+}
+
diff --git a/src/inventory.cpp b/src/inventory.cpp
index 3e7104e..761ca43 100644
--- a/src/inventory.cpp
+++ b/src/inventory.cpp
@@ -4,6 +4,7 @@
#include <components.hpp>
#include <engine.hpp>
#include <error.hpp>
+#include <font.hpp>
#include <player.hpp>
#include <render.hpp>
#include <ui.hpp>
@@ -126,9 +127,9 @@ void InventorySystem::render(void)
if (n == movingItem)
glUniform4f(Render::textShader.uniform[WU_tex_color], .8, .8, 1, .8);
glDrawArrays(GL_TRIANGLES, 0, 6);
- ui::setFontZ(inventoryZ - 0.3); // TODO fix z's
- ui::putText(i.loc.x, i.loc.y, std::to_string(i.count).c_str());
- ui::setFontZ(-6);
+ FontSystem::setFontZ(inventoryZ - 0.3); // TODO fix z's
+ UISystem::putString(i.loc, std::to_string(i.count));
+ FontSystem::setFontZ(-6);
glUniform4f(Render::textShader.uniform[WU_tex_color], 1, 1, 1, 1);
}
}
@@ -211,7 +212,7 @@ void InventorySystem::receive(const MouseReleaseEvent &mre)
auto e = game::entities.create();
e.assign<Position>(mre.position.x, mre.position.y);
- e.assign<Direction>(0, 1);
+ e.assign<Direction>(0, 0.1f);
e.assign<ItemDrop>(items[movingItem]);
e.assign<Sprite>();
e.component<Sprite>()->addSpriteSegment(
diff --git a/src/particle.cpp b/src/particle.cpp
index 02f3640..a546c0c 100644
--- a/src/particle.cpp
+++ b/src/particle.cpp
@@ -98,8 +98,6 @@ void ParticleSystem::update(entityx::EntityManager &en, entityx::EventManager &e
(void)en;
(void)ev;
- auto& worldSystem = *game::engine.getSystem<WorldSystem>();
-
for (unsigned int i = 0; i < parts.size(); i++) {
auto& p = parts[i];
auto& vel = p.velocity;
@@ -160,7 +158,7 @@ void ParticleSystem::update(entityx::EntityManager &en, entityx::EventManager &e
p.location.y += vel.y * dt;
// world collision
- auto height = worldSystem.isAboveGround(p.location);
+ auto height = WorldSystem::isAboveGround(p.location);
if (height != 0) {
if (p.type == ParticleType::Drop || p.type == ParticleType::SmallPoof)
p.location.y = height + 5, p.velocity.y = randGet() % 10 / 40.0f;
diff --git a/src/player.cpp b/src/player.cpp
index 1537721..a458479 100644
--- a/src/player.cpp
+++ b/src/player.cpp
@@ -105,6 +105,9 @@ void PlayerSystem::update(entityx::EntityManager &en, entityx::EventManager &ev,
(void)ev;
(void)dt;
+ if (player.component<Health>()->health <= 0)
+ abort();
+
auto& vel = *player.component<Direction>().get();
if (moveLeft & !moveRight)
@@ -146,34 +149,32 @@ void PlayerSystem::receive(const KeyUpEvent &kue)
void PlayerSystem::receive(const KeyDownEvent &kde)
{
- static auto& worldSystem = *game::engine.getSystem<WorldSystem>();
-
auto kc = kde.keycode;
auto& loc = *player.component<Position>().get();
auto& vel = *player.component<Direction>().get();
if ((kc == SDLK_SPACE) && game::canJump && ((vel.y > -0.01) & (vel.y < 0.01))) {
loc.y += HLINES(2);
- vel.y = .4;
+ vel.y = 0.05f;
vel.grounded = false;
- } else if (!ui::dialogBoxExists || ui::dialogPassive) {
+ } else if (!UISystem::isDialog()) {
if (kc == getControl(0)) {
- if (!ui::fadeIntensity)
- worldSystem.goWorldPortal(loc);
+ if (!UISystem::isFading())
+ WorldSystem::goWorldPortal(loc);
} else if (kc == getControl(1)) {
- if (!ui::fadeEnable) {
+ if (!UISystem::isFading()) {
moveLeft = true;
moveRight = false;
- worldSystem.goWorldLeft(loc);
+ WorldSystem::goWorldLeft(loc);
}
} else if (kc == getControl(2)) {
- if (!ui::fadeEnable) {
+ if (!UISystem::isFading()) {
moveLeft = false;
moveRight = true;
- worldSystem.goWorldRight(loc, *player.component<Solid>().get());
+ WorldSystem::goWorldRight(loc, *player.component<Solid>().get());
}
} else if (kc == getControl(3)) {
if (game::canSprint)
@@ -221,7 +222,7 @@ void PlayerSystem::receive(const UseItemEvent& uie)
auto loc = getPosition();
auto &solid = *player.component<Solid>().get();
loc.x += solid.width / 2, loc.y += solid.height / 2;
- game::events.emit<AttackEvent>(loc, AttackType::ShortSlash);
+ game::events.emit<AttackEvent>(loc, AttackType::ShortSlash, true);
} else if (uie.item->type == "Bow") {
if (game::engine.getSystem<InventorySystem>()->take("Arrow", 1)) {
auto e = game::entities.create();
@@ -229,7 +230,7 @@ void PlayerSystem::receive(const UseItemEvent& uie)
e.assign<Position>(pos.x, pos.y + 10);
auto angle = std::atan2(uie.curs.y - pos.y, uie.curs.x - pos.x);
- e.assign<Direction>(1 * std::cos(angle), 1 * std::sin(angle));
+ e.assign<Direction>(0.25f * std::cos(angle), 0.25f * std::sin(angle));
e.assign<Visible>(-5);
e.assign<Physics>();
@@ -238,14 +239,14 @@ void PlayerSystem::receive(const UseItemEvent& uie)
sprite->addSpriteSegment(SpriteData(tex.sprite), 0);
auto dim = HLINES(sprite->getSpriteSize());
e.assign<Solid>(dim.x, dim.y);
- e.assign<Hit>(10);
+ e.assign<Hit>(10, false);
}
}
- /*cool.store(false);
- std::thread([&](void) {
- std::this_thread::sleep_for(std::chrono::milliseconds(uie.item->cooldown));
+ cool.store(false);
+ std::thread([&](unsigned int ms) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(ms));
cool.store(true);
- }).detach();*/
+ }, uie.item->cooldown).detach();
}
}
diff --git a/src/render.cpp b/src/render.cpp
index 84f3e7e..8c2f50d 100644
--- a/src/render.cpp
+++ b/src/render.cpp
@@ -5,6 +5,7 @@
#include <config.hpp>
#include <error.hpp>
#include <glm.hpp>
+#include <font.hpp>
#include <texture.hpp>
extern vec2 offset;
@@ -135,7 +136,7 @@ void preRender(void)
auto ploc = ps->getPosition();
offset.x = ploc.x + ps->getWidth() / 2;
- const auto& worldWidth = game::engine.getSystem<WorldSystem>()->getWidth();
+ const auto& worldWidth = WorldSystem::getWidth();
if (worldWidth < (int)SCREEN_WIDTH2 * 2)
offset.x = 0;
else if (offset.x - SCREEN_WIDTH2 < worldWidth * -0.5f)
@@ -174,7 +175,7 @@ void render(const int& fps)
{
preRender();
- game::engine.getSystem<WorldSystem>()->render();
+ WorldSystem::render();
game::engine.getSystem<ParticleSystem>()->render();
@@ -185,14 +186,17 @@ void render(const int& fps)
// draw the debug overlay if desired
if (ui::debug) {
auto pos = game::engine.getSystem<PlayerSystem>()->getPosition();
- ui::putText(offset.x - game::SCREEN_WIDTH / 2, (offset.y + game::SCREEN_HEIGHT / 2) - ui::fontSize,
+ UISystem::putText(vec2(offset.x - game::SCREEN_WIDTH / 2, (offset.y + game::SCREEN_HEIGHT / 2) - FontSystem::getSize()),
"loc: %s\noffset: %s\nfps: %d\nticks: %d\npcount: %d\nxml: %s",
pos.toString().c_str(), offset.toString().c_str(), fps,
game::time::getTickCount(), game::engine.getSystem<ParticleSystem>()->getCount(),
- game::engine.getSystem<WorldSystem>()->getXMLFile().c_str());
+ WorldSystem::getXMLFile().c_str()
+ );
}
- ui::drawFade();
+ UISystem::render();
+
+ //ui::drawFade();
ui::draw();
game::engine.getSystem<WindowSystem>()->render();
diff --git a/src/ui.cpp b/src/ui.cpp
index 00e43a2..d14b0a6 100644
--- a/src/ui.cpp
+++ b/src/ui.cpp
@@ -6,6 +6,7 @@
#include <bmpimage.hpp>
#include <debug.hpp>
#include <error.hpp>
+#include <font.hpp>
#include <ui_menu.hpp>
#include <vector3.hpp>
@@ -43,47 +44,15 @@ SDL_Keycode getControl(int index)
return controlMap[index];
}
-/**
- * Freetype variables
- */
-
-static FT_Library ftl;
-static FT_Face ftf;
-
-struct FT_Info {
- vec2 wh;
- vec2 bl;
- vec2 ad;
- GLuint tex;
-
- FT_Info(void)
- : tex(0) {}
-};
-
-static std::vector<FT_Info> ftData (93);
-
-static Color fontColor (255, 255, 255);
-
/*
* Variables for dialog boxes / options.
*/
-static std::vector<std::pair<vec2, std::string>> textToDraw;
-
-static std::vector<std::pair<std::string,vec3>> dialogOptText;
-static std::string dialogBoxText;
static bool typeOutDone = true;
static bool typeOutSustain = false;
static Mix_Chunk *dialogClick;
-/*
- * Fade effect flags
- */
-
-static bool fadeWhite = false;
-static bool fadeFast = false;
-
bool inBattle = false;
Mix_Chunk *battleStart;
@@ -92,55 +61,7 @@ Mix_Chunk *sanic;
static GLuint pageTex = 0;
static bool pageTexReady = false;
-void loadFontSize(int size, std::vector<FT_Info> &data)
-{
- FT_Set_Pixel_Sizes(ftf, 0, size);
-
- // pre-render 'all' the characters
- for (auto& d : data) {
- glDeleteTextures(1, &d.tex);
- glGenTextures(1, &d.tex); // Generate new texture name/locations?
- }
-
- for (char i = 33; i < 126; i++) {
- // load the character from the font family file
- UserAssert(!FT_Load_Char(ftf, i, FT_LOAD_RENDER), "Error! Unsupported character " + i);
-
- // transfer the character's bitmap (?) to a texture for rendering
- glBindTexture(GL_TEXTURE_2D, data[i - 33].tex);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER , GL_LINEAR);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER , GL_LINEAR);
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-
- /**
- * The just-created texture will render red-on-black if we don't do anything to it, so
- * here we create a buffer 4 times the size and transform the texture into an RGBA array,
- * making it white-on-black.
- */
- auto& g = ftf->glyph;
- std::vector<uint32_t> buf (g->bitmap.width * g->bitmap.rows, 0xFFFFFFFF);
- for (auto j = buf.size(); j--;)
- buf[j] ^= !g->bitmap.buffer[j] ? buf[j] : 0;
-
- auto& d = data[i - 33];
- d.wh.x = g->bitmap.width;
- d.wh.y = g->bitmap.rows;
- d.bl.x = g->bitmap_left;
- d.bl.y = g->bitmap_top;
- d.ad.x = g->advance.x >> 6;
- d.ad.y = g->advance.y >> 6;
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, g->bitmap.width, g->bitmap.rows,
- 0, GL_RGBA, GL_UNSIGNED_BYTE, buf.data());
- }
-}
-
namespace ui {
-
- bool fadeEnable = false;
- int fadeIntensity = 0;
-
/*
* Mouse coordinates.
*/
@@ -149,56 +70,14 @@ namespace ui {
vec2 premouse={0,0};
/*
- * Variety of keydown bools
- */
- bool edown;
-
- /*
* Debugging flags.
*/
bool debug=false;
bool posFlag=false;
- bool dialogPassive = false;
- bool dialogMerchant = false;
- int dialogPassiveTime = 0;
-
- int fontTransInv = 255;
-
- /*
- * Dialog stuff that needs to be 'public'.
- */
-
- bool dialogBoxExists = false;
- bool dialogImportant = false;
- unsigned char dialogOptChosen = 0;
-
- unsigned int textWrapLimit = 72;
-
- /*
- * Current font size. Changing this WILL NOT change the font size, see setFontSize() for
- * actual font size changing.
- */
-
- unsigned int fontSize;
- float fontZ = -8.0;
-
+
void takeScreenshot(GLubyte* pixels);
- /*
- * Initialises the Freetype library, and sets a font size.
- */
-
- void initFonts(void) {
- UserAssert(!FT_Init_FreeType(&ftl), "Couldn't initialize freetype.");
-
-#ifdef DEBUG
- DEBUG_printf("Initialized FreeType2.\n", nullptr);
-#endif // DEBUG
-
- fontSize = 0;
- }
-
void initSounds(void) {
dialogClick = Mix_LoadWAV("assets/sounds/click.wav");
battleStart = Mix_LoadWAV("assets/sounds/frig.wav");
@@ -206,183 +85,11 @@ namespace ui {
}
void destroyFonts(void) {
- FT_Done_Face(ftf);
- FT_Done_FreeType(ftl);
-
Mix_FreeChunk(dialogClick);
Mix_FreeChunk(battleStart);
Mix_FreeChunk(sanic);
}
- /*
- * Sets a new font family to use (*.ttf).
- */
-
- void setFontFace(const char *ttf) {
- UserAssert(!FT_New_Face(ftl, ttf, 0, &ftf), "Error! Couldn't open " +
- std::string(ttf) + ".");
-
-#ifdef DEBUG
- DEBUG_printf("Using font %s\n",ttf);
-#endif // DEBUG
- }
-
- /*
- * Sets a new font size (default: 12).
- */
-
- void setFontSize(unsigned int size) {
- fontSize = size;
- loadFontSize(size, ftData);
- }
-
- /*
- * Set a color for font rendering (default: white).
- */
- void setFontColor(int r, int g, int b, int a = 255) {
- fontColor = Color(r, g, b, a);
- }
-
- /*
- * Set the font's z layer
- */
- void setFontZ(float z) {
- fontZ = z;
- }
-
- /*
- * Draws a character at the specified coordinates, aborting if the character is unknown.
- */
- vec2 putChar(float xx,float yy,char c){
- const auto& ch = ftData[c - 33];
- int x = xx, y = yy;
-
- // get dimensions of the rendered character
- vec2 c1 = {
- static_cast<float>(floor(x) + ch.bl.x),
- static_cast<float>(floor(y) + ch.bl.y)
- };
-
- const auto& c2 = ch.wh;
-
- // draw the character
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, ch.tex);
-
- Render::textShader.use();
- Render::textShader.enable();
-
- glUniform4f(Render::textShader.uniform[WU_tex_color], 1.0f, 1.0f, 1.0f, 1.0f);
-
- GLfloat tex_coord[] = {
- 0.0, 1.0, //bottom left
- 1.0, 1.0, //bottom right
- 1.0, 0.0, //top right
- 1.0, 0.0, //top right
- 0.0, 0.0, //top left
- 0.0, 1.0, //bottom left
- };
-
- GLfloat text_vert[] = {
- c1.x, c1.y -c2.y, fontZ, //bottom left
- c1.x+c2.x, c1.y -c2.y, fontZ, //bottom right
- c1.x+c2.x, c1.y+c2.y-c2.y, fontZ, //top right
- c1.x+c2.x, c1.y+c2.y-c2.y, fontZ, //top right
- c1.x, c1.y+c2.y-c2.y, fontZ, //top left
- c1.x, c1.y -c2.y, fontZ //bottom left
- };
-
- glUniform4f(Render::textShader.uniform[WU_tex_color],
- static_cast<float>(fontColor.red / 255),
- static_cast<float>(fontColor.green / 255),
- static_cast<float>(fontColor.blue / 255),
- static_cast<float>(fontColor.alpha / 255));
-
- glVertexAttribPointer(Render::textShader.coord, 3, GL_FLOAT, GL_FALSE, 0, text_vert);
- glVertexAttribPointer(Render::textShader.tex, 2, GL_FLOAT, GL_FALSE, 0, tex_coord);
- glDrawArrays(GL_TRIANGLES, 0, 6);
-
- glUniform4f(Render::textShader.uniform[WU_tex_color], 1.0, 1.0, 1.0, 1.0); // TODO seg faults
-
- Render::textShader.disable();
- Render::textShader.unuse();
-
- // return the width.
- return ch.ad;
- }
-
- /*
- * Draw a string at the specified coordinates.
- */
-
- float putString(const float x, const float y, std::string s) {
- unsigned int i = 0, nl = 1;
- vec2 add, o = {x, y};
-
- // loop on each character
- do {
- if (dialogBoxExists && i > textWrapLimit * nl) {
- o.y -= fontSize * 1.05f;
- o.x = x;
- ++nl;
-
- // skip a space if it's there since we just newline'd
- if (s[i] == ' ')
- i++;
- }
-
- switch (s[i]) {
- case '\r':
- case '\t':
- break;
- case '\n':
- o.y -= fontSize * 1.05f;
- o.x = x;
- break;
- case '\b':
- o.x -= add.x;
- break;
- case ' ':
- o.x += fontSize / 2;
- break;
- default:
- add = putChar(floor(o.x), floor(o.y), s[i]);
- o.x += add.x;
- o.y += add.y;
- break;
- }
- } while (s[++i]);
-
- return o.x; // the string width
- }
-
- float putStringCentered(const float x, const float y, std::string s) {
- unsigned int i = 0, lastnl = 0;
- float width = 0, yy = y;
-
- do {
- switch (s[i]) {
- case '\n':
- putString(floor(x - width / 2), yy, s.substr(0, i));
- lastnl = 1 + i;
- width = 0;
- yy -= fontSize * 1.15f;
- break;
- case '\b':
- break;
- case ' ':
- width += fontSize / 2;
- break;
- default:
- width += ftData[i].wh.x + fontSize * 0.1f;
- break;
- }
- } while(s[++i]);
-
- putString(floor(x - width / 2), yy, s.substr(lastnl));
- return width;
- }
-
/**
* Prevents typeOut from typing the next string it's given.
*/
@@ -458,89 +165,7 @@ namespace ui {
return ret;
}
- float putText(const float x, const float y, const char *str, ...) {
- va_list args;
-
- va_start(args,str);
- auto s = uisprintf(str, args);
- va_end(args);
-
- // draw the string and return the width
- return putString(x, y, s);
- }
-
- void putTextL(vec2 c, const char *str, ...) {
- va_list args;
-
- va_start(args, str);
- auto s = uisprintf(str, args);
- va_end(args);
-
- textToDraw.push_back(std::make_pair(c, s));
- }
-
- void dialogBox(std::string name, std::string opt, bool passive, std::string text, ...) {
- va_list args;
-
- dialogPassive = passive;
-
- // add speaker prefix
- dialogBoxText = name + ": ";
-
- // handle the formatted string
- va_start(args, text);
- auto s = uisprintf(text.c_str(), args);
- va_end(args);
-
- dialogBoxText += s;
-
- // setup option text
- dialogOptText.clear();
- dialogOptChosen = 0;
-
- if (!opt.empty()) {
- char *sopt = strtok(&opt[0], ":");
-
- // cycle through options
- while (sopt) {
- dialogOptText.push_back(std::make_pair((std::string)sopt, vec3 {0,0,0}));
- sopt = strtok(nullptr, ":");
- }
- }
-
- // tell draw() that the box is ready
- dialogBoxExists = true;
- dialogImportant = false;
-
- ret.clear();
- }
-
- /**
- * Wait for a dialog box to be dismissed.
- */
-
- void waitForDialog(void) {
- while (dialogBoxExists)
- std::this_thread::sleep_for(1ms);
- }
-
- void waitForCover(void) {
- auto& fi = fadeIntensity;
- fi = 0;
-
- while (fi < 255)
- std::this_thread::sleep_for(1ms);
-
- fi = 255;
- }
-
- void waitForUncover(void) {
- fadeIntensity = 255;
- while (fadeIntensity > 0);
- fadeIntensity = 0;
- }
-
- void importantText(const char *text, ...) {
+ /*void importantText(const char *text, ...) {
va_list args;
dialogBoxText.clear();
@@ -572,7 +197,7 @@ namespace ui {
dialogImportant = true;
dialogPassive = true;
dialogPassiveTime = duration;
- }
+ }*/
void drawPage(const GLuint& tex) {
@@ -580,51 +205,6 @@ namespace ui {
pageTexReady = true;
}
- void drawBox(vec2 c1, vec2 c2) {
- GLfloat box[] = {c1.x, c1.y, -7.0,
- c2.x, c1.y, -7.0,
- c2.x, c2.y, -7.0,
-
- c2.x, c2.y, -7.0,
- c1.x, c2.y, -7.0,
- c1.x, c1.y, -7.0};
-
- GLfloat line_strip[] = {c1.x, c1.y, -7.1,
- c2.x + 1, c1.y, -7.1,
- c2.x + 1, c2.y, -7.1,
- c1.x, c2.y, -7.1,
- c1.x, c1.y, -7.1};
-
- GLfloat box_tex[] = {0,0,
- 1,0,
- 1,1,
-
- 1,1,
- 0,1,
- 0,0};
-
- glActiveTexture(GL_TEXTURE0);
- Colors::black.use();
- glUniform1i(Render::textShader.uniform[WU_texture], 0);
-
- Render::textShader.use();
- Render::textShader.enable();
-
- glVertexAttribPointer(Render::textShader.coord, 3, GL_FLOAT, GL_FALSE, 0, box);
- glVertexAttribPointer(Render::textShader.tex, 2, GL_FLOAT, GL_FALSE, 0, box_tex);
- glDrawArrays(GL_TRIANGLES, 0 ,6);
-
- Colors::white.use();
- glUniform1i(Render::textShader.uniform[WU_texture], 0);
-
- glVertexAttribPointer(Render::textShader.coord, 3, GL_FLOAT, GL_FALSE, 0, line_strip);
- glVertexAttribPointer(Render::textShader.tex, 2, GL_FLOAT, GL_FALSE, 0, box_tex);
- glDrawArrays(GL_LINE_STRIP, 0 ,8);
-
- Render::textShader.disable();
- Render::textShader.unuse();
- }
-
void drawNiceBox(vec2 c1, vec2 c2, float z) {
drawNiceBoxColor(c1, c2, z, Color(1.0f, 1.0f, 1.0f));
}
@@ -785,7 +365,6 @@ namespace ui {
}
void draw(void){
- unsigned char i;
std::string rtext;
auto SCREEN_HEIGHT = static_cast<float>(game::SCREEN_HEIGHT);
@@ -826,7 +405,7 @@ namespace ui {
Render::textShader.disable();
Render::textShader.unuse();
- } else if (dialogBoxExists) {
+ } /* else if (dialogBoxExists) {
rtext = typeOut(dialogBoxText);
if (dialogImportant) {
@@ -840,11 +419,11 @@ namespace ui {
}
}
- if (fadeIntensity == 255 || dialogPassive) {
+ *if (fadeIntensity == 255 || dialogPassive) {
setFontSize(24);
putStringCentered(offset.x,offset.y,rtext);
setFontSize(16);
- }
+ }*
} else { //normal dialog box
float y = offset.y + SCREEN_HEIGHT / 2 - HLINES(8);
@@ -854,7 +433,7 @@ namespace ui {
setFontZ(-7.2f);
rtext = typeOut(dialogBoxText);
- putString(x + HLINES(2), y - fontSize - game::HLINE, rtext);
+ UISystem::putString(vec2(x + HLINES(2), y - fontSize - game::HLINE), rtext);
for (i = 0; i < dialogOptText.size(); i++) {
auto& sec = dialogOptText[i].second;
@@ -884,9 +463,9 @@ namespace ui {
} else {
for (const auto &s : textToDraw)
putString(s.first.x, s.first.y, s.second);
- }
+ }*/
- if (!fadeIntensity) {
+ //if (!fadeIntensity) {
/*vec2 hub = {
(SCREEN_WIDTH/2+offset.x)-fontSize*10,
(offset.y+SCREEN_HEIGHT/2)-fontSize
@@ -964,8 +543,8 @@ namespace ui {
putStringCentered(hub.x,hub.y,"Inventory:");
}*/
- setFontColor(255,255,255,255);
- }
+ // setFontColor(255,255,255,255);
+ //}
menu::draw();
@@ -979,126 +558,6 @@ namespace ui {
Render::textShader.unuse();
}
- void closeBox() {
- dialogBoxExists = false;
- dialogMerchant = false;
- }
-
- void dialogAdvance(void) {
- dialogPassive = false;
- dialogPassiveTime = 0;
-
- if (pageTex) {
- glDeleteTextures(1, &pageTex);
- pageTex = 0;
- pageTexReady = false;
- return;
- }
-
- if (!typeOutDone) {
- if (!dialogImportant)
- typeOutDone = true;
- return;
- }
-
- for (int i = 0; i < static_cast<int>(dialogOptText.size()); i++) {
- const auto& dot = dialogOptText[i].second;
-
- if (mouse.x > dot.x && mouse.x < dot.z &&
- mouse.y > dot.y && mouse.y < dot.y + 16) { // fontSize
- dialogOptChosen = i + 1;
- break;
- }
- }
-
- dialogBoxExists = false;
-
- // handle important text
- if (dialogImportant) {
- dialogImportant = false;
- setFontSize(16);
- }
- }
-
- void drawFade(void) {
- if (!fadeIntensity) {
- if (fontSize != 16)
- setFontSize(16);
- return;
- }
-
- static const GLfloat tex[12] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- };
-
- vec2 p1 (offset.x - game::SCREEN_WIDTH / 2, offset.y - game::SCREEN_HEIGHT / 2);
- vec2 p2 (p1.x + game::SCREEN_WIDTH, p1.y + game::SCREEN_HEIGHT);
- GLfloat backdrop[18] = {
- p1.x, p1.y, -7.9,
- p2.x, p1.y, -7.9,
- p2.x, p2.y, -7.9,
-
- p2.x, p2.y, -7.9,
- p1.x, p2.y, -7.9,
- p1.x, p1.y, -7.9
- };
-
- setFontZ(-8.2);
- Render::textShader.use();
- Render::textShader.enable();
-
- Colors::black.use();
- glUniform4f(Render::textShader.uniform[WU_tex_color], 1.0f, 1.0f, 1.0f, fadeIntensity / 255.0f);
- glVertexAttribPointer(Render::textShader.coord, 3, GL_FLOAT, GL_FALSE, 0, backdrop);
- glVertexAttribPointer(Render::textShader.tex, 2, GL_FLOAT, GL_FALSE, 0, tex);
- glDrawArrays(GL_TRIANGLES, 0, 6);
-
- Render::textShader.disable();
- Render::textShader.unuse();
- setFontZ(-8.0);
- }
-
- void fadeUpdate(void) {
- if (fadeEnable) {
- if (fadeIntensity < 150)
- fadeIntensity += fadeFast ? 20 : 5;
- else if (fadeIntensity < 255)
- fadeIntensity += fadeFast ? 10 : 5;
- else
- fadeIntensity = 255;
- } else {
- if (fadeIntensity > 150)
- fadeIntensity -= fadeFast ? 10 : 5;
- else if (fadeIntensity > 0)
- fadeIntensity -= fadeFast ? 20 : 5;
- else
- fadeIntensity = 0;
- }
- }
-
- void toggleBlack(void) {
- fadeEnable ^= true;
- fadeWhite = false;
- fadeFast = false;
- }
- void toggleBlackFast(void) {
- fadeEnable ^= true;
- fadeWhite = false;
- fadeFast = true;
- }
- void toggleWhite(void) {
- fadeEnable ^= true;
- fadeWhite = true;
- fadeFast = false;
- }
- void toggleWhiteFast(void) {
- fadeEnable ^= true;
- fadeWhite = true;
- fadeFast = true;
-
- //Mix_PlayChannel(1, battleStart, 0);
- }
-
void takeScreenshot(GLubyte* pixels) {
auto SCREEN_WIDTH = game::SCREEN_WIDTH;
auto SCREEN_HEIGHT = game::SCREEN_HEIGHT;
@@ -1159,6 +618,20 @@ namespace ui {
fclose(bmp);
}
+
+ bool handleGLEvent(SDL_Event& e) {
+ switch (e.type) {
+ case SDL_MOUSEBUTTONDOWN:
+ if ((UISystem::isDialog() | pageTexReady) && (e.button.button & SDL_BUTTON_RIGHT))
+ UISystem::advanceDialog();
+ return true;
+ break;
+ default:
+ break;
+ }
+
+ return false;
+ }
}
using namespace ui;
@@ -1199,25 +672,9 @@ void InputSystem::receive(const MainSDLEvent& event)
case SDL_MOUSEBUTTONDOWN:
ev.emit<MouseClickEvent>(mouse, e.button.button);
- // run actions?
- //if ((action::make = e.button.button & SDL_BUTTON_RIGHT))
- // /*player->inv->invHover =*/ edown = false;
-
- textToDraw.clear();
-
- if (dialogBoxExists || pageTexReady) {
- // right click advances dialog
+ if (UISystem::isDialog() || pageTexReady) {
if ((e.button.button & SDL_BUTTON_RIGHT))
- dialogAdvance();
- } else {
- // left click uses item
- if (e.button.button & SDL_BUTTON_LEFT) {
- /*if ((ent = currentWorld->getNearMob(*player)) != nullptr) {
- player->inv->currentAddInteract(ent);
- }
- player->inv->useCurrent();*/
- }
-
+ UISystem::advanceDialog();
}
break;
@@ -1242,22 +699,12 @@ void InputSystem::receive(const MainSDLEvent& event)
if (SDL_KEY == SDLK_ESCAPE)
ui::menu::toggle();
- if (SDL_KEY == SDLK_q) {
- /*auto item = player->inv->getCurrentItem();
- if (item != nullptr) {
- if (player->inv->takeItem(item->name, 1) == 0)
- currentWorld->addObject(item->name, "o shit waddup",
- player->loc.x + player->width / 2, player->loc.y + player->height / 2);
- }*/
- } else if (SDL_KEY == SDLK_h) {
+ if (SDL_KEY == SDLK_h) {
quest::toggle();
} else switch (SDL_KEY) {
case SDLK_F3:
debug ^= true;
break;
- case SDLK_BACKSLASH:
- dialogBoxExists = false;
- break;
case SDLK_b:
if (debug)
posFlag ^= true;
@@ -1300,3 +747,249 @@ void InputSystem::update(entityx::EntityManager &en, entityx::EventManager &ev,
mouse.x = premouse.x + offset.x - (game::SCREEN_WIDTH / 2);
mouse.y = (offset.y + game::SCREEN_HEIGHT / 2) - premouse.y;
}
+
+bool UISystem::fadeEnable = false;
+bool UISystem::fadeFast = false;
+int UISystem::fadeIntensity = 0;
+
+std::string UISystem::dialogText;
+std::string UISystem::importantText;
+std::vector<DialogOption> UISystem::dialogOptions;
+int UISystem::dialogOptionResult;
+
+void UISystem::fadeToggle(void)
+{
+ fadeEnable ^= true;
+ fadeFast = false;
+
+ fadeIntensity = fadeEnable ? 0 : 255;
+}
+
+void UISystem::fadeToggleFast(void)
+{
+ fadeEnable ^= true;
+ fadeFast = true;
+}
+
+void UISystem::waitForCover(void)
+{
+ fadeIntensity = 0;
+ while (fadeIntensity < 255)
+ std::this_thread::sleep_for(1ms);
+}
+
+void UISystem::waitForUncover(void)
+{
+ fadeIntensity = 255;
+ while (fadeIntensity > 0)
+ std::this_thread::sleep_for(1ms);
+}
+
+void UISystem::putText(const vec2& p, const std::string& s, ...)
+{
+ va_list args;
+
+ va_start(args, s);
+ putString(p, uisprintf(s.c_str(), args));
+ va_end(args);
+}
+
+void UISystem::putString(const vec2& p, const std::string& s, float wrap)
+{
+ vec2 offset = p, add;
+
+ for (auto c : s) {
+ switch (c) {
+ case '\n':
+ offset.y -= FontSystem::getSize() * 1.05f;
+ offset.x = p.x;
+ break;
+ case '\b':
+ offset.x -= add.x;
+ break;
+ case '\r':
+ case '\t':
+ break;
+ case ' ':
+ offset.x += FontSystem::getSize() / 2.0f;
+ break;
+ default:
+ add = FontSystem::putChar(floor(offset.x), floor(offset.y), c);
+ offset += add;
+ break;
+ }
+
+ if (wrap != 0.12345f && offset.x >= (wrap - 10)) {
+ offset.y -= FontSystem::getSize() * 1.05f;
+ offset.x = p.x;
+ }
+ }
+
+ //return offset.x;
+}
+
+float UISystem::putStringCentered(const vec2& p, const std::string& s, bool print)
+{
+ int i = 0, lastnl = 0;
+ float width = 0, yy = p.y;
+ auto& font = FontSystem::getFont();
+
+ do {
+ switch (s[i]) {
+ case '\n':
+ putString(vec2(floor(p.x - width / 2), yy), s.substr(0, i));
+ lastnl = 1 + i;
+ width = 0;
+ yy -= FontSystem::getSize() * 1.15f;
+ break;
+ case '\b':
+ break;
+ case ' ':
+ width += FontSystem::getSize() / 2;
+ break;
+ default:
+ width += font[i].wh.x + FontSystem::getSize() * 0.1f;
+ break;
+ }
+
+ } while(s[++i]);
+
+ if (print)
+ putString(vec2(floor(p.x - width / 2), yy), s.substr(lastnl));
+ return width;
+}
+
+void UISystem::dialogBox(const std::string& n, const std::string& s, ...)
+{
+ va_list args;
+
+ dialogText = n + ": ";
+
+ va_start(args, s);
+ dialogText += ui::uisprintf(s.c_str(), args);
+ va_end(args);
+}
+
+void UISystem::dialogAddOption(const std::string& o)
+{
+ dialogOptions.emplace_back(OptionDim(), o);
+}
+
+void UISystem::dialogImportant(const std::string& s)
+{
+ importantText = s;
+}
+
+void UISystem::waitForDialog(void)
+{
+ while (isDialog())
+ std::this_thread::sleep_for(1ms);
+}
+
+int UISystem::getDialogResult(void)
+{
+ return dialogOptionResult;
+}
+
+void UISystem::advanceDialog(void)
+{
+ dialogText.clear();
+ importantText.clear();
+
+ if (!dialogOptions.empty()) {
+ int r = 1;
+ dialogOptionResult = 0;
+ for (auto& o : dialogOptions) {
+ if (ui::mouse.x > o.first.x - o.first.width / 2 && ui::mouse.x < o.first.x + o.first.width / 2 &&
+ ui::mouse.y > o.first.y && ui::mouse.y < o.first.y + 20) {
+ dialogOptionResult = r;
+ break;
+ }
+ r++;
+ }
+
+ dialogOptions.clear();
+ }
+}
+
+void UISystem::update(entityx::EntityManager& en, entityx::EventManager& ev, entityx::TimeDelta dt)
+{
+ (void)en;
+ (void)ev;
+ (void)dt;
+}
+
+void UISystem::render(void)
+{
+ if ((fadeEnable & (fadeIntensity < 255)))
+ fadeIntensity += fadeFast ? 15 : 5;
+ else if ((!fadeEnable & (fadeIntensity > 0)))
+ fadeIntensity -= fadeFast ? 15 : 5;
+
+ if (fadeIntensity < 0)
+ fadeIntensity = 0;
+ if (fadeIntensity > 255)
+ fadeIntensity = 255;
+
+ if (fadeIntensity != 0) {
+ static const GLfloat tex[12] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+
+ vec2 p1 (offset.x - game::SCREEN_WIDTH / 2, offset.y - game::SCREEN_HEIGHT / 2);
+ vec2 p2 (p1.x + game::SCREEN_WIDTH, p1.y + game::SCREEN_HEIGHT);
+ GLfloat backdrop[18] = {
+ p1.x, p1.y, -7.9,
+ p2.x, p1.y, -7.9,
+ p2.x, p2.y, -7.9,
+
+ p2.x, p2.y, -7.9,
+ p1.x, p2.y, -7.9,
+ p1.x, p1.y, -7.9
+ };
+
+ Render::textShader.use();
+ Render::textShader.enable();
+
+ Colors::black.use();
+ glUniform4f(Render::textShader.uniform[WU_tex_color], 1.0f, 1.0f, 1.0f, fadeIntensity / 255.0f);
+ glVertexAttribPointer(Render::textShader.coord, 3, GL_FLOAT, GL_FALSE, 0, backdrop);
+ glVertexAttribPointer(Render::textShader.tex, 2, GL_FLOAT, GL_FALSE, 0, tex);
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+
+ Render::textShader.disable();
+ Render::textShader.unuse();
+ //setFontZ(-8.0);
+ }
+
+ if (!dialogText.empty()) {
+ vec2 where (offset.x - 300, game::SCREEN_HEIGHT - 60);
+ ui::drawNiceBox(vec2(where.x - 10, where.y - 200), vec2(where.x + 620, where.y + 20), -5.5f);
+ putString(where, dialogText, where.x + 600);
+
+ if (!dialogOptions.empty()) {
+ float y = where.y - 180;
+ for (auto& o : dialogOptions) {
+ o.first.x = offset.x;
+ o.first.y = y;
+ o.first.width = putStringCentered(vec2(o.first.x, o.first.y), o.second, false);
+ y += 20;
+
+ if (ui::mouse.x > o.first.x - o.first.width / 2 && ui::mouse.x < o.first.x + o.first.width / 2 &&
+ ui::mouse.y > o.first.y && ui::mouse.y < y)
+ FontSystem::setFontColor(255, 255, 0);
+
+ putStringCentered(vec2(o.first.x, o.first.y), o.second);
+ FontSystem::setFontColor(255, 255, 255);
+ }
+ }
+ }
+
+ if (!importantText.empty()) {
+ FontSystem::setFontSize(24);
+ FontSystem::setFontZ(-9.0f);
+ putStringCentered(vec2(offset.x, 400), importantText);
+ FontSystem::setFontZ(-6.0f);
+ FontSystem::setFontSize(16);
+ }
+}
diff --git a/src/ui_menu.cpp b/src/ui_menu.cpp
index e5f5f9d..b49f0e9 100644
--- a/src/ui_menu.cpp
+++ b/src/ui_menu.cpp
@@ -5,6 +5,7 @@
#include <fileio.hpp>
#include <render.hpp>
#include <texture.hpp>
+#include <font.hpp>
#include <fstream>
@@ -18,8 +19,10 @@ static Menu controlsMenu;
void Menu::gotoParent(void)
{
- if (parent == nullptr)
+ if (parent == nullptr) {
game::config::update();
+ FontSystem::setFontSize(16);
+ }
currentMenu = parent;
}
@@ -219,9 +222,9 @@ namespace ui {
Render::useShader(&Render::textShader);
- setFontSize(24);
game::config::update();
- setFontZ(-9.0);
+ FontSystem::setFontSize(24);
+ FontSystem::setFontZ(-9.0);
mouse.x = ui::premouse.x+offset.x-(SCREEN_WIDTH/2);
mouse.y = (offset.y+SCREEN_HEIGHT/2)-ui::premouse.y;
@@ -297,8 +300,8 @@ namespace ui {
ui::drawNiceBoxColor(loc, end, -8.6, Color(cMult, cMult, cMult, 1.0f));
//draw the button text
- putStringCentered(loc.x + (m.dim.x / 2),
- loc.y + (m.dim.y / 2) - (ui::fontSize / 2),
+ UISystem::putStringCentered(vec2(loc.x + (m.dim.x / 2),
+ loc.y + (m.dim.y / 2) - (FontSystem::getSize() / 2)),
m.text);
//if element is a slider
@@ -348,18 +351,19 @@ namespace ui {
vec2(loc.x + sliderW, loc.y + (m.slider.sliderLoc * 1.05) + sliderH), -8.7, Color(cMult, cMult, cMult, 1.0f));
//draw the now combined slider text
- putStringCentered(loc.x + (m.dim.x/2), (loc.y + (m.dim.y*1.05)) - ui::fontSize/2, outSV);
+ UISystem::putStringCentered(vec2(loc.x + (m.dim.x/2), (loc.y + (m.dim.y*1.05)) - FontSystem::getSize() / 2), outSV);
} else {
ui::drawNiceBoxColor(vec2(loc.x+m.slider.sliderLoc, loc.y),
vec2(loc.x + m.slider.sliderLoc + sliderW, loc.y + sliderH), -8.7, Color(cMult, cMult, cMult, 1.0f));
//draw the now combined slider text
- putStringCentered(loc.x + (m.dim.x/2), (loc.y + (m.dim.y/2)) - ui::fontSize/2, outSV);
+ UISystem::putStringCentered(loc + (m.dim / 2) /*- FontSystem::getSize() / 2*/, outSV);
}
}
}
- setFontSize(16);
- setFontZ(-8.0);
+
+ FontSystem::setFontSize(16);
+ FontSystem::setFontZ(-8.0);
}
diff --git a/src/world.cpp b/src/world.cpp
index 353f4d9..e251706 100644
--- a/src/world.cpp
+++ b/src/world.cpp
@@ -14,7 +14,6 @@ using namespace std::literals::chrono_literals;
using namespace tinyxml2;
// game headers
-#include <attack.hpp>
#include <common.hpp>
#include <components.hpp>
#include <debug.hpp>
@@ -29,6 +28,16 @@ using namespace tinyxml2;
#include <vector3.hpp>
#include <weather.hpp>
+WorldData2 WorldSystem::world;
+Mix_Music* WorldSystem::bgmObj;
+std::string WorldSystem::bgmCurrent;
+std::vector<std::string> WorldSystem::bgFiles;
+TextureIterator WorldSystem::bgTex;
+XMLDocument WorldSystem::xmlDoc;
+std::string WorldSystem::currentXMLFile;
+std::thread WorldSystem::thAmbient;
+std::vector<vec2> WorldSystem::stars;
+
extern std::string xmlFolder;
// wait
@@ -115,9 +124,18 @@ void WorldSystem::generate(int width)
// define x-coordinate of world's leftmost 'line'
world.startX = HLINES(width * -0.5);
+
+ // gen. star coordinates
+ if (stars.empty()) {
+ stars.resize(game::SCREEN_WIDTH / 30);
+ for (auto& s : stars) {
+ s.x = world.startX + (randGet() % (int)HLINES(width));
+ s.y = game::SCREEN_HEIGHT - (randGet() % (int)HLINES(game::SCREEN_HEIGHT / 1.3f));
+ }
+ }
}
-float WorldSystem::isAboveGround(const vec2& p) const
+float WorldSystem::isAboveGround(const vec2& p)
{
int line = std::clamp(static_cast<int>((p.x - world.startX) / game::HLINE),
0, static_cast<int>(world.data.size()));
@@ -371,6 +389,8 @@ void WorldSystem::load(const std::string& file)
entity.assign<Aggro>(wxml, abcd);
else if (tname == "Animation")
entity.assign<Animate>(wxml, abcd);
+ else if (tname == "Trigger")
+ entity.assign<Trigger>(wxml, abcd);
abcd = abcd->NextSiblingElement();
}
@@ -380,11 +400,6 @@ void WorldSystem::load(const std::string& file)
}
}
- // hill creation
- /*else if (tagName == "hill") {
- addHill(ivec2 { wxml->IntAttribute("peakx"), wxml->IntAttribute("peaky") }, wxml->UnsignedAttribute("width"));
- }*/
-
wxml = wxml->NextSiblingElement();
}
@@ -442,76 +457,6 @@ loadWorldFromXMLNoSave(std::string path) {
const char *ptr;
std::string name, sptr;
- // iterate through world tags
- while (wxml) {
- newEntity = nullptr;
- name = wxml->Name();
-
- // set spawn x for player
- else if (name == "spawnx" && !(loadedLeft | loadedRight)) {
- player->loc.x = std::stoi(wxml->GetText());
- }
-
- // mob creation
- else if (name == "rabbit") {
- newEntity = new Rabbit();
- } else if (name == "bird") {
- newEntity = new Bird();
- } else if (name == "trigger") {
- newEntity = new Trigger();
- } else if (name == "door") {
- newEntity = new Door();
- } else if (name == "page") {
- newEntity = new Page();
- } else if (name == "cat") {
- newEntity = new Cat();
- } else if (name == "chest") {
- newEntity = new Chest();
- }
-
- // npc creation
- else if (name == "npc") {
- newEntity = new NPC();
- }
-
- // structure creation
- else if (name == "structure") {
- newEntity = new Structures();
- }
-
- // hill creation
- else if (name == "hill") {
- tmp->addHill(ivec2 { wxml->IntAttribute("peakx"), wxml->IntAttribute("peaky") }, wxml->UnsignedAttribute("width"));
- }
-
- if (newEntity != nullptr) {
- //bool alive = true;
- //if (wxml->QueryBoolAttribute("alive", &alive) != XML_NO_ERROR || alive) {
- switch (newEntity->type) {
- case NPCT:
- tmp->addNPC(dynamic_cast<NPC *>(newEntity));
- break;
- case MOBT:
- tmp->addMob(dynamic_cast<Mob *>(newEntity), vec2 {0, 0});
- break;
- case STRUCTURET:
- tmp->addStructure(dynamic_cast<Structures *>(newEntity));
- break;
- default:
- break;
- }
-
- std::swap(currentXML, _currentXML);
- std::swap(currentXMLRaw, _currentXMLRaw);
- newEntity->createFromXML(wxml, tmp);
- std::swap(currentXML, _currentXML);
- std::swap(currentXMLRaw, _currentXMLRaw);
- //}
- }
-
- wxml = wxml->NextSiblingElement();
- }
-
Village *vptr;
Structures *s;
@@ -607,18 +552,13 @@ loadWorldFromXMLNoSave(std::string path) {
vil = vil->NextSiblingElement();
}
- if (!loadedLeft && !loadedRight) {
- currentXML = _currentXML;
- currentXMLRaw = _currentXMLRaw;
- } else {
- delete _currentXMLDoc;
- }
-
return tmp;
}*/
WorldSystem::WorldSystem(void)
- : bgmObj(nullptr) {}
+{
+ bgmObj = nullptr;
+}
WorldSystem::~WorldSystem(void)
{
@@ -730,16 +670,16 @@ void WorldSystem::render(void)
//makeWorldDrawingSimplerEvenThoughAndyDoesntThinkWeCanMakeItIntoFunctions(0, fron_tex_coord, tex_coord, 6);
// TODO make stars dynamic (make them particles??)
- /*static GLuint starTex = Texture::loadTexture("assets/style/classic/bg/star.png");
+ static const Texture starTex ("assets/style/classic/bg/star.png"); // TODO why in theme, not just std.?
const static float stardim = 24;
- GLfloat star_coord[star.size() * 5 * 6 + 1];
- GLfloat *si = &star_coord[0];
+ GLfloat* star_coord = new GLfloat[stars.size() * 5 * 6 + 1];
+ GLfloat* si = &star_coord[0];
if (worldShade > 0) {
auto xcoord = offset.x * 0.9f;
- for (auto &s : star) {
+ for (auto &s : stars) {
float data[30] = {
s.x + xcoord, s.y, 9.7, 0, 0,
s.x + xcoord + stardim, s.y, 9.7, 1, 0,
@@ -752,11 +692,13 @@ void WorldSystem::render(void)
std::memcpy(si, data, sizeof(float) * 30);
si += 30;
}
- glBindTexture(GL_TEXTURE_2D, starTex);
- glUniform4f(Render::worldShader.uniform[WU_tex_color], 1.0, 1.0, 1.0, 1.3 - static_cast<float>(alpha)/255.0f);
+ starTex.use();
+ glUniform4f(Render::worldShader.uniform[WU_tex_color], 1.0, 1.0, 1.0, 1.3);
- makeWorldDrawingSimplerEvenThoughAndyDoesntThinkWeCanMakeItIntoFunctions(5 * sizeof(GLfloat), &star_coord[0], &star_coord[3], star.size() * 6);
- }*/
+ glVertexAttribPointer(Render::worldShader.coord, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), &star_coord[0]);
+ glVertexAttribPointer(Render::worldShader.tex, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), &star_coord[3]);
+ glDrawArrays(GL_TRIANGLES, 0, stars.size() * 6);
+ }
Render::worldShader.disable();
@@ -1090,9 +1032,10 @@ void WorldSystem::detect(entityx::TimeDelta dt)
{
game::entities.each<Health>(
[](entityx::Entity e, Health& h) {
- if (h.health <= 0)
+ if (h.health <= 0) {
e.kill();
//e.destroy();
+ }
});
game::entities.each<Grounded, Position, Solid>(
@@ -1141,11 +1084,6 @@ void WorldSystem::detect(entityx::TimeDelta dt)
} else {
loc.y = data[line].groundHeight - 0.001f * dt;
vel.y = 0;
- if (e.has_component<Hit>()) {
- game::events.emit<AttackEvent>(vec2(loc.x, loc.y),
- AttackType::SmallBoom, e.component<Hit>()->damage);
- e.destroy();
- }
if (!vel.grounded) {
vel.grounded = true;
game::engine.getSystem<ParticleSystem>()->addMultiple(20, ParticleType::SmallPoof,
@@ -1157,9 +1095,11 @@ void WorldSystem::detect(entityx::TimeDelta dt)
// insure that the entity doesn't fall off either edge of the world.
if (loc.x < world.startX) {
+ std::cout << "Left!\n";
vel.x = 0;
loc.x = world.startX + HLINES(0.5f);
} else if (loc.x + dim.width + game::HLINE > -(static_cast<int>(world.startX))) {
+ std::cout << "Right\n";
vel.x = 0;
loc.x = -(static_cast<int>(world.startX)) - dim.width - game::HLINE;
}
@@ -1169,26 +1109,26 @@ void WorldSystem::detect(entityx::TimeDelta dt)
void WorldSystem::goWorldRight(Position& p, Solid &d)
{
if (!(world.toRight.empty()) && (p.x + d.width > world.startX * -1 - HLINES(5))) {
- ui::toggleBlack();
- ui::waitForCover();
+ UISystem::fadeToggle();
+ UISystem::waitForCover();
while (waitToSwap)
std::this_thread::sleep_for(1ms);
load(world.toRight);
game::engine.getSystem<PlayerSystem>()->setX(world.startX + HLINES(10));
- ui::toggleBlack();
+ UISystem::fadeToggle();
}
}
void WorldSystem::goWorldLeft(Position& p)
{
if (!(world.toLeft.empty()) && (p.x < world.startX + HLINES(10))) {
- ui::toggleBlack();
- ui::waitForCover();
+ UISystem::fadeToggle();
+ UISystem::waitForCover();
while (waitToSwap)
std::this_thread::sleep_for(1ms);
load(world.toLeft);
game::engine.getSystem<PlayerSystem>()->setX(world.startX * -1 - HLINES(15));
- ui::toggleBlack();
+ UISystem::fadeToggle();
}
}
@@ -1214,11 +1154,11 @@ void WorldSystem::goWorldPortal(Position& p)
}
if (!file.empty()) {
- ui::toggleBlack();
- ui::waitForCover();
+ UISystem::fadeToggle();
+ UISystem::waitForCover();
while (waitToSwap)
std::this_thread::sleep_for(1ms);
load(file);
- ui::toggleBlack();
+ UISystem::fadeToggle();
}
}