]> code.bitgloo.com Git - clyne/gamedev.git/commitdiff
more rewrites
authorClyne Sullivan <tullivan99@gmail.com>
Sun, 24 Apr 2016 02:31:27 +0000 (22:31 -0400)
committerClyne Sullivan <tullivan99@gmail.com>
Sun, 24 Apr 2016 02:31:27 +0000 (22:31 -0400)
12 files changed:
include/common.hpp
include/entities.hpp
include/ui.hpp
include/world.hpp
main.cpp
src/entities.cpp
src/gameplay.cpp
src/inventory.cpp
src/ui.cpp
src/ui_action.cpp
src/world.cpp
xcf/cat.xcf [new file with mode: 0644]

index 310bf7fbd2d211da61879a25b643ff61ca7198a8..9211d56fa05ba47c76c6a7f9989f63aab50d6fe7 100644 (file)
@@ -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;
 
index 4a2420ed2c7d8c9213669621e90a925ed68420bd..460dc9326ccd2f848d99e964f56ede461d9a563e 100644 (file)
+/* ----------------------------------------------------------------------------
+** 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
 
 /**
index 144a87e3d1151b55917d8e6a8d884bfc2de77b47..477c9c3aaf15d30b4e16cfae2fd82cc73c1f61af 100644 (file)
@@ -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();
index 9a1d7010814d2715f4392f599ac230aecbd2126c..c6eaf0647647940e2db50aa2d7c1afb9973fa40b 100644 (file)
@@ -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);
 };
 
 /**
index 8e078180aacdb305c6337d947172e10579785a18..fa724949a7d7af8eba24e85aa5051a592cdc02b4 100644 (file)
--- 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;
                        }
                }
        }
index 96fe0e6dfebc07972ea14a1ca2931ae39e9381ff..16ba7683392a710af897ffd80cf9220012a169f5 100644 (file)
@@ -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();
        }
index e314be47a69c2b9e5931706fc08e0ca93960315f..603ede70d9cade5e24089e1224861d2b30ee9e73 100644 (file)
@@ -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();
 }
index c6b28d93bacf4a588d9e17d548d6927c6a6e6ef1..4cf5fda8df5cf976273d3da739e2d77c0ca26342 100644 (file)
@@ -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)
index 59ea102af39004a100f00af70b9b4a08169d4d1d..30d08a2028ce94e41f79ed306ad03faaddc69978 100644 (file)
@@ -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));
                        }
                }
        }
index a7bb36bbbfbe659137d438e3e669fcb250620618..264100d2bae79a4e1d75b73e05c2b0da418d1d24 100644 (file)
@@ -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;
 }
index 5893bfb7e42f79b217584d4b18c6be68cb842484..37d899dd7c2d2b1f949e35fe18441f38401dfe94 100644 (file)
@@ -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 (file)
index 0000000..4d602bb
Binary files /dev/null and b/xcf/cat.xcf differ