diff options
Diffstat (limited to 'src/entities.cpp.bak')
-rw-r--r-- | src/entities.cpp.bak | 1352 |
1 files changed, 1352 insertions, 0 deletions
diff --git a/src/entities.cpp.bak b/src/entities.cpp.bak new file mode 100644 index 0000000..e005df5 --- /dev/null +++ b/src/entities.cpp.bak @@ -0,0 +1,1352 @@ +#include <entities.hpp> + +#include <istream> +#include <sstream> +#include <fstream> + +#include <ui.hpp> +#include <world.hpp> +#include <gametime.hpp> +#include <brice.hpp> + +#include <render.hpp> +#include <engine.hpp> + +///NEW +#include <components.hpp> +#include <entityx/entityx.h> +///OLD + +extern std::istream *names; + +extern Player *player; // main.cpp +extern World *currentWorld; // main.cpp +extern unsigned int loops; // main.cpp + +extern std::string xmlFolder; +extern XMLDocument currentXMLDoc; + +// a dynamic array of pointers to the NPC's that are being assigned the preloads +std::vector<NPC *> aipreload; + +// the size of the player's inventory +const unsigned int PLAYER_INV_SIZE = 43; +// the size of an NPC's inventory +const unsigned int NPC_INV_SIZE = 3; + +static std::vector<std::string> randomDialog (readFileA("assets/dialog_en-us")); + + +void PlayerSystem::update(entityx::EntityManager &en, entityx::EventManager &ev, entityx::TimeDelta dt) +{ + (void)en; + (void)ev; + (void)dt; + + if (!m_MoveLeft && !m_MoveRight) + (*m_Player)->vel.x = 0; +} + +void PlayerSystem::configure(entityx::EventManager &ev) +{ + ev.subscribe<KeyDownEvent>(*this); + ev.subscribe<KeyUpEvent>(*this); +} + +extern World *currentWorldToLeft; +extern World *currentWorldToRight; +extern bool gameRunning; +extern bool inBattle; + +void PlayerSystem::receive(const KeyUpEvent &kue) +{ + auto p = *m_Player; + auto kc = kue.keycode; + + if (kc == SDLK_ESCAPE) { + ui::menu::toggle(); + p->save(); + } else if (kc == getControl(1)) { + m_MoveLeft = false; + } else if (kc == getControl(2)) { + m_MoveRight = false; + } else if (kc == getControl(3) || kc == getControl(4)) { + player->speed = 1; + } else if (kc == getControl(5)) { + if (p->inv->invHover) { + p->inv->invHover = false; + } else { + if (!p->inv->selected) + p->inv->invOpening ^= true; + else + p->inv->selected = false; + + p->inv->mouseSel = false; + } + + // disable action ui + ui::action::disable(); + } +} + +void PlayerSystem::receive(const KeyDownEvent &kde) +{ + auto p = *m_Player; + auto kc = kde.keycode; + + auto worldSwitch = [&](const WorldSwitchInfo& wsi){ + player->canMove = false; + ui::toggleBlackFast(); + ui::waitForCover(); + game::events.emit<BGMToggleEvent>(wsi.first->bgm, wsi.first); + std::tie(currentWorld, player->loc) = wsi; // using p causes segfault + game::engine.getSystem<WorldSystem>()->setWorld(currentWorld); + ui::toggleBlackFast(); + ui::waitForUncover(); + player->canMove = true; // using p causes segfault + }; + + if ((kc == SDLK_SPACE) && (game::canJump & p->ground)) { + p->loc.y += HLINES(2); + p->vel.y = .4; + p->ground = false; + } + + if (!ui::dialogBoxExists || ui::dialogPassive) { + if (kc == getControl(0)) { + if (inBattle) { + std::thread([&](void){ + auto thing = dynamic_cast<Arena *>(currentWorld)->exitArena(p); + if (thing.first != currentWorld) + worldSwitch(thing); + }).detach(); + } else if (!ui::fadeIntensity) { + std::thread([&](void){ + auto thing = currentWorld->goInsideStructure(p); + if (thing.first != currentWorld) + worldSwitch(thing); + }).detach(); + } + } else if (kc == getControl(1)) { + if (!ui::fadeEnable) { + p->vel.x = -PLAYER_SPEED_CONSTANT; + if (std::stoi(game::getValue("Slow")) == 1) + p->vel.x /= 2.0f; + p->left = m_MoveLeft = true; + p->right = m_MoveRight = false; + if (currentWorldToLeft) { + std::thread([&](void){ + auto thing = currentWorld->goWorldLeft(p); + if (thing.first != currentWorld) + worldSwitch(thing); + }).detach(); + } + } + } else if (kc == getControl(2)) { + if (!ui::fadeEnable) { + p->vel.x = PLAYER_SPEED_CONSTANT; + if (std::stoi(game::getValue("Slow")) == 1) + p->vel.x /= 2.0f; + p->right = m_MoveRight = true; + p->left = m_MoveLeft = false; + if (currentWorldToRight) { + std::thread([&](void){ + auto thing = currentWorld->goWorldRight(p); + if (thing.first != currentWorld) + worldSwitch(thing); + }).detach(); + } + } + } else if (kc == getControl(3)) { + if (game::canSprint) + p->speed = 2.0f; + } else if (kc == getControl(4)) { + p->speed = .5; + } else if (kc == getControl(5)) { + /*static int heyOhLetsGo = 0; + + //edown = true; + + // start hover counter? + if (!heyOhLetsGo) { + heyOhLetsGo = game::time::getTickCount(); + p->inv->mouseSel = false; + } + + // run hover thing + if (game::time::getTickCount() - heyOhLetsGo >= 2 && !(p->inv->invOpen) && !(p->inv->selected)) { + p->inv->invHover = true; + + // enable action ui + ui::action::enable(); + }*/ + } + } else if (kc == SDLK_DELETE) { + game::endGame(); + } else if (kc == SDLK_t) { + game::time::tick(50); + } +} + + +void getRandomName(Entity *e) +{ + auto names = readFileA("assets/names_en-us"); + auto name = names[randGet() % names.size()]; + + // gender is a binary construct + e->gender = (name[0] == 'm') ? MALE : FEMALE; + + e->name = &name[1]; +} + +Entity::Entity(void) +{ + vel = 0; + width = 0; + height = 0; + health = 0; + maxHealth = 0; + outnabout = 0; + targetx = 0.9112001f; + + type = UNKNOWNT; + + // set flags + alive = true; + right = true; + left = false; + near = false; + canMove = true; + ground = false; + forcedMove = false; + z = 0.0f; + + // clear counters + ticksToUse = 0; + hitCooldown = 0; + + hitDuration = maxHitDuration = 0; + + inv = nullptr; +} + +// spawns the entity you pass to it based off of coords and global entity settings +void Entity::spawn(float x, float y) +{ + loc.x = x; + loc.y = y; + + if (health == 0 && maxHealth == 0) + health = maxHealth = 1; + + // generate a name + if (type == MOBT) + name = "mob"; + else + getRandomName(this); + + setCooldown(0); +} + +void Entity::takeHit(unsigned int _health, unsigned int cooldown) +{ + if (hitCooldown <= 1) { + // modify variables + health = fmax(health - _health, 0); + forcedMove = true; + hitCooldown = cooldown; + + hitDuration = maxHitDuration = 350.0f; + + // pushback + vel.x = player->left ? -0.5f : 0.5f; + vel.y = 0.2f; + } +} + +unsigned int Entity::coolDown() +{ + return hitCooldown; +} + +void Entity::setCooldown(unsigned int c) +{ + hitCooldown = c; +} + +void Entity::handleHits(void) +{ + hitCooldown = fmax(static_cast<int>(hitCooldown - game::time::getDeltaTime()), 0); + hitDuration = fmax(hitDuration - game::time::getDeltaTime(), 0); + + if (!forcedMove) + return; + + // reduce knockback + if ((vel.x > 0.0005f) || (vel.x < -0.0005f)) + vel.x *= 0.6f; + else + forcedMove = false; +} + +void Entity::die(void) +{ + alive = false; + health = 0; + + /*if (xmle) { + xmle->SetAttribute("alive", false); + currentXMLDoc.SaveFile(currentXML.c_str(), false); + }*/ +} + +bool Entity::isAlive(void) const +{ + return alive; +} + +bool Entity::isHit(void) const +{ + return forcedMove; +} + +void Entity::moveTo(float dest_x) +{ + targetx = dest_x; +} + +Player::Player() : Entity() +{ + width = HLINES(10); + height = HLINES(16); + + type = PLAYERT; //set type to player + subtype = 0; + health = maxHealth = 100; + speed = 1; + canMove = true; + + tex = TextureIterator({"assets/player/playerk.png", + "assets/player/playerk1.png", + "assets/player/playerk2.png", + "assets/player/playerk3.png", + "assets/player/playerk4.png", + "assets/player/playerk5.png", + "assets/player/playerk6.png", + "assets/player/playerk7.png", + "assets/player/playerk8.png" + }); + + inv = new Inventory(PLAYER_INV_SIZE); + dim2 tmpDim = Texture::imageDim(tex.getTexturePath(0)); + width = HLINES(tmpDim.x/2); + height = HLINES(tmpDim.y/2); + + z = -2.0; +} + +Player::~Player() +{ + delete inv; + delete &tex; +} + +void Player::createFromXML(XMLElement *e, World *w=nullptr) +{ + (void)e; + (void)w; +} + +void Player::saveToXML(void) +{} + +NPC::NPC() : Entity() +{ + width = HLINES(10); + height = HLINES(16); + + type = NPCT; //sets type to npc + subtype = 0; + + health = maxHealth = 100; + + maxHealth = health = 100; + canMove = true; + + tex = TextureIterator({"assets/NPC.png"}); + inv = new Inventory(NPC_INV_SIZE); + + randDialog = randGet() % randomDialog.size(); + dialogIndex = 0; + dialogCount = 0; + + dim2 tmpDim = Texture::imageDim(tex.getTexturePath(0)); + width = HLINES(tmpDim.x/2); + height = HLINES(tmpDim.y/2); +} + +NPC::~NPC() +{ + delete inv; +} + +void NPC::createFromXML(XMLElement *e, World *w=nullptr) +{ + std::string npcname; + bool dialog; + unsigned int flooor; + + xmle = e; + (void)w; + + // spawn at coordinates if desired + E_LOAD_COORDS(100); + + // name override + if (!(npcname = e->StrAttribute("name")).empty()) + name = npcname; + + // dialog enabling + dialog = false; + if (e->QueryBoolAttribute("hasDialog", &dialog) == XML_NO_ERROR && dialog) + addAIFunc(false); + else + dialogIndex = 9999; + + // custom health value + E_LOAD_HEALTH; + + // movemenet + if (e->QueryBoolAttribute("canMove", &dialog) == XML_NO_ERROR) + canMove = dialog; + + // dialog index + if (e->QueryUnsignedAttribute("dindex", &flooor) == XML_NO_ERROR) + dialogIndex = flooor; +} + +void NPC::saveToXML(void) +{ + E_SAVE_HEALTH; + E_SAVE_COORDS; + xmle->SetAttribute("dindex", dialogIndex); +} + +Merchant::Merchant() : NPC() +{ + width = HLINES(10); + height = HLINES(16); + + type = MERCHT; //sets type to merchant + subtype = 0; + + health = maxHealth = 100; + + canMove = true; + + trade.reserve(100); + currTrade = 0; + + inside = nullptr; + + //tex = new Texturec(1,"assets/NPC.png"); + //inv = new Inventory(NPC_INV_SIZE); + //inv = new Inventory(1); + + //randDialog = rand() % RAND_DIALOG_COUNT - 1; + dialogIndex = 0; + + dim2 tmpDim = Texture::imageDim(tex.getTexturePath(0)); + width = HLINES(tmpDim.x/2); + height = HLINES(tmpDim.y/2); +} + +Merchant::~Merchant() +{ +} + +void Merchant::saveToXML(void){} + +Structures::Structures() : Entity() +{ + type = STRUCTURET; + canMove = false; + health = maxHealth = 1; +} + +Structures::~Structures() +{ +} + +extern std::string currentXMLRaw; + +void Structures::createFromXML(XMLElement *e, World *w) +{ + float spawnx; + + if (e->QueryBoolAttribute("alive", &alive) == XML_NO_ERROR && !alive) { + //die(); + return; + } + + inWorld = w; + inside = e->StrAttribute("inside"); + + // edge + if (!inside.empty()) { + insideWorld = loadWorldFromXMLNoTakeover(inside); + } + + textureLoc = e->StrAttribute("texture"); + + insideTex = Texture::loadTexture(e->StrAttribute("insideTexture")); + + spawn(static_cast<BUILD_SUB>(e->UnsignedAttribute("type")), + e->QueryFloatAttribute("spawnx", &spawnx) == XML_NO_ERROR ? spawnx : (randGet() % w->getTheWidth() / 2.0f), + 100); + + xmle = e; +} + +void Structures::saveToXML(void) +{ + xmle->SetAttribute("alive", alive); +} + +Object::Object() +{ + type = OBJECTT; +} + +Object::Object(std::string in, std::string pd) +{ + iname = in; + + pickupDialog = pd; + questObject = !pd.empty(); + + type = OBJECTT; + width = getItemWidth(in); + height = getItemHeight(in); + + tex = TextureIterator({getItemTexturePath(in)}); +} + +Object::~Object() +{ +} + +void Object::createFromXML(XMLElement *e, World *w=nullptr) +{ + (void)e; + (void)w; +} + +void Object::saveToXML(void) +{} + +void Object::reloadTexture(void) +{ + tex = TextureIterator({getItemTexturePath(iname)}); + width = getItemWidth(iname); + height = getItemHeight(iname); +} + +bool Entity::isNear(const Entity *e) { + return (e != nullptr) ? (pow(e->loc.x - loc.x, 2) + pow(e->loc.y - loc.y, 2) <= pow(HLINES(40), 2)) : false; +} + +void NPC::drawThingy(void) const +{ + if (dialogCount) { + const auto w = width / 3; + GLfloat tex_coord[] = { + 0, 0, 1, 0, 1, 1, + 1, 1, 0, 1, 0, 0 + }; + const GLfloat c[4] = { + loc.x + w, loc.y + height, loc.x + w * 2, loc.y + height + w + }; + GLfloat coords[] = { + c[0], c[1], z, c[2], c[1], z, c[2], c[3], z, + c[2], c[3], z, c[0], c[3], z, c[0], c[1], z + }; + + // TODO use texture made for this + static GLuint thingyColor = Texture::genColor(Color(236, 238, 15)); + + Render::worldShader.use(); + Render::worldShader.enable(); + + glBindTexture(GL_TEXTURE_2D, thingyColor); + + glVertexAttribPointer(Render::worldShader.coord, 3, GL_FLOAT, GL_FALSE, 0, coords); + glVertexAttribPointer(Render::worldShader.tex, 2, GL_FLOAT, GL_FALSE, 0, tex_coord); + glDrawArrays(GL_TRIANGLES, 0, 6); + + Render::worldShader.disable(); + Render::worldShader.unuse(); + } +} + +void Entity::draw(void) +{ + GLfloat tex_coord[] = {0.0, 0.0, + 1.0, 0.0, + 1.0, 1.0, + + 1.0, 1.0, + 0.0, 1.0, + 0.0, 0.0}; + + GLfloat tex_coordL[] = {1.0, 0.0, + 0.0, 0.0, + 0.0, 1.0, + + 0.0, 1.0, + 1.0, 1.0, + 1.0, 0.0}; + + GLfloat coords[] = {loc.x, loc.y, z, + loc.x + width, loc.y, z, + loc.x + width, loc.y + height, z, + + loc.x + width, loc.y + height, z, + loc.x, loc.y + height, z, + loc.x, loc.y, z}; + + + glActiveTexture(GL_TEXTURE0); + + if (!alive) + return; + + if (type == NPCT) { + NPCp(this)->drawThingy(); + + if (gender == MALE) + glColor3ub(255, 255, 255); + else if (gender == FEMALE) + glColor3ub(255, 105, 180); + } else if (type == MOBT) { + if (Mobp(this)->rider != nullptr) { + Mobp(this)->rider->loc.x = loc.x + width * 0.25f; + Mobp(this)->rider->loc.y = loc.y + height - HLINES(5); + Mobp(this)->rider->vel.y = .12; + Mobp(this)->rider->z = z + 0.01; + } + } + switch(type) { + case PLAYERT: + static int texState = 0; + if (speed && !(game::time::getTickCount() % ((2.0f/speed) < 1 ? 1 : (int)((float)2.0f/(float)speed)))) { + if (++texState == 9) + texState = 1; + glActiveTexture(GL_TEXTURE0); + tex(texState); + } + if (!ground) { + glActiveTexture(GL_TEXTURE0); + tex(0); + } else if (vel.x) { + glActiveTexture(GL_TEXTURE0); + tex(texState); + } else { + glActiveTexture(GL_TEXTURE0); + tex(0); + } + break; + case MOBT: + if (!Mobp(this)->bindTex()) + goto NOPE; + break; + case STRUCTURET: + /* fall through */ + default: + glActiveTexture(GL_TEXTURE0); + tex(0); + break; + } + + Render::worldShader.use(); + // make the entity hit flash red + if (maxHitDuration-hitDuration) { + float flashAmt = 1-(hitDuration/maxHitDuration); + glUniform4f(Render::worldShader.uniform[WU_tex_color], 1.0, flashAmt, flashAmt, 1.0); + } + + glUniform1i(Render::worldShader.uniform[WU_texture], 0); + Render::worldShader.enable(); + + glVertexAttribPointer(Render::worldShader.coord, 3, GL_FLOAT, GL_FALSE, 0, coords); + if (left) + glVertexAttribPointer(Render::worldShader.tex, 2, GL_FLOAT, GL_FALSE, 0 ,tex_coordL); + else + glVertexAttribPointer(Render::worldShader.tex, 2, GL_FLOAT, GL_FALSE, 0 ,tex_coord); + glDrawArrays(GL_TRIANGLES, 0, 6); + + glUniform4f(Render::worldShader.uniform[WU_tex_color], 1.0, 1.0, 1.0, 1.0); +NOPE: +if (near && type != MOBT) + ui::putStringCentered(loc.x+width/2,loc.y-ui::fontSize-game::HLINE/2,name); +if (health != maxHealth) { + + static GLuint frontH = Texture::genColor(Color(255,0,0)); + static GLuint backH = Texture::genColor(Color(150,0,0)); + glUniform1i(Render::worldShader.uniform[WU_texture], 0); + + GLfloat coord_back[] = { + loc.x, loc.y + height, z + 0.1f, + loc.x + width, loc.y + height, z + 0.1f, + loc.x + width, loc.y + height + game::HLINE * 2, z + 0.1f, + + loc.x + width, loc.y + height + game::HLINE * 2, z + 0.1f, + loc.x, loc.y + height + game::HLINE * 2, z + 0.1f, + loc.x, loc.y + height, z + 0.1f, + }; + + GLfloat coord_front[] = { + loc.x, loc.y + height, z, + loc.x + health / maxHealth * width, loc.y + height, z, + loc.x + health / maxHealth * width, loc.y + height + game::HLINE * 2, z, + + loc.x + health / maxHealth * width, loc.y + height + game::HLINE * 2, z, + loc.x, loc.y + height + game::HLINE * 2, z, + loc.x, loc.y + height, z, + }; + + glBindTexture(GL_TEXTURE_2D, backH); + GLfloat tex[] = { 0.0, 0.0, + 1.0, 0.0, + 1.0, 1.0, + + 1.0, 1.0, + 0.0, 1.0, + 0.0, 0.0, + }; + glVertexAttribPointer(Render::worldShader.coord, 3, GL_FLOAT, GL_FALSE, 0, coord_back); + glVertexAttribPointer(Render::worldShader.tex, 2, GL_FLOAT, GL_FALSE, 0, tex); + glDrawArrays(GL_TRIANGLES, 0, 6); + + glBindTexture(GL_TEXTURE_2D, frontH); + glVertexAttribPointer(Render::worldShader.coord, 3, GL_FLOAT, GL_FALSE, 0, coord_front); + glVertexAttribPointer(Render::worldShader.tex, 2, GL_FLOAT, GL_FALSE, 0, tex); + glDrawArrays(GL_TRIANGLES, 0, 6); +} + +Render::worldShader.disable(); +Render::worldShader.unuse(); +} + +/** + * Handles NPC movement, usually just random walking. + */ + +void NPC:: +wander(int timeRun) +{ + static int direction; + + if (forcedMove) + return; + + if (hitCooldown) + hitCooldown--; + + if (targetx != 0.9112001f) { + if (loc.x > targetx + HLINES(5)) + vel.x = HLINES(-0.018); + else if (loc.x < targetx - HLINES(5)) + vel.x = HLINES(0.018); + else { + targetx = 0.9112001f; + vel.x = 0; + } + } else if (ticksToUse == 0) { + ticksToUse = timeRun; + + vel.x = HLINES(0.008); + direction = (randGet() % 3 - 1); + + if (direction == 0) + ticksToUse *= 2; + + vel.x *= direction; + } + + if (vel.x < 0) + currentWorld->goWorldLeft(this); + + ticksToUse--; +} + +void NPC::addAIFunc(bool preload) +{ + if (preload) + aipreload.push_back(this); + else + ++dialogCount; +} + +extern int commonAIFunc(NPC *speaker); + +void NPC::interact() { //have the npc's interact back to the player + std::thread([this]{ + std::vector<XMLElement *> dopt; + XMLDocument *xml; + XMLElement *exml,*oxml; + + static unsigned int oldidx = 9999; + const char *ptr; + std::string nname; + unsigned int idx; + bool stop; + float tgt = 0.12345678f; + bool pmove = true, advance = false; + + loc.y += 5; + + // freeze the npc, face the player + canMove = false; + left = (player->loc.x < loc.x); + right = !left; + + // if there's actual scripted stuff to do, do it + if (dialogCount && dialogIndex != 9999) { + // load the XML file and find the dialog tags + if (outnabout == 0) { + xml = ¤tXMLDoc; + } else if (outnabout < 0) { + xml = new XMLDocument(); + xml->LoadFile((xmlFolder + currentWorld->getToLeft()).c_str()); + } else { + xml = new XMLDocument(); + xml->LoadFile((xmlFolder + currentWorld->getToRight()).c_str()); + } + +COMMONAIFUNC: + idx = 0; + stop = false; + exml = xml->FirstChildElement("Dialog"); + + // search for the dialog block associated with this npc + while (exml->StrAttribute("name") != name) + exml = exml->NextSiblingElement(); + + // search for the desired text block + exml = exml->FirstChildElement(); + do { + if (std::string("text") == exml->Name() && exml->UnsignedAttribute("id") == (unsigned)dialogIndex) + break; + } while ((exml = exml->NextSiblingElement())); + + // handle quest tags + if ((oxml = exml->FirstChildElement("quest"))) { + std::string qname; + + // iterate through all quest tags + do { + // assign quest + if (!(qname = oxml->StrAttribute("assign")).empty()) + player->qh.assign(qname, oxml->StrAttribute("desc"), (oxml->GetText() == nullptr) ? "" : oxml->GetText()); + + // check / finish quest + else if (!(qname = oxml->StrAttribute("check")).empty()) { + if (player->qh.hasQuest(qname) && player->qh.finish(qname)) { + // QuestHandler::finish() did all the work.. + break; + } else { + // run error dialog + oldidx = dialogIndex; + dialogIndex = oxml->UnsignedAttribute("fail"); + goto COMMONAIFUNC; + } + } + } while((oxml = oxml->NextSiblingElement("quest"))); + } + + // handle give tags + if ((oxml = exml->FirstChildElement("give"))) { + do player->inv->addItem(oxml->Attribute("id"), oxml->UnsignedAttribute("count")); + while ((oxml = oxml->NextSiblingElement("give"))); + } + + // handle take tags + if ((oxml = exml->FirstChildElement("take"))) { + do player->inv->takeItem(oxml->Attribute("id"), oxml->UnsignedAttribute("count")); + while ((oxml = oxml->NextSiblingElement())); + } + + // handle movement directs + if ((oxml = exml->FirstChildElement("gotox"))) { + moveTo((tgt = std::stoi(oxml->GetText()))); + if (oxml->QueryBoolAttribute("playerMove", &pmove) != XML_NO_ERROR) + pmove = true; + if (oxml->QueryBoolAttribute("advance", &advance) != XML_NO_ERROR) + advance = false; + } + + // handle attribute setting + if ((oxml = exml->FirstChildElement("set"))) { + do game::setValue(oxml->StrAttribute("id"), oxml->StrAttribute("value")); + while ((oxml = oxml->NextSiblingElement())); + game::briceUpdate(); + } + + // asdlfkj + + auto txml = exml->FirstChildElement("content"); + if (txml == nullptr) + goto OTHERSTUFF; + + ptr = txml->GetText() - 1; + while (*++ptr && isspace(*ptr)); + + // handle dialog options + if ((oxml = exml->FirstChildElement("option"))) { + std::string optstr; + + // convert option strings to a colon-separated format + do { + // append the next option + optstr.append(std::string(":") + oxml->Attribute("text")); + + // save the associated XMLElement + dopt.push_back(oxml); + } while ((oxml = oxml->NextSiblingElement())); + + // run the dialog stuff + ui::dialogBox(name, optstr, false, ptr); + ui::waitForDialog(); + + if (ui::dialogOptChosen) + exml = dopt[ui::dialogOptChosen - 1]; + + dopt.clear(); + } + + // optionless dialog + else { + ui::dialogBox(name, "", false, ptr); + ui::waitForDialog(); + } + +OTHERSTUFF: + + // trigger other npcs if desired + if (!(nname = exml->StrAttribute("call")).empty()) { + NPC *n = dynamic_cast<NPC *>(*std::find_if(std::begin(currentWorld->entity), std::end(currentWorld->entity), [nname](Entity *e) { + return (e->type == NPCT && e->name == nname); + })); + + if (exml->QueryUnsignedAttribute("callid", &idx) == XML_NO_ERROR) { + n->dialogIndex = idx; + n->addAIFunc(false); + } + } + + if (tgt != 0.12345678f) { + stop = canMove; + canMove = true; + while (targetx != 0.9112001f) { + if (!pmove) + player->speed = 0; + } + if (!pmove) { + pmove = true; + player->speed = 1; + } + canMove = stop; + } + + // handle potential following dialogs + if ((idx = exml->UnsignedAttribute("nextid"))) { + dialogIndex = idx; + + // stop talking + if (exml->QueryBoolAttribute("stop", &stop) == XML_NO_ERROR && stop) { + dialogIndex = 9999; + dialogCount--; + } + + // pause, allow player to click npc to continue + else if (exml->QueryBoolAttribute("pause", &stop) == XML_NO_ERROR && stop) { + //return 1; + } + + // instantly continue + else { + goto COMMONAIFUNC; + } + } + + // advance if desired + else if (advance) { + goto COMMONAIFUNC; + } + + // stop talking + else { + // error text? + if (oldidx != 9999) { + dialogIndex = oldidx; + oldidx = 9999; + } else { + dialogIndex = 9999; + dialogCount--; + } + } + } else { + ui::dialogBox(name, "", false, randomDialog[randDialog]); + } + + ui::waitForDialog(); + canMove = true; + }).detach(); +} + +void Merchant::wander(int timeRun) { + static int direction; + + if (forcedMove) + return; + + if (ticksToUse == 0) { + ticksToUse = timeRun; + + vel.x = HLINES(0.008); + direction = (randGet() % 3 - 1); + + if (direction == 0) + ticksToUse *= 2; + + vel.x *= direction; + } + + if (vel.x < 0) + currentWorld->goWorldLeft(this); + if (inside != nullptr) { + loc.y = inside->loc.y + HLINES(2); + vel.y = GRAVITY_CONSTANT * 5; + if (loc.x <= inside->loc.x + HLINES(5)) + loc.x = inside->loc.x + HLINES(5); + else if (loc.x + width >= inside->loc.x + inside->width - HLINES(5)) + loc.x = inside->loc.x + inside->width - width - HLINES(5); + } + ticksToUse--; +} + +void Merchant::interact() { + std::thread([this]{ + ui::merchantBox(name.c_str(), trade[currTrade], ":Accept:Good-Bye", false, toSay->c_str()); + ui::waitForDialog(); + + // handle normal dialog options + switch (ui::dialogOptChosen) { + // Accept + case 1: + if (!(player->inv->takeItem(trade[currTrade].item[1], trade[currTrade].quantity[1]))) { + player->inv->addItem(trade[currTrade].item[0],trade[currTrade].quantity[0]); + toSay = &text[1]; + interact(); + } else { + toSay = &text[2]; + interact(); + } + break; + + // Good-bye + case 2: + break; + + default: + break; + } + + // handle merchant-specific dialog options + switch (ui::merchOptChosen) { + // left arrow + case 1: + if (currTrade) + currTrade--; + ui::dontTypeOut(); + interact(); // TODO should we nest like this? + break; + + // right arrow + case 2: + if (currTrade < trade.size() - 1) + currTrade++; + ui::dontTypeOut(); + interact(); + break; + + default: + break; + toSay = &text[0]; + } + }).detach(); +} + +void Object::interact(void) { + std::thread([this]{ + if(questObject && alive){ + ui::dialogBox(player->name, ":Yes:No", false, pickupDialog); + ui::waitForDialog(); + if (ui::dialogOptChosen == 1) { + player->inv->addItem(iname, 1); + alive = false; + } + }else{ + alive = false; + player->inv->addItem(iname, 1); + } + }).detach(); +} + +bool Entity::isInside(vec2 coord) const { + return coord.x >= loc.x && + coord.x <= loc.x + width && + coord.y >= loc.y && + coord.y <= loc.y + height; +} + +/* + * This spawns the structures + * + * Structures::spawn This allows us to spawn buildings and large amounts of entities with it. + * Passed are the type and x and y coordinates. These set the x and y coords + * of the structure being spawned, the type pass just determines what rules to follow + * when spawing the structure and entities. In theory this function can also spawn + * void spawn points for large amounts of entities. This would allow for the spawn + * point to have non-normal traits so it could be invisible or invincible... +*/ + +unsigned int Structures::spawn(BUILD_SUB sub, float x, float y) { + loc.x = x; + loc.y = y; + type = STRUCTURET; + + alive = true; + canMove = false; + + bsubtype = sub; + dim2 dim; + + z = 1.0; + /* + * tempN is the amount of entities that will be spawned in the village. Currently the village + * will spawn bewteen 2 and 7 villagers for the starting hut. + */ + + //unsigned int tempN = (randGet() % 5 + 2); + + if (textureLoc.empty()) + textureLoc = inWorld->getSTextureLocation(sub); + + switch(sub) { + case STALL_MARKET: + tex = TextureIterator({ textureLoc }); + dim = Texture::imageDim(textureLoc); + width = HLINES(dim.x/2); + height = HLINES(dim.y/2); + break; + default: + tex = TextureIterator({ textureLoc }); + dim = Texture::imageDim(textureLoc); + width = HLINES(dim.x/2); + height = HLINES(dim.y/2); + inv = NULL; + break; + } + + return 0; +} + +/*Particles::Particles(const Structures *&s, vec2 vell, Color c, float d, ) +{ + +}*/ + +Particles::Particles(float x, float y, float w, float h, float vx, float vy, Color c, float d) +{ + loc = vec2 {x, y}; + vel = vec2 {vx, vy}; + width = w; + height = h; + color = c; + duration = d; + gravity = true; + fountain = false; + behind = false; + bounce = false; + index = Texture::getIndex(c); + zOffset = ((rand()%20)-10)/1000.0f; + stu = nullptr; +} + +void Particles::draw(GLfloat*& p) const +{ + vec2 tc = vec2(0.25f * index.x, 0.125f * (8.0f - index.y)); + + float z = (behind ? 2.0f : 0.9f) + zOffset; + + // lower left + *(p++) = loc.x; + *(p++) = loc.y; + *(p++) = z; + + *(p++) = tc.x; + *(p++) = tc.y; + + // lower right + *(p++) = loc.x + width; + *(p++) = loc.y; + *(p++) = z; + + *(p++) = tc.x; + *(p++) = tc.y; + + // upper right + *(p++) = loc.x + width; + *(p++) = loc.y + height; + *(p++) = z; + + *(p++) = tc.x; + *(p++) = tc.y; + + // upper right + *(p++) = loc.x + width; + *(p++) = loc.y + height; + *(p++) = z; + + *(p++) = tc.x; + *(p++) = tc.y; + + // upper left + *(p++) = loc.x; + *(p++) = loc.y + height; + *(p++) = z; + + *(p++) = tc.x; + *(p++) = tc.y; + + // lower left + *(p++) = loc.x; + *(p++) = loc.y; + *(p++) = z; + + *(p++) = tc.x; + *(p++) = tc.y; +} + +void Particles::update(float _gravity, float ground_y) +{ + auto delta = game::time::getDeltaTime(); + + // handle ground collision + if (loc.y < ground_y) { + loc.y = ground_y; + + // handle bounce + if (bounce) { + vel.y *= -0.2f; + vel.x /= 4.0f; + } else { + vel = 0.0f; + canMove = false; + } + } + + // handle gravity + else if (gravity && vel.y > -1.0f) { + vel.y -= _gravity * delta; + } + + // handle lifetime + duration -= delta; +} + +bool Particles::timeUp(void) +{ + return !(duration > 0); +} + +void Player::save(void) { + std::string data; + std::ofstream out (xmlFolder + ".main.dat", std::ios::out | std::ios::binary); + std::cout<<"Saving player data..."<<std::endl; + data.append(std::to_string((int)loc.x) + "\n"); + data.append(std::to_string((int)loc.y) + "\n"); + data.append(std::to_string((int)health) + "\n"); + data.append(std::to_string((int)maxHealth) + "\n"); + data.append(std::to_string((int)game::time::getTickCount()) + "\n"); + + data.append("qwer\n"); + data.append(std::to_string((int)inv->Items.size()) + "\n"); + for(auto &i : inv->Items) { + if(i.second) + data.append(std::to_string(uint(i.second)) + "\n" + i.first->name + "\n"); + } + data.append("qwer\n"); + + data.append(std::string(currentXML.data() + 4) + "\n"); + + data.append("dOnE\0"); + out.write(data.data(),data.size()); + out.close(); +} + +void Player::sspawn(float x,float y) { + unsigned int i; + int count; + std::ifstream in (xmlFolder + ".main.dat", std::ios::in | std::ios::binary); + spawn(x,y); + + if (in.good()) { + std::istringstream data; + std::string ddata; + std::streampos len; + + in.seekg(0,std::ios::end); + len = in.tellg(); + in.seekg(0,std::ios::beg); + + std::vector<char> buf (len,'\0'); + in.read(buf.data(),buf.size()); + + data.rdbuf()->pubsetbuf(buf.data(),buf.size()); + + std::getline(data,ddata); + loc.x = std::stoi(ddata); + std::getline(data,ddata); + loc.y = std::stoi(ddata); + std::getline(data,ddata); + health = std::stoi(ddata); + std::getline(data,ddata); + maxHealth = std::stoi(ddata); + std::getline(data,ddata); + game::time::tick(std::stoi(ddata)); + + std::getline(data,ddata); + std::getline(data,ddata); + + for (i = std::stoi(ddata);i;i--) { + std::getline(data,ddata); + if (ddata == "qwer") + break; + count = std::stoi(ddata); + + std::getline(data,ddata); + if (ddata == "qwer") + break; + inv->addItem(ddata, (uint)count); + } + + std::getline(data,ddata); + currentWorld = loadWorldFromXMLNoSave(ddata); + + in.close(); + } +} |