aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClyne Sullivan <tullivan99@gmail.com>2016-04-23 22:31:27 -0400
committerClyne Sullivan <tullivan99@gmail.com>2016-04-23 22:31:27 -0400
commitcc2230e0039f06a7478878adcbc9ef028a223243 (patch)
tree1af80e53bc7f6ec6fa7c7d4f89656d61f203808f
parentdebb080a17eba2b2957e99ba7f1ce0fa0c4d2e4e (diff)
more rewrites
-rw-r--r--include/common.hpp5
-rw-r--r--include/entities.hpp348
-rw-r--r--include/ui.hpp2
-rw-r--r--include/world.hpp30
-rw-r--r--main.cpp97
-rw-r--r--src/entities.cpp164
-rw-r--r--src/gameplay.cpp292
-rw-r--r--src/inventory.cpp11
-rw-r--r--src/ui.cpp50
-rw-r--r--src/ui_action.cpp6
-rw-r--r--src/world.cpp182
-rw-r--r--xcf/cat.xcfbin0 -> 1900 bytes
12 files changed, 654 insertions, 533 deletions
diff --git a/include/common.hpp b/include/common.hpp
index 310bf7f..9211d56 100644
--- a/include/common.hpp
+++ b/include/common.hpp
@@ -98,6 +98,11 @@ struct _vec2 {
bool operator==(const _vec2 &v) {
return (x == v.x) && (y == v.y);
}
+ template<typename T>
+ const _vec2 operator=(const T &n) {
+ x = y = n;
+ return *this;
+ }
};
typedef struct _vec2 vec2;
diff --git a/include/entities.hpp b/include/entities.hpp
index 4a2420e..460dc93 100644
--- a/include/entities.hpp
+++ b/include/entities.hpp
@@ -1,197 +1,339 @@
+/* ----------------------------------------------------------------------------
+** The entity stuffs.
+**
+** Entities.
+** --------------------------------------------------------------------------*/
#ifndef ENTITIES_H
#define ENTITIES_H
+#define DEBUG
+
+/* ----------------------------------------------------------------------------
+** Includes section
+** --------------------------------------------------------------------------*/
+// local game includes
#include <common.hpp>
#include <quest.hpp>
#include <inventory.hpp>
#include <texture.hpp>
-#include <sstream>
-
-#define DEBUG
-
-#define NPCp(n) ((NPC *)n)
-#define Structurep(n) ((Structures *)n)
-#define Mobp(n) ((Mob *)n)
-
-#define PLAYER_INV_SIZE 43 // The size of the player's inventory
-#define NPC_INV_SIZE 3 // Size of an NPC's inventory
+/* ----------------------------------------------------------------------------
+** Structures section
+** --------------------------------------------------------------------------*/
+/**
+ * An entity type enumerator for identifying entities.
+ */
enum _TYPE {
- OBJECTT = -2,
- STRUCTURET,
- PLAYERT,
- NPCT,
- MERCHT,
- MOBT
+ OBJECTT = -2, /**< an object (Object) */
+ STRUCTURET, /**< a structure (Structures *) */
+ PLAYERT, /**< the player (Player *) */
+ NPCT, /**< an NPC (NPC *) */
+ MERCHT, /**< a merchant (Merchant *) */
+ MOBT /**< A mob (Mob *) */
};
+/**
+ * An enumerator for entity gender.
+ */
enum GENDER{
- MALE,
- FEMALE
+ MALE, /**< male */
+ FEMALE /**< female */
};
+/**
+ * An enumerator for mob types.. 'species'.
+ * The subtype of a Mob will affect what texture is used to draw it as well as
+ * how the Mob will behave.
+ */
enum MOB_SUB {
- MS_RABBIT = 1,
- MS_BIRD,
- MS_TRIGGER,
- MS_DOOR,
- MS_PAGE
+ MS_RABBIT = 1, /**< rabbits */
+ MS_BIRD, /**< birds */
+ MS_TRIGGER, /**< triggers, used to cue cutscenes */
+ MS_DOOR, /**< doors, for exiting arenas */
+ MS_PAGE /**< pages, cues page overlay */
};
+/**
+ * An enumerator for strcture types.
+ * The subtype of a structure will affect how it is drawn and how it functions.
+ */
enum BUILD_SUB{
- TOWN_HALL = 0,
- HOUSE = 1,
- HOUSE2 = 2,
- HOUSE3 = 3,
- HOUSE4 = 4,
- FOUNTAIN = 5,
- LAMP_POST = 6,
- FIRE_PIT = 7,
- STALL_MARKET = 70,
- STALL_TRADER = 71
+ TOWN_HALL = 0, /**< a town hall */
+ HOUSE, /**< a generic house */
+ HOUSE2, /**< a generic house of a different style */
+ HOUSE3, /**< a generic house of a different style */
+ HOUSE4, /**< a generic house of a different style */
+ FOUNTAIN, /**< a fountain, creates water particles */
+ LAMP_POST, /**< a lamppost, creates light */
+ FIRE_PIT, /**< a firepit, creates fire particles / light */
+ STALL_MARKET = 70, /**< a stall for a merchant */
+ STALL_TRADER /**< TODO */
};
-class Trade{
-public:
+/**
+ * A structure for tracking potential trades between the player and a merchant.
+ */
+struct Trade {
+ // the names of the items up for trade
std::string item[2];
+ // how much of each item to trade
int quantity[2];
- Trade(int qo, std::string o, int qt, std::string t);
- Trade() {}
+
+ // constructs a trade with the given values
+ Trade(int qo, std::string o, int qt, std::string t) {
+ item[0] = o;
+ item[1] = t;
+ quantity[0] = qo;
+ quantity[1] = qt;
+ }
+
+ // creates an empty trade item
+ Trade(void) {
+ item[0] = "";
+ item[1] = "";
+ quantity[0] = 0;
+ quantity[1] = 0;
+ }
};
+typedef struct Trade Trade;
+
+/* ----------------------------------------------------------------------------
+** Variables section
+** --------------------------------------------------------------------------*/
+// the size of the player's inventory
+extern const unsigned int PLAYER_INV_SIZE;
+// the size of an NPC's inventory
+extern const unsigned int NPC_INV_SIZE;
+
+/* ----------------------------------------------------------------------------
+** Classes / function prototypes section
+** --------------------------------------------------------------------------*/
+
+// a prototype of the world class, necessary for some function prototypes
class World;
+/**
+ * The particle class, handles a single particle.
+ */
class Particles{
public:
+ // the location of the particle
vec2 loc;
+
+ // the width of the particle, in pixels
float width;
+
+ // the height of the particle, in pixels
float height;
+
+ // the velocity of the particle, in pixels
vec2 vel;
+
+ // the color of the particle
Color color;
+
+ // TODO
vec2 index;
+
+ // the amount of milliseconds left for the particle to live
float duration;
+
+ // when true, the particle will move
bool canMove;
+
+ // TODO
bool fountain;
+
+ // when true, the particle will be affected by gravity
bool gravity;
+
+ // when true, draws the particle behind structures
bool behind;
+
+ // when true, the particle will bounce on impact with ground
bool bounce;
- Particles(float x, float y, float w, float h, float vx, float vy, Color c, float d) {
- loc.x = x;
- loc.y = y;
- vel.x = vx;
- vel.y = vy;
+
+ // creates a particle with the desired characteristics
+ 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;
- fountain = false;
gravity = true;
+ fountain = false;
behind = false;
bounce = false;
index = Texture::getIndex(c);
}
- ~Particles() {
- }
- void draw() {
- glColor3ub(255,255,255);
+
+ // allows the particle to be destroyed
+ ~Particles(void){}
+
+ // draws the particle
+ void draw(void) const {
+ glColor3ub(255, 255, 255);
glBegin(GL_QUADS);
- glTexCoord2f(.25*index.x, .125*index.y); glVertex2i(loc.x, loc.y);
- glTexCoord2f(.25*index.x, .125*index.y); glVertex2i(loc.x + width, loc.y);
- glTexCoord2f(.25*index.x, .125*index.y); glVertex2i(loc.x + width, loc.y + height);
- glTexCoord2f(.25*index.x, .125*index.y); glVertex2i(loc.x, loc.y + width);
+ vec2 tc = vec2 {0.25f * index.x, 0.125f * index.y};
+ glTexCoord2f(tc.x, tc.y); glVertex2i(loc.x , loc.y);
+ glTexCoord2f(tc.x, tc.y); glVertex2i(loc.x + width, loc.y);
+ glTexCoord2f(tc.x, tc.y); glVertex2i(loc.x + width, loc.y + height);
+ glTexCoord2f(tc.x, tc.y); glVertex2i(loc.x , loc.y + height);
glEnd();
}
+
+ // updates a particle
void update(float _gravity, float ground_y) {
// handle ground collision
if (loc.y < ground_y) {
loc.y = ground_y;
+
+ // handle bounce
if (bounce) {
vel.y *= -0.2f;
- vel.x /= 4;
+ vel.x /= 4.0f;
} else {
- vel.x = vel.y = 0;
+ vel = 0.0f;
canMove = false;
}
- } else if (gravity && vel.y > -1)
+ }
+
+ // handle gravity
+ else if (gravity && vel.y > -1.0f) {
vel.y -= _gravity * deltaTime;
+ }
}
+
+ // returns true if the particle should be killed
bool kill(float delta) {
return (duration -= delta) <= 0;
}
};
-void initEntity();
-
+/**
+ * The entity class.
+ * This class contains common functions and variables for all types of
+ * entities, i.e. a common structure.
+ */
class Entity{
-public:
+protected:
+ // an incrementer for invincibility after a hit
+ unsigned int hitCooldown;
+
+ // an incrementer for triggering change of movement with wander()
+ int ticksToUse;
+
+ // entity handles an applied hit (sword) if set true
+ bool forcedMove;
+
+ // if set false, entity will be destroyed
+ bool alive;
+
+ // if not null, the entity will move towards this one
Entity *followee;
- Inventory *inv;
- /*
- * Movement variables
- */
+ // TODO
+ float targetx;
+public:
+ // contains the entity's coordinates, in pixels
vec2 loc;
+
+ // contains the entity's velocity, in pixels
vec2 vel;
+ // the entity's width, in pixels
float width;
+
+ // the entity's height, in pixels
float height;
- float speed; // A speed factor for X movement
+ // a speed multiplier, applied to velocity
+ float speed;
- unsigned int hitCooldown;
+ // when true player may interact, and the entity's name will be drawn
+ bool near;
+
+ // when true, the entity can move
+ bool canMove;
- /*
- * Movement flags
- */
+ // tells direction entity is facing
+ bool right, left;
- bool near; // Causes name to display
- bool canMove; // Enables movement
- bool right,left; // Direction faced by Entity
- bool alive;
- bool hit;
- bool forcedMove;
- unsigned char ground; // Shows how the Entity is grounded (if it is)
+ // set to 1 if entity is on the ground, 0 if in the air
+ unsigned char ground;
- /*
- * Health variables
- */
+ // the entity's inventory
+ Inventory *inv;
+ // the entity's health
float health;
- float maxHealth;
- /*
- * Identification variables
- */
+ // the most health the entity can have
+ float maxHealth;
+ // the type of the entity
_TYPE type;
- int subtype;
- char *name;
+ // the entity's subtype, if applicable
+ int subtype;
+
+ // the entity's name, randomly generated on spawn
+ char *name;
+
+ // the entity's gender
GENDER gender;
+ // a texture handler for the entity
Texturec *tex;
- Texturec *ntex;
- float targetx;
-
- unsigned int randDialog;
+ // TODO
+ Texturec *ntex;
+ // draws the entity to the screen
void draw(void);
+
+ // spawns the entity at the given coordinates
void spawn(float, float);
- int ticksToUse; // Used by wander()
+ // allows the entity to wander, according to what class is deriving this.
+ virtual void wander(int){}
+
+ // allows the entity to interact with the player
+ virtual void interact(void){}
- virtual void wander(int) {}
- virtual void interact() {}
+ // causes the entity to move to the given x coordinate
+ void moveTo(float dest_x);
+ // causes the entity to follow the one provided
void follow(Entity *e);
+ // causes the entity to take a player-inflicted hit
+ void takeHit(unsigned int _health, unsigned int cooldown);
+
+ // handles hits if they've been taken
+ void handleHits(void);
+
+ // insures that the entity is dead
+ void die(void);
+
+ // checks if the entity is alive
+ bool isAlive(void) const;
+
+ // checks if the entity is hit in some way
+ bool isHit(void) const;
+
+ // returns true if this entity is near the one provided
bool isNear(Entity e);
+
+ // returns true if the coordinate is within the entity
bool isInside(vec2 coord) const;
- virtual ~Entity() {}
+ // frees memory taken by the entity
+ virtual ~Entity(){}
};
class Player : public Entity{
@@ -219,16 +361,22 @@ public:
class NPC : public Entity {
+private:
+ // the number of the random dialog to use
+ unsigned int randDialog;
+
+ unsigned int dialogCount;
+
public:
- std::vector<int (*)(NPC *)>aiFunc;
int dialogIndex;
NPC();
- NPC(NPC *n);
~NPC();
- void addAIFunc(int (*func)(NPC *),bool preload);
- void clearAIFunc(void);
+ void drawThingy(void) const;
+
+ void addAIFunc(bool preload);
+
virtual void interact();
virtual void wander(int);
};
@@ -329,6 +477,18 @@ constexpr Object *Objectp(Entity *e) {
return (Object *)e;
}
+constexpr NPC *NPCp(Entity *e) {
+ return (NPC *)e;
+}
+
+constexpr Structures *Structurep(Entity *e) {
+ return (Structures *)e;
+}
+
+constexpr Mob *Mobp(Entity *e) {
+ return (Mob *)e;
+}
+
#endif // ENTITIES_H
/**
diff --git a/include/ui.hpp b/include/ui.hpp
index 144a87e..477c9c3 100644
--- a/include/ui.hpp
+++ b/include/ui.hpp
@@ -108,7 +108,7 @@ namespace ui {
*/
void drawBox(vec2 c1, vec2 c2);
- void dialogBox(const char *name,const char *opt,bool passive,const char *text,...);
+ void dialogBox(std::string name, std::string opt, bool passive, std::string text, ...);
void merchantBox(const char *name,Trade trade,const char *opt,bool passive,const char *text,...);
void merchantBox();
void closeBox();
diff --git a/include/world.hpp b/include/world.hpp
index 9a1d701..c6eaf06 100644
--- a/include/world.hpp
+++ b/include/world.hpp
@@ -11,7 +11,7 @@
** Includes section
** --------------------------------------------------------------------------*/
-// 'local' game includes
+// local game includes
#include <common.hpp>
#include <entities.hpp>
@@ -85,8 +85,8 @@ public:
vec2 start, end;
bool in;
- Village(const char *meme, World *w);
- ~Village(void) {}
+ Village(std::string meme, World *w);
+ ~Village(void){}
};
/**
@@ -248,30 +248,46 @@ public:
Village *addVillage(std::string name, World *world);
};
-/*
- * IndoorWorld - Indoor settings stored in a World class
+/**
+ * IndoorWorld - Indoor settings stored in a World class
*/
-
class IndoorWorld : public World {
private:
+ // like lines, but split into floors
std::vector<std::vector<float>> floor;
+
+ // the x coordinate to start each floor at
std::vector<float> fstart;
+ // handles physics for a single entity
void singleDetect(Entity *e);
public:
+
+ // creates an IndoorWorld object
IndoorWorld(void);
+
+ // frees memory used by this object
~IndoorWorld(void);
+ // adds a floor of the desired width
void addFloor(unsigned int width);
+
+ // adds a floor at the desired x coordinate with the given width
void addFloor(unsigned int width, unsigned int start);
+
+ // attempts to move the entity provided to the given floor
bool moveToFloor(Entity *e, unsigned int _floor);
+ // checks for a floor above the given entity
bool isFloorAbove(Entity *e);
+
+ // checks for a floor below the given entity
bool isFloorBelow(Entity *e);
- void draw(Player *p); // Draws the world (ignores layers)
+ // draws the world about the player
+ void draw(Player *p);
};
/**
diff --git a/main.cpp b/main.cpp
index 8e07818..fa72494 100644
--- a/main.cpp
+++ b/main.cpp
@@ -287,10 +287,7 @@ int main(int argc, char *argv[]){
SDL_ShowCursor(SDL_DISABLE);
- //glEnable(GL_CULL_FACE);
-
Texture::initColorIndex();
- initEntity();
/*
* Initializes our shaders so that the game has shadows.
@@ -682,73 +679,57 @@ void logic(){
if (player->inv->usingi) {
for (auto &e : currentWorld->entity) {
- e->hit = false;
-
- if (player->inv->usingi && !e->hit &&
- player->inv->detectCollision({ e->loc.x, e->loc.y }, { e->loc.x + e->width, e->loc.y + e->height})) {
- e->health -= 25;
- e->hit = true;
- e->forcedMove = true;
- e->hitCooldown = 10;
- e->vel.x = 0.5f * (player->left ? -1 : 1);
- e->vel.y = 0.2f;
+ if (player->inv->usingi && !e->isHit() &&
+ player->inv->detectCollision(vec2 { e->loc.x, e->loc.y }, vec2 { e->loc.x + e->width, e->loc.y + e->height})) {
+ e->takeHit(25, 10);
break;
- //for(int r = 0; r < (rand()%5);r++)
- // currentWorld->addParticle(rand()%HLINE*3 + n->loc.x - .05f,n->loc.y + n->height*.5, HLINE,HLINE, -(rand()%10)*.01,((rand()%4)*.001-.002), {(rand()%75+10)/100.0f,0,0}, 10000);
- //if (e->health <= 0) {
- //for(int r = 0; r < (rand()%30)+15;r++)
- // currentWorld->addParticle(rand()%HLINE*3 + n->loc.x - .05f,n->loc.y + n->height*.5, HLINE,HLINE, -(rand()%10)*.01,((rand()%10)*.01-.05), {(rand()%75)+10/100.0f,0,0}, 10000);
}
}
player->inv->usingi = false;
}
for (auto &e : currentWorld->entity) {
- if (e->alive) {
- if (e->type == NPCT || e->type == MERCHT || e->type == OBJECTT) {
-
- if (e->type == OBJECTT && ObjectSelected) {
+ if (e->isAlive() && ((e->type == NPCT) || (e->type == MERCHT) || (e->type == OBJECTT))) {
+ if (e->type == OBJECTT && ObjectSelected) {
+ e->near = false;
+ continue;
+ } else if (e->canMove) {
+ e->wander((rand() % 120 + 30));
+ if (NPCSelected) {
e->near = false;
continue;
- } else { // has to be NPC
- if (e->canMove) {
- e->wander((rand() % 120 + 30));
- if (NPCSelected) {
- e->near = false;
- continue;
- }
- }
}
+ }
- if(e->isInside(ui::mouse) && player->isNear(*e)) {
- if (e->type == OBJECTT)
- ObjectSelected = true;
- else
- NPCSelected = true;
- e->near = true;
+ if(e->isInside(ui::mouse) && player->isNear(*e)) {
+ e->near = true;
+ if (e->type == OBJECTT)
+ ObjectSelected = true;
+ else
+ NPCSelected = true;
+
+ if ((SDL_GetMouseState(NULL, NULL) & SDL_BUTTON(SDL_BUTTON_RIGHT)) && !ui::dialogBoxExists)
+ e->interact();
+ } else {
+ e->near = false;
+ }
+ } else if (e->type == MOBT) {
+ e->near = player->isNear(*e);
- if ((SDL_GetMouseState(NULL, NULL) & SDL_BUTTON(SDL_BUTTON_RIGHT)) && !ui::dialogBoxExists)
- e->interact();
- } else
- e->near = false;
- } else if (e->type == MOBT) {
- e->near = player->isNear(*e);
-
- switch (e->subtype) {
- case MS_RABBIT:
- case MS_BIRD:
- e->wander((rand()%240 + 15));
- break;
- case MS_TRIGGER:
- case MS_PAGE:
- e->wander(0);
- break;
- case MS_DOOR:
- break;
- default:
- std::cout<<"Unhandled mob of subtype "<<e->subtype<<"."<<std::endl;
- break;
- }
+ switch (e->subtype) {
+ case MS_RABBIT:
+ case MS_BIRD:
+ e->wander((rand()%240 + 15));
+ break;
+ case MS_TRIGGER:
+ case MS_PAGE:
+ e->wander(0);
+ break;
+ case MS_DOOR:
+ break;
+ default:
+ std::cout<<"Unhandled mob of subtype "<<e->subtype<<"."<<std::endl;
+ break;
}
}
}
diff --git a/src/entities.cpp b/src/entities.cpp
index 96fe0e6..16ba768 100644
--- a/src/entities.cpp
+++ b/src/entities.cpp
@@ -1,6 +1,8 @@
+#include <entities.hpp>
+
#include <istream>
+#include <sstream>
-#include <entities.hpp>
#include <ui.hpp>
extern std::istream *names;
@@ -12,13 +14,15 @@ extern unsigned int tickCount; // main.cpp
extern std::string xmlFolder;
-GLuint waterTex;
-
-std::vector<int (*)(NPC *)> AIpreload; // A dynamic array of AI functions that are being preloaded
-std::vector<NPC *> AIpreaddr; // A dynamic array of pointers to the NPC's that are being assigned the preloads
+// a dynamic array of pointers to the NPC's that are being assigned the preloads
+std::vector<NPC *> aipreload;
-#define RAND_DIALOG_COUNT 14
+// 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 const unsigned int RAND_DIALOG_COUNT = 14;
const char *randomDialog[RAND_DIALOG_COUNT] = {
"What a beautiful day it is.",
"Have you ever went fast? I have.",
@@ -36,11 +40,8 @@ const char *randomDialog[RAND_DIALOG_COUNT] = {
"What's a bagel? I don't know because I'm mormon"
};
-void initEntity() {
- waterTex = Texture::loadTexture("assets/waterTex.png");
-}
-
-void getRandomName(Entity *e) {
+void getRandomName(Entity *e)
+{
unsigned int tempNum,max=0;
char *bufs;
@@ -76,17 +77,9 @@ void getRandomName(Entity *e) {
delete[] bufs;
}
-Trade::Trade(int qo, std::string o, int qt, std::string t) {
- item[0] = o;
- item[1] = t;
-
- quantity[0] = qo;
- quantity[1] = qt;
-
- std::cout << "Trading: " << quantity[0] << " " << item[0] << " for " << quantity[1] << " " << item[1] << std::endl;
-}
-
-void Entity::spawn(float x, float y) { //spawns the entity you pass to it based off of coords and global entity settings
+// 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;
vel.x = 0;
@@ -99,7 +92,6 @@ void Entity::spawn(float x, float y) { //spawns the entity you pass to it based
near = false;
//canMove = true;
ground = false;
- hit = false;
forcedMove = false;
ticksToUse = 0;
@@ -122,7 +114,52 @@ void Entity::spawn(float x, float y) { //spawns the entity you pass to it based
followee = NULL;
}
-Player::Player() { //sets all of the player specific traits on object creation
+void Entity::takeHit(unsigned int _health, unsigned int cooldown)
+{
+ // modify variables
+ health = fmax(health - _health, 0);
+ forcedMove = true;
+ hitCooldown = cooldown;
+
+ // pushback
+ vel.x = player->left ? -0.5f : 0.5f;
+ vel.y = 0.2f;
+}
+
+void Entity::handleHits(void)
+{
+ 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;
+}
+
+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(){ //sets all of the player specific traits on object creation
width = HLINE * 10;
height = HLINE * 16;
@@ -168,11 +205,8 @@ NPC::NPC() { //sets all of the NPC specific traits on object creation
dialogIndex = 0;
}
-NPC::~NPC() {
- while(!aiFunc.empty()) {
- aiFunc.pop_back();
- }
-
+NPC::~NPC()
+{
delete inv;
delete tex;
delete[] name;
@@ -268,6 +302,7 @@ Mob::Mob(int sub) {
inv = new Inventory(NPC_INV_SIZE);
}
+
Mob::~Mob() {
delete inv;
delete tex;
@@ -322,23 +357,30 @@ bool Entity::isNear(Entity e) {
return pow(e.loc.x - loc.x, 2) + pow(e.loc.y - loc.y, 2) <= pow(40 * HLINE, 2);
}
-void Entity::draw(void) { //draws the entities
+void NPC::drawThingy(void) const
+{
+ if (dialogCount) {
+ auto w = width / 3;
+ glColor3ub(255, 255, 0);
+ glRectf(loc.x + w, loc.y + height, loc.x + w * 2, loc.y + height + w);
+ }
+}
+
+void Entity::draw(void)
+{
glPushMatrix();
glColor3ub(255,255,255);
if (!alive)
return;
- if (type==NPCT) {
- if (NPCp(this)->aiFunc.size()) {
- glColor3ub(255,255,0);
- glRectf(loc.x+width/3,loc.y+height,loc.x+width*2/3,loc.y+height+width/3);
- }
- if (gender == MALE) {
- glColor3ub(255,255,255);
- }else if (gender == FEMALE) {
- glColor3ub(255,105,180);
- }
+ if (type == NPCT) {
+ NPCp(this)->drawThingy();
+
+ if (gender == MALE)
+ glColor3ub(255, 255, 255);
+ else if (gender == FEMALE)
+ glColor3ub(255, 105, 180);
}
if (left) {
glScalef(-1.0f,1.0f,1.0f);
@@ -467,37 +509,31 @@ wander(int timeRun)
ticksToUse--;
}
-void NPC::addAIFunc(int (*func)(NPC *),bool preload) {
- if (preload) { // Preload AI functions so that they're given after
- // the current dialog box is closed
- AIpreload.push_back(func);
- AIpreaddr.push_back(this);
- }
- else aiFunc.push_back(func);
+void NPC::addAIFunc(bool preload)
+{
+ if (preload)
+ aipreload.push_back(this);
+ else
+ ++dialogCount;
}
-void NPC::clearAIFunc(void) {
- aiFunc.clear();
-}
+extern int commonAIFunc(NPC *speaker);
void NPC::interact() { //have the npc's interact back to the player
std::thread([this]{
- int (*func)(NPC *);
loc.y += 5;
canMove=false;
left = (player->loc.x < loc.x);
right = !left;
- if (aiFunc.size()) {
- func=aiFunc.front();
-
- if (!func(this)) {
- if (aiFunc.size())aiFunc.erase(aiFunc.begin());
- }
- }else{
- ui::dialogBox(name,NULL,false,randomDialog[randDialog]);
+ if (dialogCount && dialogIndex != 9999) {
+ if (!commonAIFunc(this))
+ dialogCount--;
+ } else {
+ ui::dialogBox(name, "", false, randomDialog[randDialog]);
}
+
ui::waitForDialog();
canMove=true;
}).detach();
@@ -588,8 +624,8 @@ void Merchant::interact() {
void Object::interact(void) {
std::thread([this]{
- if (questObject && alive) {
- ui::dialogBox(player->name, ":Yes:No", false, pickupDialog.c_str());
+ if(questObject && alive){
+ ui::dialogBox(player->name, ":Yes:No", false, pickupDialog);
ui::waitForDialog();
if (ui::dialogOptChosen == 1) {
player->inv->addItem(iname, 1);
@@ -763,10 +799,10 @@ void Player::save(void) {
for(auto &i : inv->items)
data.append(std::to_string((int)i.count) + "\n" + std::to_string((int)i.id) + "\n");
- data.append((std::string)(currentXML.c_str() + 4) + "\n");
+ data.append(std::string(currentXML.data() + 4) + "\n");
data.append("dOnE\0");
- out.write(data.c_str(),data.size());
+ out.write(data.data(),data.size());
out.close();
}
@@ -810,7 +846,7 @@ void Player::sspawn(float x,float y) {
}
std::getline(data,ddata);
- currentWorld = loadWorldFromXMLNoSave(ddata.c_str());
+ currentWorld = loadWorldFromXMLNoSave(ddata);
in.close();
}
diff --git a/src/gameplay.cpp b/src/gameplay.cpp
index e314be4..603ede7 100644
--- a/src/gameplay.cpp
+++ b/src/gameplay.cpp
@@ -14,10 +14,9 @@ extern Menu optionsMenu;
extern std::string xmlFolder;
-extern void mainLoop(void); // main.cpp
+extern std::vector<NPC *> aipreload;
-extern std::vector<NPC *> AIpreaddr; // entities.cpp
-extern std::vector<int (*)(NPC *)> AIpreload; // entities.cpp
+extern void mainLoop(void); // main.cpp
std::vector<XMLElement *> dopt;
@@ -27,197 +26,154 @@ inline void segFault() {
(*((int *)NULL))++;
}
-int commonAIFunc(NPC *speaker) {
+int commonAIFunc(NPC *speaker)
+{
XMLDocument xml;
XMLElement *exml,*oxml;
static unsigned int oldidx = 9999;
- const char *name;
+ std::string name;
unsigned int idx = 0;
bool stop = false;
- /*
- * Load the current world's XML file into memory for reading.
- */
-
+ // load the XML file and find the dialog tags
xml.LoadFile(currentXML.c_str());
exml = xml.FirstChildElement("Dialog");
- /*
- * Search for the correct dialog block.
- */
-
- while(strcmp(exml->Attribute("name"),speaker->name))
+ // search for the dialog block associated with this npc
+ while (exml->StrAttribute("name") != speaker->name)
exml = exml->NextSiblingElement();
+ // search for the desired text block
exml = exml->FirstChildElement();
-
- /*
- * Search for which text block should be used.
- */
-
- do{
- if (!strcmp(exml->Name(),"text")) {
- if (exml->UnsignedAttribute("id") == (unsigned)speaker->dialogIndex) {
-
- /*
- * Handle any quest tags
- */
-
- if ((oxml = exml->FirstChildElement("quest"))) {
- std::string qname;
-
- while (oxml) {
- if (!(qname = oxml->StrAttribute("assign")).empty())
- player->qh.assign(qname,"None",(std::string)oxml->GetText());
- else if (!(qname = oxml->StrAttribute("check")).empty()) {
- if (player->qh.hasQuest(qname) && player->qh.finish(qname)) {
- goto CONT;
- }else{
- oldidx = speaker->dialogIndex;
- speaker->dialogIndex = oxml->UnsignedAttribute("fail");
- return commonAIFunc(speaker);
- }
- }
-
- oxml = oxml->NextSiblingElement();
- }
- }
-
-CONT:
-
- /*
- * Handle any 'give' requests.
- */
-
- if ((oxml = exml->FirstChildElement("give"))) {
- while(oxml) {
- player->inv->addItem(oxml->Attribute("id"),oxml->UnsignedAttribute("count"));
- oxml = oxml->NextSiblingElement();
- }
- }
-
- /*
- * Handle any 'take' requests.
- */
-
- if ((oxml = exml->FirstChildElement("take"))) {
- while(oxml) {
- player->inv->takeItem(oxml->Attribute("id"),oxml->UnsignedAttribute("count"));
- oxml = oxml->NextSiblingElement();
- }
+ std::cout << speaker->dialogIndex << '\n';
+ do {
+ if (std::string("text") == exml->Name() && exml->UnsignedAttribute("id") == (unsigned)speaker->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, "None", std::string(oxml->GetText())); // TODO add descriptions
+
+ // 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 = speaker->dialogIndex;
+ speaker->dialogIndex = oxml->UnsignedAttribute("fail");
+ return commonAIFunc(speaker);
}
+ }
+ } while((oxml = oxml->NextSiblingElement()));
+ }
- /*
- * Handle 'go to' thingy
- */
-
- if ((oxml = exml->FirstChildElement("gotox")))
- speaker->targetx = atoi(oxml->GetText());
-
- /*
- * Handle dialog options.
- */
-
- if ((oxml = exml->FirstChildElement("option"))) {
-
- /*
- * Convert the list of options into a single colon-separated string.
- */
-
- std::string optstr;
+ // handle give tags
+ if ((oxml = exml->FirstChildElement("give"))) {
+ do player->inv->addItem(oxml->Attribute("id"), oxml->UnsignedAttribute("count"));
+ while ((oxml = oxml->NextSiblingElement()));
+ }
- while(oxml) {
+ // handle take tags
+ if ((oxml = exml->FirstChildElement("take"))) {
+ do player->inv->takeItem(oxml->Attribute("id"), oxml->UnsignedAttribute("count"));
+ while ((oxml = oxml->NextSiblingElement()));
+ }
- /*
- * Create a buffer big enough for the next option.
- */
+ // handle movement directs
+ if ((oxml = exml->FirstChildElement("gotox")))
+ speaker->moveTo(std::stoi(oxml->GetText()));
- optstr.append((std::string)":" + oxml->Attribute("text"));
+ // handle dialog options
+ if ((oxml = exml->FirstChildElement("option"))) {
+ std::string optstr;
- /*
- * Append the next option.
- */
+ // convert option strings to a colon-separated format
+ do {
+ // append the next option
+ optstr.append(std::string(":") + oxml->Attribute("text"));
- dopt.push_back(oxml);
+ // save the associated XMLElement
+ dopt.push_back(oxml);
+ } while ((oxml = oxml->NextSiblingElement()));
- oxml = oxml->NextSiblingElement();
- }
+ // run the dialog stuff
+ ui::dialogBox(speaker->name, optstr, false, exml->GetText() + 1);
+ ui::waitForDialog();
- /*
- * Get the player's choice, then set the XMLElement to the option's block.
- */
+ if (ui::dialogOptChosen)
+ exml = dopt[ui::dialogOptChosen - 1];
- ui::dialogBox(speaker->name,optstr.c_str(),false,exml->GetText()+1);
- ui::waitForDialog();
+ dopt.clear();
+ }
- if (ui::dialogOptChosen)
- exml = dopt[ui::dialogOptChosen-1];
+ // optionless dialog
+ else {
+ ui::dialogBox(speaker->name, "", false, exml->GetText());
+ ui::waitForDialog();
+ }
- while(!dopt.empty())
- dopt.pop_back();
- }else{
+ // trigger other npcs if desired
+ if (!(name = exml->StrAttribute("call")).empty()) {
+ NPC *n = *std::find_if(std::begin(currentWorld->npc), std::end(currentWorld->npc), [name](NPC *npc) {
+ return (npc->name == name);
+ });
- /*
- * No options - simply print the text.
- */
+ if (exml->QueryUnsignedAttribute("callid", &idx) == XML_NO_ERROR) {
+ n->dialogIndex = idx;
+ n->addAIFunc(false);
+ }
+ }
- ui::dialogBox(speaker->name,NULL,false,exml->GetText());
- ui::waitForDialog();
- }
+ // handle potential following dialogs
+ if ((idx = exml->UnsignedAttribute("nextid"))) {
+ speaker->dialogIndex = idx;
- /*
- * Give another NPC dialog if requested.
- */
-
- if ((name = exml->Attribute("call"))) {
- for(auto &n : currentWorld->npc) {
- if (!strcmp(n->name,name)) {
- if (exml->QueryUnsignedAttribute("callid",&idx) == XML_NO_ERROR)
- n->dialogIndex = idx;
- n->addAIFunc(commonAIFunc,false);
- break;
- }
- }
- }
+ // stop talking
+ if (exml->QueryBoolAttribute("stop", &stop) == XML_NO_ERROR && stop) {
+ speaker->dialogIndex = 9999;
+ return 0;
+ }
- /*
- * Handle the next dialog block if this one leads to another.
- */
-
- if (exml->QueryUnsignedAttribute("nextid",&idx) == XML_NO_ERROR) {
- speaker->dialogIndex = idx;
-
- if (exml->QueryBoolAttribute("stop",&stop) == XML_NO_ERROR && stop) {
- speaker->dialogIndex = 9999;
- return 0;
- }else if (exml->QueryBoolAttribute("pause",&stop) == XML_NO_ERROR && stop) {
- //speaker->dialogIndex = 9999;
- return 1;
- }else return commonAIFunc(speaker);
- }else{
- if (oldidx != 9999) {
- speaker->dialogIndex = oldidx;
- oldidx = 9999;
- return 1;
- }else{
- speaker->dialogIndex = 9999;
- return 0;
- }
- }
- //return 1;
- }
+ // pause, allow player to click npc to continue
+ else if (exml->QueryBoolAttribute("pause", &stop) == XML_NO_ERROR && stop) {
+ return 1;
}
- exml = exml->NextSiblingElement();
+ // instantly continue
+ else {
+ return commonAIFunc(speaker);
+ }
+ }
- }while(exml);
+ // stop talking
+ else {
+ // error text?
+ if (oldidx != 9999) {
+ speaker->dialogIndex = oldidx;
+ oldidx = 9999;
+ return 1;
+ } else {
+ speaker->dialogIndex = 9999;
+ return 0;
+ }
+ }
return 0;
}
-void commonPageFunc(Mob *callee) {
+void commonPageFunc(Mob *callee)
+{
ui::drawPage(callee->heyid);
ui::waitForDialog();
callee->health = 0;
@@ -235,7 +191,7 @@ void commonTriggerFunc(Mob *callee) {
xml.LoadFile(currentXML.c_str());
exml = xml.FirstChildElement("Trigger");
- while(strcmp(exml->Attribute("id"),callee->heyid.c_str()))
+ while(exml->StrAttribute("id") != callee->heyid)
exml = exml->NextSiblingElement();
player->vel.x = 0;
@@ -284,16 +240,11 @@ void initEverything(void) {
* Load the first file found as currentWorld.
*/
- for(unsigned int i=0;i<xmlFiles.size();i++) {
- if (xmlFiles[i] != "." && xmlFiles[i] != ".." && strcmp(xmlFiles[i].c_str()+xmlFiles[i].size()-3,"dat")) {
-
- /*
- * Read in the XML file.
- */
- C("Setting current XML file");
- std::cout << "File to load: " << xmlFiles[i] << std::endl;
- currentWorld = loadWorldFromXML(xmlFiles[i]);
- C("Done setting current XML file");
+ for (xf : xmlFiles) { //unsigned int i=0;i<xmlFiles.size();i++){
+ if (xf[0] != '.' && strcmp(&xf[xf.size() - 3], "dat")){
+ // read the xml file
+ std::cout << "File to load: " << xf << std::endl;
+ currentWorld = loadWorldFromXML(xf);
break;
}
}
@@ -326,8 +277,5 @@ void destroyEverything(void) {
//delete currentWorld;
//delete[] currentXML;
- while(!AIpreload.empty())
- AIpreload.pop_back();
- while(!AIpreaddr.empty())
- AIpreaddr.pop_back();
+ aipreload.clear();
}
diff --git a/src/inventory.cpp b/src/inventory.cpp
index c6b28d9..4cf5fda 100644
--- a/src/inventory.cpp
+++ b/src/inventory.cpp
@@ -150,8 +150,9 @@ void destroyInventory(void) {
Mix_FreeChunk(swordSwing);
}
-const char *getItemTexturePath(std::string name) {
- for(auto &i : itemMap) {
+
+const char *getItemTexturePath(std::string name){
+ for (auto &i : itemMap) {
if (i->name == name)
return i->texloc.c_str();
}
@@ -397,7 +398,7 @@ void Inventory::draw(void) {
glEnd();
glDisable(GL_TEXTURE_2D);
ui::setFontColor(255,255,255,((float)dfp[a]/(float)(range?range:1))*255);
- ui::putStringCentered(r.end.x,r.end.y-(itemWide*.9),itemMap[items[a].id]->name.c_str());
+ ui::putStringCentered(r.end.x,r.end.y-(itemWide*.9),itemMap[items[a].id]->name);
ui::putText(r.end.x-(itemWide/2)+(itemWide*.85),r.end.y-(itemWide/2),"%d",items[a].count);
ui::setFontColor(255,255,255,255);
}
@@ -518,8 +519,8 @@ void Inventory::draw(void) {
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()
- );
+ itemMap[items[highlight].id]->name
+ );
}
}
if (!items.empty() && items.size() > sel && items[sel].count)
diff --git a/src/ui.cpp b/src/ui.cpp
index 59ea102..30d08a2 100644
--- a/src/ui.cpp
+++ b/src/ui.cpp
@@ -20,9 +20,7 @@ extern WorldWeather weather;
* In the case of dialog, some NPC quests can be preloaded so that they aren't assigned until
* the dialog box closes. Reference variables for that here.
*/
-
-extern std::vector<int (*)(NPC *)> AIpreload;
-extern std::vector<NPC *> AIpreaddr;
+extern std::vector<NPC *> aipreload;
/*
* Pressing ESC or closing the window will set this to false.
@@ -463,20 +461,19 @@ namespace ui {
return putString(x, y, buf.get());
}
- void dialogBox(const char *name, const char *opt, bool passive, const char *text, ...) {
+ void dialogBox(std::string name, std::string opt, bool passive, std::string text, ...) {
va_list dialogArgs;
std::unique_ptr<char[]> printfbuf (new char[512]);
textWrapLimit = 110;
dialogPassive = passive;
- // reset & add speaker prefix
- dialogBoxText.clear();
- dialogBoxText = (std::string)name + ": ";
+ // add speaker prefix
+ dialogBoxText = name + ": ";
// handle the formatted string
- va_start(dialogArgs,text);
- vsnprintf(printfbuf.get(),512,text,dialogArgs);
+ va_start(dialogArgs, text);
+ vsnprintf(printfbuf.get(), 512, text.c_str(), dialogArgs);
va_end(dialogArgs);
dialogBoxText += printfbuf.get();
@@ -485,12 +482,11 @@ namespace ui {
dialogOptChosen = 0;
- if (opt) {
- std::string soptbuf = opt;
- char *sopt = strtok(&soptbuf[0], ":");
+ if (!opt.empty()) {
+ char *sopt = strtok(&opt[0], ":");
// cycle through options
- while(sopt) {
+ while (sopt) {
dialogOptText.push_back(std::make_pair((std::string)sopt, vec3 {0,0,0}));
sopt = strtok(NULL,":");
}
@@ -558,11 +554,11 @@ namespace ui {
* Wait for a dialog box to be dismissed.
*/
- void waitForDialog (void) {
+ void waitForDialog(void) {
while (dialogBoxExists);
}
- void waitForCover (void) {
+ void waitForCover(void) {
while (fadeIntensity < 255)
mainLoop();
fadeIntensity = 255;
@@ -666,7 +662,7 @@ namespace ui {
}
if (fadeIntensity == 255 || dialogPassive) {
setFontSize(24);
- putStringCentered(offset.x,offset.y,rtext.c_str());
+ putStringCentered(offset.x,offset.y,rtext);
setFontSize(16);
}
}else if (dialogMerchant) {
@@ -683,10 +679,10 @@ namespace ui {
vec2 merchBase = {offset.x, offset.y + SCREEN_HEIGHT / 5};
- 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(merchBase.x + SCREEN_WIDTH / 10 - 20, merchBase.y + 40 + fontSize * 2, itemString1);
+ putStringCentered(merchBase.x + SCREEN_WIDTH / 10 - 20, merchBase.y + 40 + fontSize , merchTrade.item[0]);
+ putStringCentered(merchBase.x - SCREEN_WIDTH / 10 , merchBase.y + 40 + fontSize * 2, itemString2);
+ putStringCentered(merchBase.x - SCREEN_WIDTH / 10 , merchBase.y + 40 + fontSize , merchTrade.item[1]);
putStringCentered(offset.x, merchBase.y + 60, "for");
glEnable(GL_TEXTURE_2D);
@@ -797,7 +793,7 @@ namespace ui {
putText(hub.x,hub.y,"Health: %u/%u",player->health>0?(unsigned)player->health:0,
(unsigned)player->maxHealth
);
- if (player->alive) {
+ if (player->isAlive()) {
glColor3ub(150,0,0);
hub.y-=fontSize*1.15;
glRectf(hub.x,
@@ -824,7 +820,7 @@ namespace ui {
for(auto &c : player->qh.current) {
hub.y -= fontSize * 1.15;
- putStringCentered(hub.x,hub.y,c.title.c_str());
+ putStringCentered(hub.x,hub.y,c.title);
}
hub.y = offset.y + 40*1.2;
@@ -899,6 +895,7 @@ EXIT:
//if (!dialogMerchant)closeBox();
dialogBoxExists = false;
dialogMerchant = false;
+ dialogPassive = false;
//DONE:
@@ -1211,11 +1208,10 @@ EXIT:
}
// Flush preloaded AI functions if necessary
- if (!dialogBoxExists && AIpreaddr.size()) {
- while (!AIpreaddr.empty()) {
- AIpreaddr.front()->addAIFunc(AIpreload.front(), false);
- AIpreaddr.erase(AIpreaddr.begin());
- AIpreload.erase(AIpreload.begin());
+ if (!dialogBoxExists) {
+ while (!aipreload.empty()) {
+ aipreload.front()->addAIFunc(false);
+ aipreload.erase(std::begin(aipreload));
}
}
}
diff --git a/src/ui_action.cpp b/src/ui_action.cpp
index a7bb36b..264100d 100644
--- a/src/ui_action.cpp
+++ b/src/ui_action.cpp
@@ -137,10 +137,8 @@ void actionAction(void)
auto e = currentWorld->getNearInteractable(*player);
- if (e->type == NPCT) {
- if (!NPCp(e)->aiFunc.empty())
- e->interact();
- }
+ if (e->type == NPCT)
+ e->interact();
ACTION_EPILOUGE;
}
diff --git a/src/world.cpp b/src/world.cpp
index 5893bfb..37d899d 100644
--- a/src/world.cpp
+++ b/src/world.cpp
@@ -190,9 +190,6 @@ deleteEntities(void)
void World::
generate(unsigned int width)
{
- // iterator for `for` loops
- std::vector<WorldData>::iterator wditer;
-
// see below for description/usage
float geninc = 0;
@@ -206,34 +203,24 @@ generate(unsigned int width)
// prepare for generation
worldData.front().groundHeight = GROUND_HEIGHT_INITIAL;
- wditer = worldData.begin();
+ auto wditer = std::begin(worldData) + GROUND_HILLINESS;
// give every GROUND_HILLINESSth entry a groundHeight value
- for (unsigned i = GROUND_HILLINESS; i < worldData.size(); i += GROUND_HILLINESS, wditer += GROUND_HILLINESS)
- worldData[i].groundHeight = (*wditer).groundHeight + (randGet() % 8 - 4);
+ for (; wditer < std::end(worldData); wditer += GROUND_HILLINESS)
+ (*(wditer - GROUND_HILLINESS)).groundHeight = (*wditer).groundHeight + (randGet() % 8 - 4);
// create slopes from the points that were just defined, populate the rest of the WorldData structure
+ for (wditer = std::begin(worldData) + 1; wditer < std::end(worldData); wditer++){
+ auto w = &*(wditer);
- for(wditer = worldData.begin() + 1; wditer != worldData.end(); wditer++) {
- 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 {
- (*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;
+ if (w->groundHeight)
+ geninc = ((w + (int)GROUND_HILLINESS)->groundHeight - w->groundHeight) / GROUND_HILLINESS;
- if((*wditer).groundHeight <= 0)
- (*wditer).groundHeight = GROUND_HEIGHT_MINIMUM;
+ w->groundHeight = fmin(fmax((w - 1)->groundHeight + geninc, GROUND_HEIGHT_MINIMUM), GROUND_HEIGHT_MAXIMUM);
+ w->groundColor = randGet() % 32 / 8;
+ w->grassUnpressed = true;
+ w->grassHeight[0] = (randGet() % 16) / 3 + 2;
+ w->grassHeight[1] = (randGet() % 16) / 3 + 2;
}
// define x-coordinate of world's leftmost 'line'
@@ -449,22 +436,21 @@ draw(Player *p)
glBegin(GL_QUADS);
//std::for_each(std::begin(worldData) + iStart, std::begin(worldData) + iEnd, [&](WorldData wd) {
for (i = iStart; i < iEnd; i++) {
- auto wd = worldData[i];
- if (wd.groundHeight <= 0) {
- wd.groundHeight = GROUND_HEIGHT_MINIMUM - 1;
+ if (worldData[i].groundHeight <= 0) {
+ worldData[i].groundHeight = GROUND_HEIGHT_MINIMUM - 1;
glColor4ub(0, 0, 0, 255);
} else {
safeSetColorA(150, 150, 150, 255);
}
- 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);
+ int ty = worldData[i].groundHeight / 64 + worldData[i].groundColor;
+ 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, 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;
+ if (worldData[i].groundHeight == GROUND_HEIGHT_MINIMUM - 1)
+ worldData[i].groundHeight = 0;
}//);
glEnd();
@@ -558,10 +544,11 @@ singleDetect(Entity *e)
int l;
// kill dead entities
- if (e->alive && e->health <= 0) {
+ if (!e->isAlive()) {
+ return;
+ } else if (e->health <= 0) {
// die
- e->alive = false;
- e->health = 0;
+ e->die();
// delete the entity
for (i = 0; i < entity.size(); i++) {
@@ -599,15 +586,10 @@ singleDetect(Entity *e)
}
// collision / gravity: handle only living entities
- if (e->alive) {
+ else {
// forced movement gravity (sword hits)
- if (e->forcedMove) {
- if (e->vel.x > .0005 || e->vel.x < -.0005)
- e->vel.x *= .6;
- else
- e->forcedMove = false;
- }
+ e->handleHits();
if (e->subtype == MS_TRIGGER)
return;
@@ -877,7 +859,7 @@ void World::save(void){
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(std::to_string((int)m->isAlive()) + "\n");
}
// wrap up
@@ -898,9 +880,8 @@ void World::load(void){
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();
+ if ((n->dialogIndex = std::stoi(line)) != 9999)
+ n->addAIFunc(false);
std::getline(iss,line);
if(line == "dOnE")return;
@@ -928,7 +909,8 @@ void World::load(void){
m->loc.y = std::stoi(line);
std::getline(iss,line);
if(line == "dOnE")return;
- m->alive = std::stoi(line);
+ if (!std::stoi(line))
+ m->die();
}
while(std::getline(iss,line)){
@@ -1005,18 +987,15 @@ setStyle(std::string pre)
// get folder prefix
std::string prefix = pre.empty() ? "assets/style/classic/" : pre;
- for_each(std::begin(buildPaths), std::end(buildPaths), [this, prefix](std::string s){
+ for (s : buildPaths)
sTexLoc.push_back(prefix + s);
- });
prefix += "bg/";
- for_each(std::begin(bgPaths[0]), std::end(bgPaths[0]), [this, prefix](std::string s){
+ for (s : bgPaths[0])
bgFiles.push_back(prefix + s);
- });
- for_each(std::begin(bgPaths[1]), std::end(bgPaths[1]), [this, prefix](std::string s){
+ for (s : bgPaths[1])
bgFilesIndoors.push_back(prefix + s);
- });
}
/**
@@ -1107,7 +1086,7 @@ 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;
+ e->die();
currentWorldToLeft->npc.back()->loc.x = 0;
currentWorldToLeft->npc.back()->loc.y = GROUND_HEIGHT_MAXIMUM;
@@ -1125,45 +1104,50 @@ World *World::
goInsideStructure(Player *p)
{
World *tmp;
- std::string current;
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 (b->inside.empty())
- return this;
+ auto d = std::find_if(std::begin(build), std::end(build), [p](const Structures *s) {
+ return ((p->loc.x > s->loc.x) && (p->loc.x + p->width < s->loc.x + s->width));
+ });
+ auto b = *d;
- // +size cuts folder prefix
- inside.push_back(currentXML.c_str() + xmlFolder.size());
- tmp = loadWorldFromXML(b->inside);
+ if ((d == std::end(build)) || b->inside.empty())
+ return this;
- // make the fade, as we let it fade back the worlds should be switched
- ui::toggleBlackFast();
- ui::waitForCover();
- ui::toggleBlackFast();
+ // +size cuts folder prefix
+ inside.push_back(&currentXML[xmlFolder.size()]);
+ tmp = loadWorldFromXML(b->inside);
- glClearColor(0, 0, 0, 1);
+ // 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);
- return tmp;
- }
- }
+ return tmp;
} else {
- current = currentXML.c_str() + xmlFolder.size();
+ std::string current = &currentXML[xmlFolder.size()];
tmp = loadWorldFromXML(inside.back());
- for (auto &b : tmp->build) {
- if (current == b->inside) {
- inside.pop_back();
+ inside.clear();
- ui::toggleBlackFast();
- ui::waitForCover();
- p->loc.x = b->loc.x + (b->width / 2);
- ui::toggleBlackFast();
+ Structures *b;
+ for (auto &s : build) {
+ if (s->inside == current) {
+ b = s;
+ break;
+ }
+ }
+ //auto b = *std::find_if(std::begin(build), std::end(build), [&](const Structures *s) {
+ // return (s->inside == current);
+ //});
- glClearColor(1, 1, 1, 1);
+ ui::toggleBlackFast();
+ ui::waitForCover();
+ p->loc.x = b->loc.x + (b->width / 2);
+ ui::toggleBlackFast();
+ glClearColor(1, 1, 1, 1);
- return tmp;
- }
- }
+ return tmp;
}
return this;
@@ -1173,18 +1157,15 @@ void World::addStructure(BUILD_SUB sub, float x,float y, std::string tex, std::s
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);
+ village.emplace_back(name, world);
return &village.back();
}
@@ -1358,9 +1339,9 @@ singleDetect(Entity *e)
unsigned int floornum = 0;
float start, end;
- if (!e->alive)
+ if (!e->isAlive())
return;
- if (e->type == MOBT && Mobp(e)->subtype == MS_TRIGGER)
+ if (e->type == MOBT && e->subtype == MS_TRIGGER)
return;
for (; floornum < floor.size(); floornum++) {
@@ -1527,10 +1508,10 @@ 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) {
- tmp = battleNest.front();
+ if (!mmob->isAlive() &&
+ 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());
inBattle = !battleNest.empty();
@@ -1541,7 +1522,7 @@ World *Arena::exitArena(Player *p) {
battleNestLoc.pop_back();
mob.clear();
- mmob->alive = false;
+ mmob->die();
return tmp;
}else{
@@ -1749,9 +1730,9 @@ loadWorldFromXMLNoSave(std::string path) {
// dialog enabling
dialog = false;
- if (wxml->QueryBoolAttribute("hasDialog", &dialog) == XML_NO_ERROR && dialog)
- tmp->npc.back()->addAIFunc(commonAIFunc, false);
- else
+ if (wxml->QueryBoolAttribute("hasDialog", &dialog) == XML_NO_ERROR && dialog) {
+ tmp->npc.back()->addAIFunc(false);
+ } else
tmp->npc.back()->dialogIndex = 9999;
if (Indoor && wxml->QueryUnsignedAttribute("floor", &flooor) == XML_NO_ERROR)
@@ -1855,8 +1836,6 @@ loadWorldFromXMLNoSave(std::string path) {
sxml->IntAttribute("quantity1"),
sxml->StrAttribute("item1")));
} else if (tag == "text") { //this is what the merchant says
- std::cout << "text" << std::endl;
-
XMLElement *txml = sxml->FirstChildElement();
std::string textOption;
@@ -1894,7 +1873,7 @@ loadWorldFromXMLNoSave(std::string path) {
vil = vil->NextSiblingElement();
}
- std::ifstream dat (((std::string)currentXML + ".dat").c_str());
+ std::ifstream dat (((std::string)currentXML + ".dat").data());
if (dat.good()) {
dat.close();
tmp->load();
@@ -1903,7 +1882,8 @@ loadWorldFromXMLNoSave(std::string path) {
return tmp;
}
-Village::Village(const char *meme, World *w) {
+Village::Village(std::string meme, World *w)
+{
name = meme;
start.x = w->getTheWidth() / 2.0f;
end.x = -start.x;
diff --git a/xcf/cat.xcf b/xcf/cat.xcf
new file mode 100644
index 0000000..4d602bb
--- /dev/null
+++ b/xcf/cat.xcf
Binary files differ