aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/entities.cpp16
-rw-r--r--src/inventory.cpp73
-rw-r--r--src/ui.cpp131
-rw-r--r--src/ui_action.cpp146
-rw-r--r--src/world.cpp1296
5 files changed, 893 insertions, 769 deletions
diff --git a/src/entities.cpp b/src/entities.cpp
index c52ff4e..96fe0e6 100644
--- a/src/entities.cpp
+++ b/src/entities.cpp
@@ -114,7 +114,10 @@ void Entity::spawn(float x, float y) { //spawns the entity you pass to it based
}
name = new char[32];
- getRandomName(this);
+ if (type == MOBT)
+ name[0] = '\0';
+ else
+ getRandomName(this);
followee = NULL;
}
@@ -382,14 +385,7 @@ void Entity::draw(void) { //draws the entities
}
break;
case STRUCTURET:
- for(auto &strt : currentWorld->build) {
- if (this == strt) {
- glActiveTexture(GL_TEXTURE0);
- tex->bind(0);
- break;
- }
- }
- break;
+ /* fall through */
default:
glActiveTexture(GL_TEXTURE0);
tex->bind(0);
@@ -414,7 +410,7 @@ NOPE:
glDisable(GL_TEXTURE_2D);
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
- if (near)
+ if (near && type != MOBT)
ui::putStringCentered(loc.x+width/2,loc.y-ui::fontSize-HLINE/2,name);
if (health != maxHealth) {
glColor3ub(150,0,0); glRectf(loc.x, loc.y + height, loc.x + width, loc.y + height + HLINE * 2);
diff --git a/src/inventory.cpp b/src/inventory.cpp
index 224ee12..c6b28d9 100644
--- a/src/inventory.cpp
+++ b/src/inventory.cpp
@@ -440,32 +440,22 @@ void Inventory::draw(void) {
a++;
}
C("Done drawing standard inv");
- }else if (invHover) {
+ } else if (invHover) {
static unsigned int highlight = 0;
static unsigned int thing = 0;
- std::cout<<"Inventory2???"<<std::endl;
-
if (!mouseSel) {
+ // setup?
mouseStart.x = ui::mouse.x - offset.x;
- std::cout << "Setting highlight" << std::endl;
highlight = sel;
- std::cout << "Setting thing" << std::endl;
thing = sel;
- std::cout << "Setting mouseSel" << std::endl;
- mouseSel=true;
- std::cout << "Done" << std::endl;
- }else{
- std::cout << "Is mousex greater than the start" << std::endl;
- if ((ui::mouse.x - offset.x) >= mouseStart.x) {
- std::cout << "Thing" << std::endl;
+ mouseSel = true;
+ } else {
+ if((ui::mouse.x - offset.x) >= mouseStart.x){
thing = (ui::mouse.x - offset.x - mouseStart.x)/80;
- std::cout << "Highlight" << std::endl;
highlight=sel+thing;
- std::cout << "Highlight Check" << std::endl;
- if (highlight>numSlot-1)highlight=numSlot-1;
- std::cout << "Left Click" << std::endl;
- if (SDL_GetMouseState(NULL, NULL) & SDL_BUTTON(SDL_BUTTON_LEFT)) {
+ if(highlight>numSlot-1)highlight=numSlot-1;
+ if(SDL_GetMouseState(NULL, NULL) & SDL_BUTTON(SDL_BUTTON_LEFT)){
sel = highlight;
mouseSel=false;
invHover=false;
@@ -474,9 +464,11 @@ void Inventory::draw(void) {
}
if ((ui::mouse.x - offset.x) < mouseStart.x) {
thing = (mouseStart.x - (ui::mouse.x - offset.x))/80;
- if ((int)sel-(int)thing<0)highlight=0;
- else highlight=sel-thing;
- if (SDL_GetMouseState(NULL, NULL) & SDL_BUTTON(SDL_BUTTON_LEFT)) {
+ if ((int)sel - (int)thing < 0)
+ highlight = 0;
+ else
+ highlight = sel - thing;
+ if(SDL_GetMouseState(NULL, NULL) & SDL_BUTTON(SDL_BUTTON_LEFT)){
sel = highlight;
mouseSel=false;
invHover=false;
@@ -484,17 +476,15 @@ void Inventory::draw(void) {
}
}
}
- std::cout << "Rays" << std::endl;
- for(auto &r : iray) {
- std::cout << "Setting angle" << std::endl;
- angle=180-(angleB*a) - angleB/2.0f;
- std::cout << "Currcourd" << std::endl;
+
+ a = 0;
+ for (auto &r : iray) {
+ angle = 180 - (angleB * a) - angleB / 2.0f;
curCoord[a].x += float(range) * cos(angle*PI/180);
curCoord[a].y += float(range) * sin(angle*PI/180);
- std::cout << "Ray.end" << std::endl;
r.end = curCoord[a];
- std::cout << "Draw" << std::endl;
+ // square drawing
glColor4f(0.0f, 0.0f, 0.0f, a == highlight ? 0.5f : 0.1f);
glBegin(GL_QUADS);
glVertex2i(r.end.x-(itemWide/2), r.end.y-(itemWide/2));
@@ -503,18 +493,16 @@ void Inventory::draw(void) {
glVertex2i(r.end.x-(itemWide/2), r.end.y+(itemWide/2));
glEnd();
- std::cout << "Draw items," << a << std::endl;
- if (!items.empty() && a < numSlot && items[a].count) {
- std::cout << "drawing" << std::endl;
+ if (a < items.size() && items[a].count) {
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, itemtex[items[a].id]);
- glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+ glColor4f(1.0f, 1.0f, 1.0f, a == highlight ? 0.8f : 0.2f);
glBegin(GL_QUADS);
- if (itemMap[items[a].id]->height > itemMap[items[a].id]->width) {
- glTexCoord2i(0,1);glVertex2i(r.end.x-((itemWide/2)*((float)itemMap[items[a].id]->width/(float)itemMap[items[a].id]->height)), r.end.y-(itemWide/2));
- glTexCoord2i(1,1);glVertex2i(r.end.x+((itemWide/2)*((float)itemMap[items[a].id]->width/(float)itemMap[items[a].id]->height)), r.end.y-(itemWide/2));
- glTexCoord2i(1,0);glVertex2i(r.end.x+((itemWide/2)*((float)itemMap[items[a].id]->width/(float)itemMap[items[a].id]->height)), r.end.y+(itemWide/2));
- glTexCoord2i(0,0);glVertex2i(r.end.x-((itemWide/2)*((float)itemMap[items[a].id]->width/(float)itemMap[items[a].id]->height)), r.end.y+(itemWide/2));
+ if(itemMap[items[a].id]->height > itemMap[items[a].id]->width){
+ glTexCoord2i(0,1);glVertex2i(r.end.x-((itemWide/2)*((float)itemMap[items[a].id]->width/(float)itemMap[items[a].id]->height)),r.end.y-(itemWide/2));
+ glTexCoord2i(1,1);glVertex2i(r.end.x+((itemWide/2)*((float)itemMap[items[a].id]->width/(float)itemMap[items[a].id]->height)),r.end.y-(itemWide/2));
+ glTexCoord2i(1,0);glVertex2i(r.end.x+((itemWide/2)*((float)itemMap[items[a].id]->width/(float)itemMap[items[a].id]->height)),r.end.y+(itemWide/2));
+ glTexCoord2i(0,0);glVertex2i(r.end.x-((itemWide/2)*((float)itemMap[items[a].id]->width/(float)itemMap[items[a].id]->height)),r.end.y+(itemWide/2));
}else{
glTexCoord2i(0,1);glVertex2i(r.end.x-(itemWide/2),r.end.y-(itemWide/2)*((float)itemMap[items[a].id]->height/(float)itemMap[items[a].id]->width));
glTexCoord2i(1,1);glVertex2i(r.end.x+(itemWide/2),r.end.y-(itemWide/2)*((float)itemMap[items[a].id]->height/(float)itemMap[items[a].id]->width));
@@ -523,15 +511,16 @@ void Inventory::draw(void) {
}
glEnd();
glDisable(GL_TEXTURE_2D);
-
- if (highlight == a) {
- std::cout << "Shitting" << std::endl;
- std::cout << itemMap[items[a].id]->name << std::endl;
- ui::putStringCentered(player->loc.x+player->width/2, player->loc.y + range*.75,itemMap[items[a].id]->name);
- }
}
a++;
}
+
+ if (highlight < items.size()) {
+ ui::putStringCentered(player->loc.x + player->width / 2,
+ player->loc.y + range * 0.75f,
+ itemMap[items[highlight].id]->name.c_str()
+ );
+ }
}
if (!items.empty() && items.size() > sel && items[sel].count)
itemDraw(player,items[sel].id);
diff --git a/src/ui.cpp b/src/ui.cpp
index bcac044..59ea102 100644
--- a/src/ui.cpp
+++ b/src/ui.cpp
@@ -615,11 +615,30 @@ namespace ui {
pageTexReady = true;
}
- void draw(void) {
+ void drawBox(vec2 c1, vec2 c2) {
+ // draw black body
+ glColor3ub(0, 0, 0);
+ glRectf(c1.x, c1.y, c2.x, c2.y);
+
+ // draw white border
+ glColor3ub(255, 255, 255);
+ glBegin(GL_LINE_STRIP);
+ glVertex2i(c1.x , c1.y);
+ glVertex2i(c2.x + 1, c1.y);
+ glVertex2i(c2.x + 1, c2.y);
+ glVertex2i(c1.x - 1, c2.y);
+ glVertex2i(c1.x , c1.y);
+ glEnd();
+ }
+
+ void draw(void){
unsigned char i;
float x,y,tmp;
std::string rtext;
+ // will return if not toggled
+ action::draw(vec2 {player->loc.x + player->width / 2, player->loc.y + player->height + HLINE});
+
if (pageTexReady) {
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, pageTex);
@@ -654,38 +673,24 @@ namespace ui {
x=offset.x-SCREEN_WIDTH/6;
y=(offset.y+SCREEN_HEIGHT/2)-HLINE*8;
- // draw the box border
- glColor3ub(255,255,255);
- glBegin(GL_LINE_STRIP);
- glVertex2f(x-1 ,y+1);
- glVertex2f(x+1+(SCREEN_WIDTH/3),y+1);
- glVertex2f(x+1+(SCREEN_WIDTH/3),y-1-SCREEN_HEIGHT*.6);
- glVertex2f(x-1,y-1-SCREEN_HEIGHT*.6);
- glVertex2f(x - 1,y+1);
- glEnd();
-
- // draw the box
- glColor3ub(0,0,0);
- glRectf(x,y,x+SCREEN_WIDTH/3,y-SCREEN_HEIGHT*.6);
+ drawBox(vec2 {x, y}, vec2 {x + SCREEN_WIDTH / 3, y - SCREEN_HEIGHT * 0.6f});
// draw typeOut'd text
putString(x + HLINE, y - fontSize - HLINE, (rtext = typeOut(dialogBoxText)));
- std::string itemString1 = std::to_string(merchTrade.quantity[0]);
- itemString1 += "x";
-
- std::string itemString2 = std::to_string(merchTrade.quantity[1]);
- itemString2 += "x";
+ std::string itemString1 = std::to_string(merchTrade.quantity[0]) + "x",
+ itemString2 = std::to_string(merchTrade.quantity[1]) + "x";
- putStringCentered(offset.x - (SCREEN_WIDTH / 10) + 20, offset.y + (SCREEN_HEIGHT / 5) + 40 + (fontSize*2), itemString1.c_str());
- putStringCentered(offset.x - (SCREEN_WIDTH / 10) + 20, offset.y + (SCREEN_HEIGHT / 5) + 40 + fontSize, merchTrade.item[0].c_str());
+ vec2 merchBase = {offset.x, offset.y + SCREEN_HEIGHT / 5};
- putStringCentered(offset.x + (SCREEN_WIDTH / 10) - 20, offset.y + (SCREEN_HEIGHT / 5) + 40 + (fontSize*2), itemString2.c_str());
- putStringCentered(offset.x + (SCREEN_WIDTH / 10) - 20, offset.y + (SCREEN_HEIGHT / 5) + 40 + fontSize, merchTrade.item[1].c_str());
-
- putStringCentered(offset.x,offset.y + (SCREEN_HEIGHT / 5) + 60, "for");
+ putStringCentered(merchBase.x + SCREEN_WIDTH / 10 - 20, merchBase.y + 40 + fontSize * 2, itemString1.c_str());
+ putStringCentered(merchBase.x + SCREEN_WIDTH / 10 - 20, merchBase.y + 40 + fontSize , merchTrade.item[0].c_str());
+ putStringCentered(merchBase.x - SCREEN_WIDTH / 10 , merchBase.y + 40 + fontSize * 2, itemString2.c_str());
+ putStringCentered(merchBase.x - SCREEN_WIDTH / 10 , merchBase.y + 40 + fontSize , merchTrade.item[1].c_str());
+ putStringCentered(offset.x, merchBase.y + 60, "for");
glEnable(GL_TEXTURE_2D);
+
glBindTexture(GL_TEXTURE_2D, getItemTexture(merchTrade.item[0]));
glBegin(GL_QUADS);
glTexCoord2d(0,1);glVertex2f(offset.x - (SCREEN_WIDTH / 10) ,offset.y + (SCREEN_HEIGHT/5));
@@ -701,6 +706,7 @@ namespace ui {
glTexCoord2d(1,0);glVertex2f(offset.x + (SCREEN_WIDTH / 10) ,offset.y + (SCREEN_HEIGHT/5) + 40);
glTexCoord2d(0,0);glVertex2f(offset.x + (SCREEN_WIDTH / 10) - 40,offset.y + (SCREEN_HEIGHT/5) + 40);
glEnd();
+
glDisable(GL_TEXTURE_2D);
merchArrowLoc[0].x = offset.x - (SCREEN_WIDTH / 8.5) - 16;
@@ -748,24 +754,12 @@ namespace ui {
}
setFontColor(255, 255, 255);
- }else{ //normal dialog box
+ } else { //normal dialog box
- x=offset.x-SCREEN_WIDTH/2+HLINE*8;
- y=(offset.y+SCREEN_HEIGHT/2)-HLINE*8;
-
- // draw white border
- glColor3ub(255, 255, 255);
+ x = offset.x - SCREEN_WIDTH / 2 + HLINE * 8;
+ y = offset.y + SCREEN_HEIGHT / 2 - HLINE * 8;
- glBegin(GL_LINE_STRIP);
- glVertex2i(x-1 ,y+1);
- glVertex2i(x+1+SCREEN_WIDTH-HLINE*16,y+1);
- glVertex2i(x+1+SCREEN_WIDTH-HLINE*16,y-1-SCREEN_HEIGHT/4);
- glVertex2i(x-1 ,y-1-SCREEN_HEIGHT/4);
- glVertex2i(x-1 ,y+1);
- glEnd();
-
- glColor3ub(0,0,0);
- glRectf(x,y,x+SCREEN_WIDTH-HLINE*16,y-SCREEN_HEIGHT/4);
+ drawBox(vec2 {x, y}, vec2 {x + SCREEN_WIDTH - HLINE * 16, y - SCREEN_HEIGHT / 4});
rtext = typeOut(dialogBoxText);
@@ -956,16 +950,22 @@ EXIT:
// mouse clicks
case SDL_MOUSEBUTTONDOWN:
- // right click advances dialog
- if ((e.button.button & SDL_BUTTON_RIGHT) && (dialogBoxExists | pageTexReady))
- dialogAdvance();
+ // run actions?
+ if ((action::make = e.button.button & SDL_BUTTON_RIGHT))
+ /*player->inv->invHover =*/ edown = false;
- // left click uses item
- if ((e.button.button & SDL_BUTTON_LEFT) && !dialogBoxExists)
- player->inv->usingi = true;
+ if (dialogBoxExists || pageTexReady) {
+ // right click advances dialog
+ if ((e.button.button & SDL_BUTTON_RIGHT))
+ dialogAdvance();
+ } else {
+ // left click uses item
+ if (e.button.button & SDL_BUTTON_LEFT)
+ player->inv->usingi = true;
+ }
- if (mouse.x > player->loc.x && mouse.x < player->loc.x + player->width &&
- mouse.y > player->loc.y && mouse.y < player->loc.y + player->height) {
+ if(mouse.x > player->loc.x && mouse.x < player->loc.x + player->width &&
+ mouse.y > player->loc.y && mouse.y < player->loc.y + player->height) {
player->vel.y = .05;
fr = mouse;
ig = player;
@@ -1054,8 +1054,6 @@ EXIT:
}
}
break;
- case SDLK_s:
- break;
case SDLK_w:
if (inBattle) {
tmp = currentWorld;
@@ -1067,31 +1065,42 @@ EXIT:
break;
case SDLK_LSHIFT:
if (debug) {
- Mix_PlayChannel(1,sanic,-1);
+ Mix_PlayChannel(1, sanic, -1);
player->speed = 4.0f;
- }else
+ } else
player->speed = 2.0f;
break;
case SDLK_LCTRL:
player->speed = .5;
break;
case SDLK_e:
- edown=true;
+ edown = true;
+
+ // start hover counter?
if (!heyOhLetsGo) {
heyOhLetsGo = loops;
player->inv->mouseSel = false;
}
- if (loops - heyOhLetsGo >= 2 && !(player->inv->invOpen) && !(player->inv->selected))
- player->inv->invHover=true;
+
+ // run hover thing
+ if (loops - heyOhLetsGo >= 2 && !(player->inv->invOpen) && !(player->inv->selected)) {
+ player->inv->invHover = true;
+
+ // enable action ui
+ action::enable();
+ }
+
break;
default:
break;
}
+
+ // handle world switches?
if (tmp != currentWorld) {
- std::swap(tmp,currentWorld);
+ std::swap(tmp, currentWorld);
toggleBlackFast();
waitForCover();
- std::swap(tmp,currentWorld);
+ std::swap(tmp, currentWorld);
toggleBlackFast();
}
}
@@ -1149,6 +1158,10 @@ EXIT:
else player->inv->selected = false;
player->inv->mouseSel = false;
}
+
+ // disable action ui
+ action::disable();
+
heyOhLetsGo = 0;
break;
case SDLK_l:
@@ -1165,7 +1178,7 @@ EXIT:
else {
currentWorld->addStructure(FIRE_PIT, player->loc.x, player->loc.y, "", "");
currentWorld->addLight({player->loc.x + SCREEN_WIDTH/2, player->loc.y},{1.0f,1.0f,1.0f});
- currentWorld->getLastLight()->follow(currentWorld->build.back());
+ //currentWorld->getLastLight()->follow(currentWorld->build.back());
currentWorld->getLastLight()->makeFlame();
}
break;
diff --git a/src/ui_action.cpp b/src/ui_action.cpp
new file mode 100644
index 0000000..a7bb36b
--- /dev/null
+++ b/src/ui_action.cpp
@@ -0,0 +1,146 @@
+#include <ui_action.hpp>
+
+#define ACTION_PROLOUGE { actioning = true; }
+#define ACTION_EPILOUGE { actioning = false; actionHover = 0; }
+
+extern World *currentWorld;
+extern Player *player;
+extern bool inBattle;
+
+static std::vector<std::pair<std::string, vec3>> actionText = {
+ {"Attack", vec3 {0, 0, 0}},
+ {"Action", vec3 {0, 0, 0}},
+ {"Umm" , vec3 {0, 0, 0}}
+};
+
+void actionAttack(void);
+void actionAction(void);
+
+static std::vector<void (*)(void)> actionFunc = {
+ actionAttack,
+ actionAction,
+ nullptr,
+};
+
+static bool actionToggle = false, actioning = false;
+static unsigned int actionHover = 0;
+static Entity *nearEntity = nullptr, *lastEntity = nullptr;
+
+namespace ui {
+ namespace action {
+ bool make = false;
+
+ // enables action ui
+ void enable(void) {
+ actionToggle = true;
+ }
+
+ // disables action ui
+ void disable(void) {
+ actionToggle = false;
+
+ if (lastEntity != nullptr)
+ lastEntity->canMove = true;
+ }
+
+ // draws the action ui
+ void draw(vec2 loc) {
+ unsigned int i = 1;
+ float y = loc.y;
+
+ if (!actionToggle)
+ return;
+
+ nearEntity = currentWorld->getNearInteractable(*player);
+
+ if (nearEntity == nullptr) {
+ if (lastEntity != nullptr) {
+ lastEntity->canMove = true;
+ lastEntity = nullptr;
+ }
+ return;
+ } else if (nearEntity != lastEntity) {
+ if (lastEntity != nullptr)
+ lastEntity->canMove = true;
+ lastEntity = nearEntity;
+ }
+
+ if (make) {
+ while(actioning);
+
+ if (!actionHover) {
+ make = false;
+ return;
+ }
+
+ if (actionFunc[actionHover - 1] != nullptr)
+ std::thread(actionFunc[actionHover - 1]).detach();
+
+ actionHover = 0;
+ } else {
+ nearEntity->canMove = false;
+ ui::drawBox(vec2 {loc.x - HLINES(11), loc.y}, vec2 {loc.x + HLINES(12), loc.y + actionText.size() * HLINES(8)});
+
+ for (auto &s : actionText) {
+ s.second.z = ui::putStringCentered((s.second.x = loc.x), (s.second.y = (y += fontSize * 1.15f)), s.first) / 2;
+
+ if (ui::mouse.x > s.second.x - s.second.z && ui::mouse.x < s.second.x + s.second.z &&
+ ui::mouse.y > s.second.y && ui::mouse.y < s.second.y + ui::fontSize) {
+ actionHover = i;
+ ui::setFontColor(255, 100, 100, 255);
+ ui::putStringCentered(s.second.x, s.second.y, s.first);
+ ui::setFontColor(255, 255, 255, 255);
+ }
+ i++;
+ }
+
+ ui::putStringCentered(loc.x, y + fontSize * 1.2f, nearEntity->name);
+ }
+
+ if (i == actionText.size())
+ actionHover = 0;
+
+ ui::setFontColor(255, 255, 255, 255);
+ make = false;
+ }
+ }
+}
+
+void actionAttack(void)
+{
+ ACTION_PROLOUGE;
+
+ auto m = currentWorld->getNearInteractable(*player);
+
+ if (m->type == MOBT) {
+ if (!inBattle && m != nullptr) {
+ Arena *a = new Arena(currentWorld, player, Mobp(m));
+ a->setStyle("");
+ a->setBackground(WorldBGType::Forest);
+ a->setBGM("assets/music/embark.wav");
+
+ ui::toggleWhiteFast();
+ ui::waitForCover();
+ currentWorld = a;
+ ui::toggleWhiteFast();
+ }
+ } else {
+ ui::dialogBox(player->name, "", false, "%s doesn't appear to be in the mood for fighting...", m->name);
+ }
+
+ ACTION_EPILOUGE;
+}
+
+void actionAction(void)
+{
+ ACTION_PROLOUGE;
+
+ auto e = currentWorld->getNearInteractable(*player);
+
+ if (e->type == NPCT) {
+ if (!NPCp(e)->aiFunc.empty())
+ e->interact();
+ }
+
+ ACTION_EPILOUGE;
+}
diff --git a/src/world.cpp b/src/world.cpp
index be8ba94..5893bfb 100644
--- a/src/world.cpp
+++ b/src/world.cpp
@@ -1,54 +1,74 @@
+#include <world.hpp>
+
+/* ----------------------------------------------------------------------------
+** Includes section
+** --------------------------------------------------------------------------*/
+
+// standard library headers
#include <algorithm>
#include <sstream>
-#include <world.hpp>
+// local game headers
#include <ui.hpp>
+// local library headers
#include <tinyxml2.h>
using namespace tinyxml2;
-/**
- * Defines how many HLINEs tall a blade of grass can be.
- */
+/* ----------------------------------------------------------------------------
+** Macros section
+** --------------------------------------------------------------------------*/
-#define GRASS_HEIGHT 4
-
-/**
- * Defines the height of the floor in an IndoorWorld.
- */
+// defines grass height in HLINEs
+#define GRASS_HEIGHT 4
+// indoor world constants
#define INDOOR_FLOOR_THICKNESS 50
#define INDOOR_FLOOR_HEIGHTT 400
-extern Player *player; // main.cpp?
-extern World *currentWorld; // main.cpp
-extern World *currentWorldToLeft; // main.cpp
-extern World *currentWorldToRight; // main.cpp
-extern int commonAIFunc(NPC *); // entities.cpp
-extern void commonTriggerFunc(Mob *); // gameplay.cpp
-extern void commonPageFunc(Mob *); // gameplay.cpp
-extern bool inBattle;
+/* ----------------------------------------------------------------------------
+** Variables section
+** --------------------------------------------------------------------------*/
+// external variables
+extern Player *player; // main.cpp?
+extern World *currentWorld; // main.cpp
+extern World *currentWorldToLeft; // main.cpp
+extern World *currentWorldToRight; // main.cpp
+extern bool inBattle; // ui.cpp?
extern unsigned int tickCount; // main.cpp
+extern std::string xmlFolder;
-extern std::string xmlFolder;
+// externally referenced in main.cpp
+const unsigned int DAY_CYCLE = 12000;
int worldShade = 0;
-std::string currentXML;
-
-std::vector<std::string> inside; // tracks indoor worlds
+// externally referenced in entities.cpp
+const float PLAYER_SPEED_CONSTANT = 0.150f;
+const float GRAVITY_CONSTANT = 0.001f;
-std::vector<World *> battleNest; // tracks arenas
-std::vector<vec2> battleNestLoc; // keeps arena locations
+// ground-generating constants
+static const float GROUND_HEIGHT_INITIAL = 80.0f;
+static const float GROUND_HEIGHT_MINIMUM = 60.0f;
+static const float GROUND_HEIGHT_MAXIMUM = 110.0f;
+static const float GROUND_HILLINESS = 10.0f;
-/**
- * Contains the current weather, used in many other places/files.
- */
+// the path of the currently loaded XML file, externally referenced in places
+std::string currentXML;
+// contains the current world's weather, extern'd in ui.cpp, main.cpp, ..?
WorldWeather weather = WorldWeather::Sunny;
-const std::string bgPaths[2][9]={
+// keeps track of pathnames of XML file'd worlds the player has left to enter structures
+std::vector<std::string> inside;
+
+// keeps track of information of worlds the player has left to enter arenas
+static std::vector<World *> battleNest;
+static std::vector<vec2> battleNestLoc;
+
+// pathnames of images for world themes
+static const std::string bgPaths[][9] = {
{"bg.png", // Daytime background
"bgn.png", // Nighttime background
"bgFarMountain.png", // Furthest layer
@@ -68,7 +88,8 @@ const std::string bgPaths[2][9]={
"bgWoodTile.png"}
};
-const std::string buildPaths[] = {
+// pathnames of structure textures
+static const std::string buildPaths[] = {
"townhall.png",
"house1.png",
"house2.png",
@@ -79,99 +100,66 @@ const std::string buildPaths[] = {
"brazzier.png"
};
-/**
- * Constants used for layer drawing in World::draw(), releated to transparency.
- */
-
-const float bgDraw[4][3]={
+// alpha-related values used for world drawing? nobody knows...
+static const float bgDraw[4][3]={
{ 100, 240, 0.6 },
{ 150, 250, 0.4 },
{ 200, 255, 0.25 },
{ 255, 255, 0.1 }
};
-/**
- * Sets the desired theme for the world's background.
- *
- * The images chosen for the background layers are selected depending on the
- * world's background type.
- */
-
-void World::
-setBackground(WorldBGType bgt)
-{
- // load textures with a limit check
- switch ((bgType = bgt)) {
- case WorldBGType::Forest:
- bgTex = new Texturec(bgFiles);
- break;
+/* ----------------------------------------------------------------------------
+** Functions section
+** --------------------------------------------------------------------------*/
- case WorldBGType::WoodHouse:
- bgTex = new Texturec(bgFilesIndoors);
- break;
-
- default:
- UserError("Invalid world background type");
- break;
- }
-}
+// externs
+extern int commonAIFunc(NPC *); // gameplay.cpp
+extern void commonTriggerFunc(Mob *); // gameplay.cpp
+extern void commonPageFunc(Mob *); // gameplay.cpp
/**
- * Sets the world's style.
- *
- * The world's style will determine what sprites are used for things like\
- * generic structures.
+ * Creates a world object.
+ * Note that all this does is nullify a pointer...
*/
-
-void World::
-setStyle(std::string pre)
+World::
+World(void)
{
- unsigned int i;
-
- // get folder prefix
- std::string prefix = pre.empty() ? "assets/style/classic/" : pre;
-
- for (i = 0; i < arrAmt(buildPaths); i++)
- sTexLoc.push_back(prefix + buildPaths[i]);
-
- prefix += "bg/";
-
- for (i = 0; i < arrAmt(bgPaths[0]); i++)
- bgFiles.push_back(prefix + bgPaths[0][i]);
-
- for (i = 0; i < arrAmt(bgPaths[1]); i++)
- bgFilesIndoors.push_back(prefix + bgPaths[1][i]);
+ bgmObj = nullptr;
}
/**
- * Creates a world object.
- *
- * Note that all this does is nullify pointers, to prevent as much disaster as
- * possible. Functions like setBGM(), setStyle() and generate() should be called
- * before the World is actually put into use.
+ * The world destructor.
+ * This will free objects used by the world itself, then free the vectors of
+ * entity-related objects.
*/
-
World::
-World(void)
+~World(void)
{
- bgmObj = NULL;
+ // SDL2_mixer's object
+ if (bgmObj != nullptr)
+ Mix_FreeMusic(bgmObj);
+
+ delete bgTex;
+ deleteEntities();
}
/**
* The entity vector destroyer.
- *
* This function will free all memory used by all entities, and then empty the
* vectors they were stored in.
*/
-
void World::
deleteEntities(void)
{
// free mobs
- mob.clear();
+ while (!mob.empty()) {
+ delete mob.back();
+ mob.pop_back();
+ }
- merchant.clear();
- while(!npc.empty()) {
+ // free npcs
+ merchant.clear(); // TODO
+ while (!npc.empty()) {
delete npc.back();
npc.pop_back();
}
@@ -184,52 +172,28 @@ deleteEntities(void)
// free objects
object.clear();
-
- // clear entity array
- entity.clear();
-
// free particles
particles.clear();
-
// clear light array
light.clear();
-
// free villages
village.clear();
-}
-
-/**
- * The world destructor.
- *
- * This will free objects used by the world itself, then free the vectors of
- * entity-related objects.
- */
-
-World::
-~World(void)
-{
- // sdl2_mixer's object
- if (bgmObj)
- Mix_FreeMusic(bgmObj);
-
- delete bgTex;
- deleteEntities();
+ // clear entity array
+ entity.clear();
}
/**
* Generates a world of the specified width.
- *
- * This will mainly populate the WorldData array, mostly preparing the World
+ * This will mainly populate the WorldData array, preparing most of the world
* object for usage.
*/
-
void World::
generate(unsigned int width)
{
// iterator for `for` loops
std::vector<WorldData>::iterator wditer;
- // see below for description
+ // see below for description/usage
float geninc = 0;
// check for valid width
@@ -237,7 +201,7 @@ generate(unsigned int width)
UserError("Invalid world dimensions");
// allocate space for world
- worldData = std::vector<WorldData> (width + GROUND_HILLINESS, WorldData { false, {0,0}, 0, 0 });
+ worldData = std::vector<WorldData> (width + GROUND_HILLINESS, WorldData { false, {0, 0}, 0, 0 });
lineCount = worldData.size();
// prepare for generation
@@ -245,7 +209,7 @@ generate(unsigned int width)
wditer = worldData.begin();
// give every GROUND_HILLINESSth entry a groundHeight value
- for(unsigned int i = GROUND_HILLINESS; i < worldData.size(); i += GROUND_HILLINESS, wditer += GROUND_HILLINESS)
+ for (unsigned i = GROUND_HILLINESS; i < worldData.size(); i += GROUND_HILLINESS, wditer += GROUND_HILLINESS)
worldData[i].groundHeight = (*wditer).groundHeight + (randGet() % 8 - 4);
// create slopes from the points that were just defined, populate the rest of the WorldData structure
@@ -254,23 +218,22 @@ generate(unsigned int width)
if ((*wditer).groundHeight && wditer + GROUND_HILLINESS < worldData.end())
// wditer + GROUND_HILLINESS can go out of bounds (invalid read)
geninc = ((*(wditer + GROUND_HILLINESS)).groundHeight - (*wditer).groundHeight) / (float)GROUND_HILLINESS;
- else
+ else {
(*wditer).groundHeight = (*(wditer - 1)).groundHeight + geninc;
+ if ((*wditer).groundHeight < GROUND_HEIGHT_MINIMUM)
+ (*wditer).groundHeight = GROUND_HEIGHT_MINIMUM;
+ else if ((*wditer).groundHeight > GROUND_HEIGHT_MAXIMUM)
+ (*wditer).groundHeight = GROUND_HEIGHT_MAXIMUM;
+ }
+
(*wditer).groundColor = randGet() % 32 / 8;
(*wditer).grassUnpressed = true;
(*wditer).grassHeight[0] = (randGet() % 16) / 3 + 2;
(*wditer).grassHeight[1] = (randGet() % 16) / 3 + 2;
- // bound checks
- if ((*wditer).groundHeight < GROUND_HEIGHT_MINIMUM)
- (*wditer).groundHeight = GROUND_HEIGHT_MINIMUM;
- else if ((*wditer).groundHeight > GROUND_HEIGHT_MAXIMUM)
- (*wditer).groundHeight = GROUND_HEIGHT_MAXIMUM;
-
- if ((*wditer).groundHeight <= 0)
+ if((*wditer).groundHeight <= 0)
(*wditer).groundHeight = GROUND_HEIGHT_MINIMUM;
-
}
// define x-coordinate of world's leftmost 'line'
@@ -285,107 +248,17 @@ generate(unsigned int width)
}
/**
- * Updates all entity and player coordinates with their velocities.
- *
- * Also handles music fading, although that could probably be placed elsewhere.
- */
-
-void World::
-update(Player *p, unsigned int delta)
-{
- // update player coords
- p->loc.y += p->vel.y * delta;
- p->loc.x +=(p->vel.x * p->speed) * delta;
-
- if (p->loc.y > 5000)
- UserError("Too high for me m8.");
-
- // update entity coords
- for (auto &e : entity) {
-
- // dont let structures move?
- if (e->type != STRUCTURET && e->canMove) {
- e->loc.x += e->vel.x * delta;
- e->loc.y += e->vel.y * delta;
-
- // update boolean directions
- if (e->vel.x < 0)
- e->left = true;
- else if (e->vel.x > 0)
- e->left = false;
- } else if (e->vel.y < 0)
- e->loc.y += e->vel.y * delta;
- }
- // iterate through particles
- particles.erase(std::remove_if (particles.begin(), particles.end(), [&delta](Particles &part) {return part.kill(delta);}), particles.end());
- for (auto part = particles.begin(); part != particles.end(); part++) {
- if ((*part).canMove) {
- (*part).loc.y += (*part).vel.y * delta;
- (*part).loc.x += (*part).vel.x * delta;
-
- for (auto &b : build) {
- if (b->bsubtype == FOUNTAIN) {
- if ((*part).loc.x >= b->loc.x && (*part).loc.x <= b->loc.x + b->width) {
- if ((*part).loc.y <= b->loc.y + b->height * .25)
- particles.erase(part);
-
- }
- }
- }
- }
- }
-
- // handle music fades
- if (ui::dialogImportant) {
- //Mix_FadeOutMusic(2000);
- } else if (!Mix_PlayingMusic())
- Mix_FadeInMusic(bgmObj,-1,2000);
-}
-
-/**
- * Set the world's BGM.
- *
- * This will load a sound file to be played while the player is in this world.
- * If no file is found, no music should play.
- */
-
-void World::
-setBGM(std::string path)
-{
- if (!path.empty())
- bgmObj = Mix_LoadMUS((bgm = path).c_str());
-}
-
-/**
- * Toggle play/stop of the background music.
- *
- * If new music is to be played a crossfade will occur, otherwise... uhm.
- */
-
-void World::
-bgmPlay(World *prev) const
-{
- if (prev) {
- if (bgm != prev->bgm) {
- // new world, new music
- Mix_FadeOutMusic(800);
- Mix_PlayMusic(bgmObj, -1);
- }
- } else {
- // first call
- Mix_FadeOutMusic(800);
- Mix_PlayMusic(bgmObj, -1);
- }
-}
-
-/**
* The world draw function.
- *
* This function will draw the background layers, entities, and player to the
* screen.
*/
+void World::
+draw(Player *p)
+{
+ const ivec2 backgroundOffset = ivec2 {
+ (int)(SCREEN_WIDTH / 2), (int)(SCREEN_HEIGHT / 2)
+ };
-void World::draw(Player *p) {
// iterators
int i, iStart, iEnd;
@@ -398,134 +271,105 @@ void World::draw(Player *p) {
// world width in pixels
int width = worldData.size() * HLINE;
+ // used for alpha values of background textures
+ int alpha;
+
// shade value for GLSL
- float shadeAmbient = -worldShade / 50.0f + 0.5f; // -0.5f to 1.5f
- if (shadeAmbient < 0)
- shadeAmbient = 0;
- else if (shadeAmbient > 0.9f)
- shadeAmbient = 1;
+ float shadeAmbient = fmax(0, -worldShade / 50.0f + 0.5f); // 0 to 1.5f
- /*
- * Draw background images.
- */
+ if (shadeAmbient > 0.9f)
+ shadeAmbient = 1.0f;
+ // draw background images.
glEnable(GL_TEXTURE_2D);
// the sunny wallpaper is faded with the night depending on tickCount
-
bgTex->bind(0);
- int alpha;
- switch(weather) {
- case WorldWeather::Snowy:
- alpha = 150;
- break;
- case WorldWeather::Rain:
- alpha = 0;
- break;
+ switch (weather) {
+ case WorldWeather::Snowy : alpha = 150; break;
+ case WorldWeather::Rain : alpha = 0; break;
default:
alpha = 255 - worldShade * 4;
break;
}
- safeSetColorA(255, 255, 255, alpha);
+ safeSetColorA(255, 255, 255, alpha);
glBegin(GL_QUADS);
- glTexCoord2i(0, 0); glVertex2i(offset.x - SCREEN_WIDTH/2-5, offset.y + SCREEN_HEIGHT/2);
- glTexCoord2i(1, 0); glVertex2i(offset.x + SCREEN_WIDTH/2+5, offset.y + SCREEN_HEIGHT/2);
- glTexCoord2i(1, 1); glVertex2i(offset.x + SCREEN_WIDTH/2+5, offset.y - SCREEN_HEIGHT/2);
- glTexCoord2i(0, 1); glVertex2i(offset.x - SCREEN_WIDTH/2-5, offset.y - SCREEN_HEIGHT/2);
+ glTexCoord2i(0, 0); glVertex2i(offset.x - backgroundOffset.x - 5, offset.y + backgroundOffset.y);
+ glTexCoord2i(1, 0); glVertex2i(offset.x + backgroundOffset.x + 5, offset.y + backgroundOffset.y);
+ glTexCoord2i(1, 1); glVertex2i(offset.x + backgroundOffset.x + 5, offset.y - backgroundOffset.y);
+ glTexCoord2i(0, 1); glVertex2i(offset.x - backgroundOffset.x - 5, offset.y - backgroundOffset.y);
glEnd();
bgTex->bindNext();
safeSetColorA(255, 255, 255, !alpha ? 255 : worldShade * 4);
-
glBegin(GL_QUADS);
- glTexCoord2i(0, 0); glVertex2i(offset.x - SCREEN_WIDTH/2-5, offset.y + SCREEN_HEIGHT/2);
- glTexCoord2i(1, 0); glVertex2i(offset.x + SCREEN_WIDTH/2+5, offset.y + SCREEN_HEIGHT/2);
- glTexCoord2i(1, 1); glVertex2i(offset.x + SCREEN_WIDTH/2+5, offset.y - SCREEN_HEIGHT/2);
- glTexCoord2i(0, 1); glVertex2i(offset.x - SCREEN_WIDTH/2-5, offset.y - SCREEN_HEIGHT/2);
+ glTexCoord2i(0, 0); glVertex2i(offset.x - backgroundOffset.x - 5, offset.y + backgroundOffset.y);
+ glTexCoord2i(1, 0); glVertex2i(offset.x + backgroundOffset.x + 5, offset.y + backgroundOffset.y);
+ glTexCoord2i(1, 1); glVertex2i(offset.x + backgroundOffset.x + 5, offset.y - backgroundOffset.y);
+ glTexCoord2i(0, 1); glVertex2i(offset.x - backgroundOffset.x - 5, offset.y - backgroundOffset.y);
glEnd();
glDisable(GL_TEXTURE_2D);
// draw the stars if the time deems it appropriate
-
- //if ((((weather == WorldWeather::Dark) & (tickCount % DAY_CYCLE)) < DAY_CYCLE / 2) ||
- // (((weather == WorldWeather::Sunny) & (tickCount % DAY_CYCLE)) > DAY_CYCLE * .75)) {
if (worldShade > 0) {
-
safeSetColorA(255, 255, 255, 255 - (getRand() % 30 - 15));
- for (i = 0; i < 100; i++) {
- glRectf(star[i].x + offset.x * .9,
- star[i].y,
- star[i].x + offset.x * .9 + HLINE,
- star[i].y + HLINE
- );
- }
+ auto xcoord = offset.x * 0.9f;
+ for (auto &s : star)
+ glRectf(s.x + xcoord, s.y, s.x + xcoord + HLINE, s.y + HLINE);
}
// draw remaining background items
-
glEnable(GL_TEXTURE_2D);
bgTex->bindNext();
safeSetColorA(150 + shadeBackground * 2, 150 + shadeBackground * 2, 150 + shadeBackground * 2, 255);
-
- glBegin(GL_QUADS);
+ glBegin(GL_QUADS); {
+ auto xcoord = width / 2 * -1 + offset.x * 0.85f;
for (i = 0; i <= (int)(worldData.size() * HLINE / 1920); i++) {
- glTexCoord2i(0, 1); glVertex2i(width / 2 * -1 + (1920 * i) + offset.x * .85, GROUND_HEIGHT_MINIMUM);
- glTexCoord2i(1, 1); glVertex2i(width / 2 * -1 + (1920 * (i + 1)) + offset.x * .85, GROUND_HEIGHT_MINIMUM);
- glTexCoord2i(1, 0); glVertex2i(width / 2 * -1 + (1920 * (i + 1)) + offset.x * .85, GROUND_HEIGHT_MINIMUM + 1080);
- glTexCoord2i(0, 0); glVertex2i(width / 2 * -1 + (1920 * i) + offset.x * .85, GROUND_HEIGHT_MINIMUM + 1080);
+ glTexCoord2i(0, 1); glVertex2i(1920 * i + xcoord, GROUND_HEIGHT_MINIMUM);
+ glTexCoord2i(1, 1); glVertex2i(1920 * (i + 1) + xcoord, GROUND_HEIGHT_MINIMUM);
+ glTexCoord2i(1, 0); glVertex2i(1920 * (i + 1) + xcoord, GROUND_HEIGHT_MINIMUM + 1080);
+ glTexCoord2i(0, 0); glVertex2i(1920 * i + xcoord, GROUND_HEIGHT_MINIMUM + 1080);
}
- glEnd();
+ } glEnd();
for (i = 0; i < 4; i++) {
bgTex->bindNext();
- safeSetColorA(bgDraw[i][0] + shadeBackground * 2, bgDraw[i][0] + shadeBackground * 2, bgDraw[i][0] + shadeBackground * 2, bgDraw[i][1]);
-
- glBegin(GL_QUADS);
- for(int j = worldStart; j <= -worldStart; j += 600) {
- glTexCoord2i(0, 1); glVertex2i(j + offset.x * bgDraw[i][2], GROUND_HEIGHT_MINIMUM);
- glTexCoord2i(1, 1); glVertex2i((j + 600) + offset.x * bgDraw[i][2], GROUND_HEIGHT_MINIMUM);
- glTexCoord2i(1, 0); glVertex2i((j + 600) + offset.x * bgDraw[i][2], GROUND_HEIGHT_MINIMUM + 400);
- glTexCoord2i(0, 0); glVertex2i(j + offset.x * bgDraw[i][2], GROUND_HEIGHT_MINIMUM + 400);
+ safeSetColorA(bgDraw[i][0] + shadeBackground * 2,
+ bgDraw[i][0] + shadeBackground * 2,
+ bgDraw[i][0] + shadeBackground * 2,
+ bgDraw[i][1]
+ );
+ glBegin(GL_QUADS); {
+ auto xcoord = offset.x * bgDraw[i][2];
+ for (int j = worldStart; j <= -worldStart; j += 600) {
+ glTexCoord2i(0, 1); glVertex2i(j + xcoord, GROUND_HEIGHT_MINIMUM);
+ glTexCoord2i(1, 1); glVertex2i(j + 600 + xcoord, GROUND_HEIGHT_MINIMUM);
+ glTexCoord2i(1, 0); glVertex2i(j + 600 + xcoord, GROUND_HEIGHT_MINIMUM + 400);
+ glTexCoord2i(0, 0); glVertex2i(j + xcoord, GROUND_HEIGHT_MINIMUM + 400);
}
- glEnd();
+ } glEnd();
}
glDisable(GL_TEXTURE_2D);
- // draw black under backgrounds
-
+ // draw black under backgrounds (y-coordinate)
glColor3ub(0, 0, 0);
glRectf(worldStart, GROUND_HEIGHT_MINIMUM, -worldStart, 0);
- pOffset = (offset.x + p->width / 2 - worldStart) / HLINE;
-
- /*
- * Prepare for world ground drawing.
- */
-
- // only draw world within player vision
-
- if ((iStart = pOffset - (SCREEN_WIDTH / 2 / HLINE) - GROUND_HILLINESS) < 0)
- iStart = 0;
-
- if ((iEnd = pOffset + (SCREEN_WIDTH / 2 / HLINE) + GROUND_HILLINESS + HLINE) > (int)worldData.size())
- iEnd = worldData.size();
- else if (iEnd < GROUND_HILLINESS)
- iEnd = GROUND_HILLINESS;
-
// draw particles and buildings
-
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, colorIndex);
-
glUniform1i(glGetUniformLocation(shaderProgram, "sampler"), 0);
glUseProgram(shaderProgram);
- std::for_each(particles.begin(), particles.end(), [](Particles part) { if (part.behind) part.draw(); });
+ std::for_each(std::begin(particles), std::end(particles), [](Particles &p) {
+ if (p.behind)
+ p.draw();
+ });
glUseProgram(0);
@@ -541,14 +385,7 @@ void World::draw(Player *p) {
b->draw();
}
- // draw light elements?
-
- glEnable(GL_TEXTURE_2D);
-
- glActiveTexture(GL_TEXTURE0);
- bgTex->bindNext();
-
- for(auto &l : light) {
+ for (auto &l : light) {
if (l.belongsTo) {
l.loc.x = l.following->loc.x + SCREEN_WIDTH/2;
l.loc.y = l.following->loc.y;
@@ -557,11 +394,16 @@ void World::draw(Player *p) {
l.fireFlicker = .9+((rand()%2)/10.0f);
l.fireLoc.x = l.loc.x + (rand()%2-1)*3;
l.fireLoc.y = l.loc.y + (rand()%2-1)*3;
- }else{
+ } else {
l.fireFlicker = 1.0f;
}
}
+ // draw light elements
+ glEnable(GL_TEXTURE_2D);
+ glActiveTexture(GL_TEXTURE0);
+ bgTex->bindNext();
+
std::unique_ptr<GLfloat[]> pointArrayBuf = std::make_unique<GLfloat[]> (2 * (light.size()));
auto pointArray = pointArrayBuf.get();
GLfloat flameArray[64];
@@ -595,214 +437,171 @@ void World::draw(Player *p) {
glUniform1fv(glGetUniformLocation(shaderProgram,"fireFlicker"), light.size(),flameArray);
}
- /*
- * Draw the dirt.
- */
-
- glBegin(GL_QUADS);
+ // get the line that the player is currently standing on
+ pOffset = (offset.x + p->width / 2 - worldStart) / HLINE;
- // faulty
- /*glTexCoord2i(0 ,0);glVertex2i(pOffset - (SCREEN_WIDTH / 1.5),0);
- glTexCoord2i(64,0);glVertex2i(pOffset + (SCREEN_WIDTH / 1.5),0);
- glTexCoord2i(64,1);glVertex2i(pOffset + (SCREEN_WIDTH / 1.5),GROUND_HEIGHT_MINIMUM);
- glTexCoord2i(0 ,1);glVertex2i(pOffset - (SCREEN_WIDTH / 1.5),GROUND_HEIGHT_MINIMUM);*/
+ // only draw world within player vision
+ iStart = (int)fmax(pOffset - (SCREEN_WIDTH / 2 / HLINE) - GROUND_HILLINESS, 0);
+ iEnd = (int)fmin(pOffset + (SCREEN_WIDTH / 2 / HLINE) + GROUND_HILLINESS + HLINE, worldData.size());
+ iEnd = (int)fmax(iEnd, GROUND_HILLINESS);
+ // draw the dirt
+ glBegin(GL_QUADS);
+ //std::for_each(std::begin(worldData) + iStart, std::begin(worldData) + iEnd, [&](WorldData wd) {
for (i = iStart; i < iEnd; i++) {
- if (worldData[i].groundHeight <= 0) {
- worldData[i].groundHeight = GROUND_HEIGHT_MINIMUM - 1;
+ auto wd = worldData[i];
+ if (wd.groundHeight <= 0) {
+ wd.groundHeight = GROUND_HEIGHT_MINIMUM - 1;
glColor4ub(0, 0, 0, 255);
- } else
+ } else {
safeSetColorA(150, 150, 150, 255);
+ }
- glTexCoord2i(0, 0); glVertex2i(worldStart + i * HLINE , worldData[i].groundHeight - GRASS_HEIGHT);
- glTexCoord2i(1, 0); glVertex2i(worldStart + i * HLINE + HLINE , worldData[i].groundHeight - GRASS_HEIGHT);
-
- glTexCoord2i(1, (int)(worldData[i].groundHeight / 64) + worldData[i].groundColor); glVertex2i(worldStart + i * HLINE + HLINE, 0);
- glTexCoord2i(0, (int)(worldData[i].groundHeight / 64) + worldData[i].groundColor); glVertex2i(worldStart + i * HLINE , 0);
-
- if (worldData[i].groundHeight == GROUND_HEIGHT_MINIMUM - 1)
- worldData[i].groundHeight = 0;
- }
+ int ty = wd.groundHeight / 64 + wd.groundColor;
+ glTexCoord2i(0, 0); glVertex2i(worldStart + i * HLINE , wd.groundHeight - GRASS_HEIGHT);
+ glTexCoord2i(1, 0); glVertex2i(worldStart + i * HLINE + HLINE , wd.groundHeight - GRASS_HEIGHT);
+ glTexCoord2i(1, ty); glVertex2i(worldStart + i * HLINE + HLINE, 0);
+ glTexCoord2i(0, ty); glVertex2i(worldStart + i * HLINE , 0);
+ if (wd.groundHeight == GROUND_HEIGHT_MINIMUM - 1)
+ wd.groundHeight = 0;
+ }//);
glEnd();
glUseProgram(0);
glDisable(GL_TEXTURE_2D);
- /*
- * Draw the grass/the top of the ground.
- */
-
+ // draw the grass
glEnable(GL_TEXTURE_2D);
-
glActiveTexture(GL_TEXTURE0);
bgTex->bindNext();
-
glUseProgram(shaderProgram);
glUniform1i(glGetUniformLocation(shaderProgram, "sampler"), 0);
+ safeSetColorA(255, 255, 255, 255);
- float cgh[2];
- for (i = iStart; i < iEnd - GROUND_HILLINESS; i++) {
-
- // load the current line's grass values
- if (worldData[i].groundHeight)
- memcpy(cgh, worldData[i].grassHeight, 2 * sizeof(float));
- else
- memset(cgh, 0 , 2 * sizeof(float));
+ for (i = iStart; i < iEnd; i++) {
+ auto wd = worldData[i];
+ auto gh = wd.grassHeight;
// flatten the grass if the player is standing on it.
if (!worldData[i].grassUnpressed) {
- cgh[0] /= 4;
- cgh[1] /= 4;
+ gh[0] /= 4;
+ gh[1] /= 4;
}
// actually draw the grass.
-
- safeSetColorA(255, 255, 255, 255);
-
- glBegin(GL_QUADS);
- glTexCoord2i(0, 0); glVertex2i(worldStart + i * HLINE , worldData[i].groundHeight + cgh[0]);
- glTexCoord2i(1, 0); glVertex2i(worldStart + i * HLINE + HLINE / 2, worldData[i].groundHeight + cgh[0]);
- glTexCoord2i(1, 1); glVertex2i(worldStart + i * HLINE + HLINE / 2, worldData[i].groundHeight - GRASS_HEIGHT);
- glTexCoord2i(0, 1); glVertex2i(worldStart + i * HLINE , worldData[i].groundHeight - GRASS_HEIGHT);
- glTexCoord2i(0, 0); glVertex2i(worldStart + i * HLINE + HLINE / 2, worldData[i].groundHeight + cgh[1]);
- glTexCoord2i(1, 0); glVertex2i(worldStart + i * HLINE + HLINE , worldData[i].groundHeight + cgh[1]);
- glTexCoord2i(1, 1); glVertex2i(worldStart + i * HLINE + HLINE , worldData[i].groundHeight - GRASS_HEIGHT);
- glTexCoord2i(0, 1); glVertex2i(worldStart + i * HLINE + HLINE / 2, worldData[i].groundHeight - GRASS_HEIGHT);
- glEnd();
+ if (wd.groundHeight) {
+ glBegin(GL_QUADS);
+ glTexCoord2i(0, 0); glVertex2i(worldStart + i * HLINE , wd.groundHeight + gh[0]);
+ glTexCoord2i(1, 0); glVertex2i(worldStart + i * HLINE + HLINE / 2, wd.groundHeight + gh[0]);
+ glTexCoord2i(1, 1); glVertex2i(worldStart + i * HLINE + HLINE / 2, wd.groundHeight - GRASS_HEIGHT);
+ glTexCoord2i(0, 1); glVertex2i(worldStart + i * HLINE , wd.groundHeight - GRASS_HEIGHT);
+ glTexCoord2i(0, 0); glVertex2i(worldStart + i * HLINE + HLINE / 2, wd.groundHeight + gh[1]);
+ glTexCoord2i(1, 0); glVertex2i(worldStart + i * HLINE + HLINE , wd.groundHeight + gh[1]);
+ glTexCoord2i(1, 1); glVertex2i(worldStart + i * HLINE + HLINE , wd.groundHeight - GRASS_HEIGHT);
+ glTexCoord2i(0, 1); glVertex2i(worldStart + i * HLINE + HLINE / 2, wd.groundHeight - GRASS_HEIGHT);
+ glEnd();
+ }
}
glUseProgram(0);
glDisable(GL_TEXTURE_2D);
- /*
- * Draw remaining entities.
- */
-
-
+ // draw particles
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, colorIndex);
-
glUniform1i(glGetUniformLocation(shaderProgram, "sampler"), 0);
glUseProgram(shaderProgram);
- std::for_each(particles.begin(), particles.end(), [](Particles part) { if (!part.behind) part.draw(); });
+ for (auto &p : particles) {
+ if (!p.behind)
+ p.draw();
+ }
glUseProgram(0);
+ // draw remaining entities
for (auto &n : npc) {
if (n->type != MERCHT)
n->draw();
}
for (auto &m : mob)
- m.draw();
+ m->draw();
for (auto &o : object)
o.draw();
- /*
- * Handle grass-squishing.
- */
-
- // calculate the line that the player is on
- int ph = (p->loc.x + p->width / 2 - worldStart) / HLINE;
-
// flatten grass under the player if the player is on the ground
if (p->ground) {
- for (i = 0; i < (int)(worldData.size() - GROUND_HILLINESS); i++)
- worldData[i].grassUnpressed = !(i < ph + 6 && i > ph - 6);
+ for (i = 0; i < (int)worldData.size(); i++)
+ worldData[i].grassUnpressed = !(i < pOffset + 6 && i > pOffset - 6);
} else {
- for (i = 0; i < (int)(worldData.size() - GROUND_HILLINESS); i++)
+ for (i = 0; i < (int)worldData.size(); i++)
worldData[i].grassUnpressed = true;
}
- /*
- * Draw the player.
- */
-
+ // draw the player
p->draw();
}
/**
* Handles physics and such for a single entity.
- *
* This function is kept private, as World::detect() should be used instead to
* handle stuffs for all entities at once.
*/
-
void World::
singleDetect(Entity *e)
{
std::string killed;
- unsigned int i,j;
+ unsigned int i;
int l;
- /*
- * Kill any dead entities.
- */
-
+ // kill dead entities
if (e->alive && e->health <= 0) {
+ // die
e->alive = false;
e->health = 0;
+
+ // delete the entity
for (i = 0; i < entity.size(); i++) {
if (entity[i] == e) {
switch (e->type) {
case STRUCTURET:
killed = "structure";
- for(j=0;j<build.size();j++) {
- if (build[j]==e) {
- delete build[j];
- build.erase(build.begin()+j);
- break;
- }
- }
- break;
- case NPCT:
+ build.erase(std::find(std::begin(build), std::end(build), e));
+ break;
+ case NPCT:
killed = "NPC";
- for(j=0;j<npc.size();j++) {
- if (npc[j]==e) {
- delete npc[j];
- npc.erase(npc.begin()+j);
- break;
- }
- }
+ npc.erase(std::find(std::begin(npc), std::end(npc), e));
break;
case MOBT:
killed = "mob";
- /*for(j=0;j<mob.size();j++) {
- if (mob[j]==e) {
- delete mob[j];
- mob.erase(mob.begin()+j);
- break;
- }
- }*/
+ // TODO
break;
case OBJECTT:
killed = "object";
- for (auto o = std::begin(object); o != std::end(object); o++) {
- if (&(*o) == e) {
- object.erase(o);
- break;
- }
- }
+ object.erase(std::find(std::begin(object), std::end(object), *Objectp(e)));
break;
default:
break;
}
+
std::cout << "Killed a " << killed << "..." << std::endl;
- entity.erase(entity.begin()+i);
+ entity.erase(entity.begin() + i);
return;
}
}
+
+ // exit on player death
std::cout << "RIP " << e->name << "." << std::endl;
exit(0);
}
- // handle only living entities
+ // collision / gravity: handle only living entities
if (e->alive) {
- // forced movement gravity
+ // forced movement gravity (sword hits)
if (e->forcedMove) {
if (e->vel.x > .0005 || e->vel.x < -.0005)
e->vel.x *= .6;
@@ -810,25 +609,21 @@ singleDetect(Entity *e)
e->forcedMove = false;
}
- if (e->type == MOBT && Mobp(e)->subtype == MS_TRIGGER)
+ if (e->subtype == MS_TRIGGER)
return;
// calculate the line that this entity is currently standing on
- l = (e->loc.x + e->width / 2 - worldStart) / HLINE;
- if (l < 0)
- l = 0;
- i = l;
- if (i > lineCount - 1)
- i = lineCount - 1;
+ l = (int)fmax((e->loc.x + e->width / 2 - worldStart) / HLINE, 0);
+ l = (int)fmin(l, lineCount - 1);
// if the entity is under the world/line, pop it back to the surface
- if (e->loc.y < worldData[i].groundHeight) {
+ if (e->loc.y < worldData[l].groundHeight) {
int dir = e->vel.x < 0 ? -1 : 1;
- if (i + (dir * 2) < worldData.size() && worldData[i + (dir * 2)].groundHeight - 30 > worldData[i + dir].groundHeight) {
- e->loc.x -= (PLAYER_SPEED_CONSTANT + 2.7) * e->speed * 2 * dir;
+ if (l + (dir * 2) < (int)worldData.size() && worldData[l + (dir * 2)].groundHeight - 30 > worldData[l + dir].groundHeight) {
+ e->loc.x -= (PLAYER_SPEED_CONSTANT + 2.7f) * e->speed * 2 * dir;
e->vel.x = 0;
} else {
- e->loc.y = worldData[i].groundHeight - .001 * deltaTime;
+ e->loc.y = worldData[l].groundHeight - 0.001f * deltaTime;
e->ground = true;
e->vel.y = 0;
}
@@ -837,26 +632,23 @@ singleDetect(Entity *e)
// handle gravity if the entity is above the line
else {
-
if (e->type == STRUCTURET) {
- e->loc.y = worldData[i].groundHeight;
+ e->loc.y = worldData[l].groundHeight;
e->vel.y = 0;
e->ground = true;
return;
- } else if (e->vel.y > -2)
+ } else if (e->vel.y > -2) {
e->vel.y -= GRAVITY_CONSTANT * deltaTime;
+ }
}
- /*
- * Insure that the entity doesn't fall off either edge of the world.
- */
-
- if (e->loc.x < worldStart) { // Left bound
- e->vel.x=0;
- e->loc.x=(float)worldStart + HLINE / 2;
- }else if (e->loc.x + e->width + HLINE > worldStart + worldStart * -2) { // Right bound
- e->vel.x=0;
- e->loc.x=worldStart + worldStart * -2 - e->width - HLINE;
+ // insure that the entity doesn't fall off either edge of the world.
+ if (e->loc.x < worldStart) {
+ e->vel.x = 0;
+ e->loc.x = worldStart + HLINE / 2;
+ } else if (e->loc.x + e->width + HLINE > worldStart + worldStart * -2) {
+ e->vel.x = 0;
+ e->loc.x = worldStart + worldStart * -2 - e->width - HLINE;
}
}
}
@@ -868,7 +660,6 @@ singleDetect(Entity *e)
* currently in a vector of this world. Particles and village entrance/exiting
* are also handled here.
*/
-
void World::
detect(Player *p)
{
@@ -883,16 +674,9 @@ detect(Player *p)
// handle particles
for (auto &part : particles) {
-
// get particle's current world line
- l = (part.loc.x + part.width / 2 - worldStart) / HLINE;
-
- if (l < 0)
- l = 0;
-
- if (l > (int)(lineCount - 1))
- l = lineCount - 1;
-
+ l = (int)fmax((part.loc.x + part.width / 2 - worldStart) / HLINE, 0);
+ l = (int)fmin(lineCount - 1, l);
part.update(GRAVITY_CONSTANT, worldData[l].groundHeight);
}
@@ -910,11 +694,9 @@ detect(Player *p)
{ 0, 0, 255 }, // RGB color
2500 // duration (ms)
);
-
particles.back().fountain = true;
}
break;
-
case FIRE_PIT:
for(unsigned int r = (randGet() % 20) + 11; r--;) {
addParticle(randGet() % (int)(b->width / 2) + b->loc.x + b->width / 4, // x
@@ -926,12 +708,10 @@ detect(Player *p)
{ 255, 0, 0 }, // RGB color
400 // duration (ms)
);
-
particles.back().gravity = false;
particles.back().behind = true;
}
break;
-
default:
break;
}
@@ -939,140 +719,345 @@ detect(Player *p)
// draws the village welcome message if the player enters the village bounds
for (auto &v : village) {
- if (p->loc.x > v.start.x && p->loc.x < v.end.x) {
- if (!v.in) {
- ui::passiveImportantText(5000, "Welcome to %s", v.name.c_str());
- v.in = true;
- }
- } else
+ if (p->loc.x > v.start.x && p->loc.x < v.end.x && !v.in) {
+ ui::passiveImportantText(5000, "Welcome to %s", v.name.c_str());
+ v.in = true;
+ } else {
v.in = false;
+ }
}
}
-void World::addStructure(BUILD_SUB sub, float x,float y, std::string tex, std::string inside) {
- build.push_back(new Structures());
- build.back()->inWorld = this;
- build.back()->textureLoc = tex;
+/**
+ * Updates all entity and player coordinates with their velocities.
+ * Also handles music fading, although that could probably be placed elsewhere.
+ */
+void World::
+update(Player *p, unsigned int delta)
+{
+ // update player coords
+ p->loc.y += p->vel.y * delta;
+ p->loc.x +=(p->vel.x * p->speed) * delta;
- build.back()->spawn(sub,x,y);
+ // handle high-ness
+ if (p->loc.y > 5000)
+ UserError("Too high for me m8.");
- build.back()->inside = inside;
+ // update entity coords
+ for (auto &e : entity) {
+ // dont let structures move?
+ if (e->type != STRUCTURET && e->canMove) {
+ e->loc.x += e->vel.x * delta;
+ e->loc.y += e->vel.y * delta;
- entity.push_back(build.back());
+ // update boolean directions
+ e->left = e->vel.x ? (e->vel.x < 0) : e->left;
+ } else if (e->vel.y < 0) {
+ e->loc.y += e->vel.y * delta;
+ }
+ }
+ // iterate through particles
+ particles.erase(std::remove_if(particles.begin(), particles.end(), [&delta](Particles &part){
+ return part.kill(delta);
+ }),
+ particles.end());
+
+ for (auto part = particles.begin(); part != particles.end(); part++) {
+ auto pa = *part;
+
+ if (pa.canMove) {
+ (*part).loc.y += pa.vel.y * delta;
+ (*part).loc.x += pa.vel.x * delta;
+
+ if (std::any_of(std::begin(build), std::end(build), [pa](Structures *s) {
+ return (s->bsubtype == FOUNTAIN) &&
+ (pa.loc.x >= s->loc.x) && (pa.loc.x <= s->loc.x + s->width) &&
+ (pa.loc.y <= s->loc.y + s->height * 0.25f);
+ })) {
+ particles.erase(part);
+ }
+ }
+ }
+
+ // handle music fades
+ if (!Mix_PlayingMusic())
+ Mix_FadeInMusic(bgmObj, -1, 2000);
}
-Village *World::
-addVillage(std::string name, World *world)
+/**
+ * Get's the world's width in pixels.
+ */
+int World::
+getTheWidth(void) const
{
- village.emplace_back(name.c_str(), world);
- return &village.back();
+ return (worldStart * -2);
}
-void World::addMob(int t,float x,float y) {
- mob.emplace_back(t);
- mob.back().spawn(x,y);
+/**
+ * Get a pointer to the most recently created light.
+ * Meant to be non-constant.
+ */
+Light *World::
+getLastLight(void)
+{
+ return &light.back();
+}
- entity.push_back(&mob.back());
+/**
+ * Get a pointer to the most recently created mob.
+ * Meant to be non-constant.
+ */
+Mob *World::
+getLastMob(void)
+{
+ return mob.back();
}
-void World::addMob(int t,float x,float y,void (*hey)(Mob *)) {
- mob.emplace_back(t);
- mob.back().spawn(x,y);
- mob.back().hey = hey;
+/**
+ * Get the interactable entity that is closest to the entity provided.
+ */
+Entity *World::
+getNearInteractable(Entity &e)
+{
+ auto n = std::find_if(std::begin(entity), std::end(entity), [&](Entity *&a) {
+ return ((a->type == MOBT) || (a->type == NPCT) || a->type == MERCHT) &&
+ e.isNear(*a) && (e.left ? (a->loc.x < e.loc.x) : (a->loc.x > e.loc.x));
+ });
- entity.push_back(&mob.back());
+ return n == std::end(entity) ? nullptr : *n;
}
-void World::addNPC(float x,float y) {
- npc.push_back(new NPC());
- npc.back()->spawn(x,y);
+/**
+ * Get the file path for the `index`th building.
+ */
+std::string World::
+getSTextureLocation(unsigned int index) const
+{
+ return index < sTexLoc.size() ? sTexLoc[ index ] : "";
+}
- entity.push_back(npc.back());
+/**
+ * Get the coordinates of the `index`th building, with -1 meaning the last building.
+ */
+vec2 World::
+getStructurePos(int index)
+{
+ if (index < 0)
+ return build.back()->loc;
+ else if ((unsigned)index >= build.size())
+ return vec2 {0, 0};
+
+ return build[index]->loc;
}
-void World::addMerchant(float x, float y) {
- merchant.push_back(new Merchant());
- merchant.back()->spawn(x,y);
+/**
+ * Saves world data to a file.
+ */
+void World::save(void){
+ std::string data;
+ std::string save = currentXML + ".dat";
+ std::ofstream out (save, std::ios::out | std::ios::binary);
- npc.push_back(merchant.back());
- entity.push_back(npc.back());
+ std::cout << "Saving to " << save << " ..." << '\n';
+
+ // save npcs
+ for (auto &n : npc) {
+ data.append(std::to_string(n->dialogIndex) + "\n");
+ data.append(std::to_string((int)n->loc.x) + "\n");
+ data.append(std::to_string((int)n->loc.y) + "\n");
+ }
+
+ // save structures
+ for (auto &b : build) {
+ data.append(std::to_string((int)b->loc.x) + "\n");
+ data.append(std::to_string((int)b->loc.y) + "\n");
+ }
+
+ // save mobs
+ for (auto &m : mob) {
+ data.append(std::to_string((int)m->loc.x) + "\n");
+ data.append(std::to_string((int)m->loc.y) + "\n");
+ data.append(std::to_string((int)m->alive) + "\n");
+ }
+
+ // wrap up
+ data.append("dOnE\0");
+ out.write(data.data(), data.size());
+ out.close();
}
-void World::addObject(std::string in, std::string p, float x, float y) {
- object.emplace_back(in, p);
- object.back().spawn(x, y);
+void World::load(void){
+ std::string save, data, line;
+ const char *filedata;
- entity.push_back(&object.back());
+ save = currentXML + ".dat";
+ filedata = readFile(save.c_str());
+ data = filedata;
+ std::istringstream iss (data);
+
+ for(auto &n : npc){
+ std::getline(iss,line);
+ if(line == "dOnE")return;
+ if((n->dialogIndex = std::stoi(line)) != 9999)
+ n->addAIFunc(commonAIFunc,false);
+ else n->clearAIFunc();
+
+ std::getline(iss,line);
+ if(line == "dOnE")return;
+ n->loc.x = std::stoi(line);
+ std::getline(iss,line);
+ if(line == "dOnE")return;
+ n->loc.y = std::stoi(line);
+ }
+
+ for(auto &b : build){
+ std::getline(iss,line);
+ if(line == "dOnE")return;
+ b->loc.x = std::stoi(line);
+ std::getline(iss,line);
+ if(line == "dOnE")return;
+ b->loc.y = std::stoi(line);
+ }
+
+ for(auto &m : mob){
+ std::getline(iss,line);
+ if(line == "dOnE")return;
+ m->loc.x = std::stoi(line);
+ std::getline(iss,line);
+ if(line == "dOnE")return;
+ m->loc.y = std::stoi(line);
+ std::getline(iss,line);
+ if(line == "dOnE")return;
+ m->alive = std::stoi(line);
+ }
+
+ while(std::getline(iss,line)){
+ if(line == "dOnE")
+ break;
+ }
+
+ delete[] filedata;
}
+/**
+ * Toggle play/stop of the background music.
+ * If new music is to be played a crossfade will occur, otherwise... uhm.
+ */
void World::
-addParticle(float x, float y, float w, float h, float vx, float vy, Color color, int d)
+bgmPlay(World *prev) const
{
- particles.emplace_back(x, y, w, h, vx, vy, color, d);
- particles.back().canMove = true;
+ if (prev) {
+ if (bgm != prev->bgm) {
+ // new world, new music
+ Mix_FadeOutMusic(800);
+ Mix_PlayMusic(bgmObj, -1);
+ }
+ // sucks to be here
+ } else {
+ // first call
+ Mix_FadeOutMusic(800);
+ Mix_PlayMusic(bgmObj, -1);
+ }
}
+/**
+ * Set the world's BGM.
+ * This will load a sound file to be played while the player is in this world.
+ * If no file is found, no music should play.
+ */
void World::
-addParticle(float x, float y, float w, float h, float vx, float vy, Color color, int d, unsigned char flags)
+setBGM(std::string path)
{
- particles.emplace_back(x, y, w, h, vx, vy, color, d);
- particles.back().canMove = true;
- particles.back().gravity = flags & (1 << 0);
- particles.back().bounce = flags & (1 << 1);
+ if (!path.empty())
+ bgmObj = Mix_LoadMUS((bgm = path).c_str());
}
+/**
+ * Sets the desired theme for the world's background.
+ * The images chosen for the background layers are selected depending on the
+ * world's background type.
+ */
void World::
-addLight(vec2 loc, Color color)
+setBackground(WorldBGType bgt)
{
- if (light.size() < 64)
- light.push_back(Light(loc, color, 1));
+ // load textures with a limit check
+ switch ((bgType = bgt)) {
+ case WorldBGType::Forest:
+ bgTex = new Texturec(bgFiles);
+ break;
+ case WorldBGType::WoodHouse:
+ bgTex = new Texturec(bgFilesIndoors);
+ break;
+ default:
+ UserError("Invalid world background type");
+ break;
+ }
}
-Light *World::
-getLastLight(void)
+/**
+ * Sets the world's style.
+ * The world's style will determine what sprites are used for things like\
+ * generic structures.
+ */
+void World::
+setStyle(std::string pre)
{
- return &light.back();
-}
+ // get folder prefix
+ std::string prefix = pre.empty() ? "assets/style/classic/" : pre;
-Mob *World::
-getLastMob(void)
-{
- return &mob.back();
-}
+ for_each(std::begin(buildPaths), std::end(buildPaths), [this, prefix](std::string s){
+ sTexLoc.push_back(prefix + s);
+ });
-std::string World::
-getSTextureLocation(unsigned int index) const
-{
- if (index > sTexLoc.size())
- return "";
+ prefix += "bg/";
- return sTexLoc[ index ];
+ for_each(std::begin(bgPaths[0]), std::end(bgPaths[0]), [this, prefix](std::string s){
+ bgFiles.push_back(prefix + s);
+ });
+ for_each(std::begin(bgPaths[1]), std::end(bgPaths[1]), [this, prefix](std::string s){
+ bgFilesIndoors.push_back(prefix + s);
+ });
}
+/**
+ * Pretty self-explanatory.
+ */
std::string World::
setToLeft(std::string file)
{
return (toLeft = file);
}
+/**
+ * Pretty self-explanatory.
+ */
std::string World::
setToRight(std::string file)
{
return (toRight = file);
}
+/**
+ * Pretty self-explanatory.
+ */
std::string World::
getToLeft(void) const
{
return toLeft;
}
+/**
+ * Pretty self-explanatory.
+ */
std::string World::
getToRight(void) const
{
return toRight;
}
+/**
+ * Attempts to go to the left world, returning either that world or itself.
+ */
World *World::
goWorldLeft(Player *p)
{
@@ -1080,7 +1065,6 @@ goWorldLeft(Player *p)
// check if player is at world edge
if (!toLeft.empty() && p->loc.x < worldStart + HLINE * 15.0f) {
-
// load world (`toLeft` conditional confirms existance)
tmp = loadWorldFromPtr(currentWorldToLeft);
@@ -1094,24 +1078,9 @@ goWorldLeft(Player *p)
return this;
}
-bool World::
-goWorldLeft(NPC *e)
-{
- // check if entity is at world edge
- if (!toLeft.empty() && e->loc.x < worldStart + HLINE * 15.0f) {
-
- currentWorldToLeft->addNPC(e->loc.x,e->loc.y);
- e->alive = false;
-
- currentWorldToLeft->npc.back()->loc.x = 0;
- currentWorldToLeft->npc.back()->loc.y = GROUND_HEIGHT_MAXIMUM;
-
- return true;
- }
-
- return false;
-}
-
+/**
+ * Attempts to go to the right world, returning either that world or itself.
+ */
World *World::
goWorldRight(Player *p)
{
@@ -1129,6 +1098,29 @@ goWorldRight(Player *p)
return this;
}
+/**
+ * Acts like goWorldLeft(), but takes an NPC; returning true on success.
+ */
+bool World::
+goWorldLeft(NPC *e)
+{
+ // check if entity is at world edge
+ if(!toLeft.empty() && e->loc.x < worldStart + HLINE * 15.0f) {
+ currentWorldToLeft->addNPC(e->loc.x,e->loc.y);
+ e->alive = false;
+
+ currentWorldToLeft->npc.back()->loc.x = 0;
+ currentWorldToLeft->npc.back()->loc.y = GROUND_HEIGHT_MAXIMUM;
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Attempts to enter a building that the player is standing in front of.
+ */
World *World::
goInsideStructure(Player *p)
{
@@ -1137,21 +1129,20 @@ goInsideStructure(Player *p)
if (inside.empty()) {
for (auto &b : build) {
- if (p->loc.x > b->loc.x &&
- p->loc.x + p->width < b->loc.x + b->width) {
-
+ if (p->loc.x > b->loc.x && p->loc.x + p->width < b->loc.x + b->width) {
if (b->inside.empty())
return this;
+ // +size cuts folder prefix
inside.push_back(currentXML.c_str() + xmlFolder.size());
-
tmp = loadWorldFromXML(b->inside);
+ // make the fade, as we let it fade back the worlds should be switched
ui::toggleBlackFast();
ui::waitForCover();
ui::toggleBlackFast();
- glClearColor(0,0,0,1);
+ glClearColor(0, 0, 0, 1);
return tmp;
}
@@ -1165,12 +1156,10 @@ goInsideStructure(Player *p)
ui::toggleBlackFast();
ui::waitForCover();
-
p->loc.x = b->loc.x + (b->width / 2);
-
ui::toggleBlackFast();
- glClearColor(1,1,1,1);
+ glClearColor(1, 1, 1, 1);
return tmp;
}
@@ -1180,6 +1169,88 @@ goInsideStructure(Player *p)
return this;
}
+void World::addStructure(BUILD_SUB sub, float x,float y, std::string tex, std::string inside){
+ build.push_back(new Structures());
+ build.back()->inWorld = this;
+ build.back()->textureLoc = tex;
+
+ build.back()->spawn(sub,x,y);
+
+ build.back()->inside = inside;
+
+ entity.push_back(build.back());
+}
+
+Village *World::
+addVillage(std::string name, World *world)
+{
+ village.emplace_back(name.c_str(), world);
+ return &village.back();
+}
+
+void World::addMob(int t,float x,float y){
+ mob.push_back(new Mob(t));
+ mob.back()->spawn(x,y);
+
+ entity.push_back(mob.back());
+}
+
+void World::addMob(int t,float x,float y,void (*hey)(Mob *)){
+ mob.push_back(new Mob(t));
+ mob.back()->spawn(x,y);
+ mob.back()->hey = hey;
+
+ entity.push_back(mob.back());
+}
+
+void World::addNPC(float x,float y){
+ npc.push_back(new NPC());
+ npc.back()->spawn(x,y);
+
+ entity.push_back(npc.back());
+}
+
+void World::addMerchant(float x, float y, bool housed){
+ merchant.push_back(new Merchant());
+ merchant.back()->spawn(x,y);
+
+ if (housed)
+ merchant.back()->inside = build.back();
+
+ npc.push_back(merchant.back());
+ entity.push_back(npc.back());
+}
+
+void World::addObject(std::string in, std::string p, float x, float y){
+ object.emplace_back(in, p);
+ object.back().spawn(x, y);
+
+ entity.push_back(&object.back());
+}
+
+void World::
+addParticle(float x, float y, float w, float h, float vx, float vy, Color color, int d)
+{
+ particles.emplace_back(x, y, w, h, vx, vy, color, d);
+ particles.back().canMove = true;
+}
+
+void World::
+addParticle(float x, float y, float w, float h, float vx, float vy, Color color, int d, unsigned char flags)
+{
+ particles.emplace_back(x, y, w, h, vx, vy, color, d);
+ particles.back().canMove = true;
+ particles.back().gravity = flags & (1 << 0);
+ particles.back().bounce = flags & (1 << 1);
+}
+
+void World::
+addLight(vec2 loc, Color color)
+{
+ if (light.size() < 64)
+ light.push_back(Light(loc, color, 1));
+}
+
void World::
addHole(unsigned int start, unsigned int end)
{
@@ -1193,7 +1264,9 @@ addHole(unsigned int start, unsigned int end)
void World::
addHill(const ivec2 peak, const unsigned int width)
{
- int start = peak.x - width / 2, end = start + width, offset = 0;
+ int start = peak.x - width / 2,
+ end = start + width,
+ offset = 0;
const float thing = peak.y - worldData[start].groundHeight;
const float period = PI / width;
@@ -1212,95 +1285,6 @@ addHill(const ivec2 peak, const unsigned int width)
}
}
-int World::
-getTheWidth(void) const
-{
- return worldStart * -2;
-}
-
-void World::save(void) {
- std::string data;
-
- std::string save = (std::string)currentXML + ".dat";
- std::ofstream out (save,std::ios::out | std::ios::binary);
-
- std::cout<<"Saving to "<<save<<" ..."<<std::endl;
-
- for(auto &n : npc) {
- data.append(std::to_string(n->dialogIndex) + "\n");
- data.append(std::to_string((int)n->loc.x) + "\n");
- data.append(std::to_string((int)n->loc.y) + "\n");
- }
-
- for(auto &b : build) {
- data.append(std::to_string((int)b->loc.x) + "\n");
- data.append(std::to_string((int)b->loc.y) + "\n");
- }
-
- for(auto &m : mob) {
- data.append(std::to_string((int)m.loc.x) + "\n");
- data.append(std::to_string((int)m.loc.y) + "\n");
- data.append(std::to_string((int)m.alive) + "\n");
- }
-
- data.append("dOnE\0");
- out.write(data.c_str(),data.size());
- out.close();
-}
-
-void World::load(void) {
- std::string save,data,line;
- const char *filedata;
-
- save = std::string(currentXML + ".dat");
- filedata = readFile(save.c_str());
- data = filedata;
- std::istringstream iss (data);
-
- for(auto &n : npc) {
- std::getline(iss,line);
- if (line == "dOnE")return;
- if ((n->dialogIndex = std::stoi(line)) != 9999)
- n->addAIFunc(commonAIFunc,false);
- else n->clearAIFunc();
-
- std::getline(iss,line);
- if (line == "dOnE")return;
- n->loc.x = std::stoi(line);
- std::getline(iss,line);
- if (line == "dOnE")return;
- n->loc.y = std::stoi(line);
- }
-
- for(auto &b : build) {
- std::getline(iss,line);
- if (line == "dOnE")return;
- b->loc.x = std::stoi(line);
- std::getline(iss,line);
- if (line == "dOnE")return;
- b->loc.y = std::stoi(line);
- }
-
- for(auto &m : mob) {
- std::getline(iss,line);
- if (line == "dOnE")return;
- m.loc.x = std::stoi(line);
- std::getline(iss,line);
- if (line == "dOnE")return;
- m.loc.y = std::stoi(line);
- std::getline(iss,line);
- if (line == "dOnE")return;
- m.alive = std::stoi(line);
- }
-
- while(std::getline(iss,line)) {
- if (line == "dOnE")
- break;
- }
-
- delete[] filedata;
-}
-
float getIndoorWorldFloorHeight(void)
{
return INDOOR_FLOOR_HEIGHTT + INDOOR_FLOOR_THICKNESS;
@@ -1530,8 +1514,8 @@ Arena::Arena(World *leave,Player *p,Mob *m) {
mmob = m;
mmob->aggressive = false;
- mob.push_back(*m);
- entity.push_back(&mob.back());
+ mob.push_back(m);
+ entity.push_back(mob.back());
battleNest.push_back(leave);
battleNestLoc.push_back(p->loc);
@@ -1544,8 +1528,8 @@ Arena::~Arena(void) {
World *Arena::exitArena(Player *p) {
World *tmp;
if (!mmob->alive &&
- p->loc.x + p->width / 2 > mob[0].loc.x &&
- p->loc.x + p->width / 2 < mob[0].loc.x + HLINE * 12) {
+ p->loc.x + p->width / 2 > mob[0]->loc.x &&
+ p->loc.x + p->width / 2 < mob[0]->loc.x + HLINE * 12) {
tmp = battleNest.front();
battleNest.erase(battleNest.begin());
@@ -1842,9 +1826,7 @@ loadWorldFromXMLNoSave(std::string path) {
vil->StrAttribute("texture"),
vil->StrAttribute("inside")
);
- tmp->addMerchant(0, 100);
-
- tmp->merchant.back()->inside = tmp->build.back();
+ tmp->addMerchant(0, 100, true);
}
// handle traders
@@ -1900,15 +1882,13 @@ loadWorldFromXMLNoSave(std::string path) {
}
}
- vptr->build.push_back(tmp->build.back());
+ float buildx = tmp->getStructurePos(-1).x;
- if (vptr->build.back()->loc.x < vptr->start.x) {
- vptr->start.x = vptr->build.back()->loc.x;
- }
+ if (buildx < vptr->start.x)
+ vptr->start.x = buildx;
- if (vptr->build.back()->loc.x + vptr->build.back()->width > vptr->end.x) {
- vptr->end.x = vptr->build.back()->loc.x + vptr->build.back()->width;
- }
+ if (buildx > vptr->end.x)
+ vptr->end.x = buildx;
//go to the next element in the village block
vil = vil->NextSiblingElement();