diff options
Diffstat (limited to 'src/world.cpp')
-rw-r--r-- | src/world.cpp | 1798 |
1 files changed, 831 insertions, 967 deletions
diff --git a/src/world.cpp b/src/world.cpp index b2e1cfb..5ce0b2d 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -1,158 +1,225 @@ +#include <algorithm> +#include <sstream> + #include <world.h> #include <ui.h> -#define getWidth(w) ((w->lineCount-GEN_INC)*HLINE) // Calculates the width of world 'w' +#include <tinyxml2.h> +using namespace tinyxml2; -#define GEN_INIT 60 +/** + * Defines how many HLINEs tall a blade of grass can be. + */ -#define GRASS_HEIGHT 4 // Defines how long the grass layer of a line should be in multiples of HLINE. +#define GRASS_HEIGHT 4 +/** + * Defines the height of the floor in an IndoorWorld. + */ -#define DRAW_Y_OFFSET 50 // Defines how many pixels each layer should be offset from each other on the y axis when drawn. -#define DRAW_SHADE 30 // Defines a shade increment for draw() +#define INDOOR_FLOOR_HEIGHT 100 -#define INDOOR_FLOOR_HEIGHT 100 // Defines how high the base floor of an IndoorWorld should be -bool worldInside = false; // True if player is inside a structure +extern Player *player; // main.cpp? +extern World *currentWorld; // main.cpp +extern int commonAIFunc(NPC *); // entities.cpp +extern void commonTriggerFunc(Mob *); // entities.cpp +extern bool inBattle; + +extern unsigned int tickCount; // main.cpp + +int worldShade = 0; -WEATHER weather = SUNNY; +std::string currentXML; +std::vector<std::string> inside; // tracks indoor worlds + +std::vector<World *> battleNest; // tracks arenas +std::vector<vec2> battleNestLoc; // keeps arena locations + +/** + * Contains the current weather, used in many other places/files. + */ + +WorldWeather weather = WorldWeather::Sunny; const std::string bgPaths[2][9]={ - {"bg.png", // Daytime background - "bgn.png", // Nighttime background - "bgFarMountain.png", // Furthest layer - "forestTileFar.png", // Furthest away Tree Layer - "forestTileBack.png", // Closer layer - "forestTileMid.png", // Near layer - "forestTileFront.png", // Closest layer - "dirt.png", // Dirt - "grass.png"}, // Grass - {"bgWoodTile.png", - "bgWoodTile.png", - "bgWoodTile.png", - "bgWoodTile.png", - "bgWoodTile.png", - "bgWoodTile.png", - "bgWoodTile.png", - "bgWoodTile.png"} + {"bg.png", // Daytime background + "bgn.png", // Nighttime background + "bgFarMountain.png", // Furthest layer + "forestTileFar.png", // Furthest away Tree Layer + "forestTileBack.png", // Closer layer + "forestTileMid.png", // Near layer + "forestTileFront.png", // Closest layer + "dirt.png", // Dirt + "grass.png"}, // Grass + {"bgWoodTile.png", + "bgWoodTile.png", + "bgWoodTile.png", + "bgWoodTile.png", + "bgWoodTile.png", + "bgWoodTile.png", + "bgWoodTile.png", + "bgWoodTile.png"} }; -const std::string buildPaths[] = { "townhall.png", - "house1.png", - "house2.png", - "house1.png", - "house1.png", - "fountain1.png", - "lampPost1.png", - "brazzier.png"}; +const std::string buildPaths[] = { + "townhall.png", + "house1.png", + "house2.png", + "house1.png", + "house1.png", + "fountain1.png", + "lampPost1.png", + "brazzier.png" +}; + +/** + * Constants used for layer drawing in World::draw(), releated to transparency. + */ const float bgDraw[4][3]={ - {100,240,.6 }, - {150,250,.4 }, - {200,255,.25}, - {255,255,.1} + { 100, 240, 0.6 }, + { 150, 250, 0.4 }, + { 200, 255, 0.25 }, + { 255, 255, 0.1 } }; -float worldGetYBase(World *w){ -// World *tmp = w; - float base = GEN_MIN; -/* while(tmp->infront){ - tmp = tmp->infront; - base -= DRAW_Y_OFFSET; - }*/ - if(!w)return 0; - return base; -} - -void World::setBackground(WORLD_BG_TYPE bgt){ - bgType = bgt; - switch(bgt){ - case BG_FOREST: - bgTex = new Texturec(bgFiles); +/** + * Sets the desired theme for the world's background. + * + * The images chosen for the background layers are selected depending on the + * world's background type. + */ + +void World:: +setBackground( WorldBGType bgt ) +{ + // load textures with a limit check + switch ( (bgType = bgt) ) { + case WorldBGType::Forest: + bgTex = new Texturec( bgFiles ); break; - case BG_WOODHOUSE: - bgTex = new Texturec(bgFilesIndoors); + + case WorldBGType::WoodHouse: + bgTex = new Texturec( bgFilesIndoors ); break; + + default: + UserError( "Invalid world background type" ); + break; } } -void World::setStyle(const char* pre){ - std::string prefix = pre ? pre : "assets/style/classic/"; - for(uint i = 0; i < arrAmt(buildPaths);i++){ - sTexLoc.push_back(prefix); - sTexLoc.back() += buildPaths[i]; - //std::cout << sTexLoc.back() << std::endl; - } +/** + * Sets the world's style. + * + * The world's style will determine what sprites are used for things like\ + * generic structures. + */ + +void World:: +setStyle( std::string pre ) +{ + unsigned int i; + + // get folder prefix + std::string prefix = pre.empty() ? "assets/style/classic/" : pre; + + for ( i = 0; i < arrAmt(buildPaths); i++ ) + sTexLoc.push_back( prefix + buildPaths[i] ); + prefix += "bg/"; - for(uint i = 0; i < arrAmt(bgPaths[0]);i++){ - bgFiles.push_back(prefix); - bgFiles.back() += bgPaths[0][i]; - //std::cout << bgFiles.back() << std::endl; - } - for(uint i = 0; i < arrAmt(bgPaths[1]);i++){ - bgFilesIndoors.push_back(prefix); - bgFilesIndoors.back() += bgPaths[1][i]; - //std::cout << bgFilesIndoors.back() << std::endl; - } + + for ( i = 0; i < arrAmt(bgPaths[0]); i++ ) + bgFiles.push_back( prefix + bgPaths[0][i] ); + + for ( i = 0; i < arrAmt(bgPaths[1]); i++ ) + bgFilesIndoors.push_back( prefix + bgPaths[1][i] ); } -World::World(void){ - - bgm = NULL; - bgmObj = NULL; - - toLeft = - toRight = NULL; - - /* - * Allocate and clear an array for star coordinates. - */ - - star = new vec2[100]; - memset(star,0,100 * sizeof(vec2)); +/** + * Creates a world object. + * + * Note that all this does is nullify pointers, to prevent as much disaster as + * possible. Functions like setBGM(), setStyle() and generate() should be called + * before the World is actually put into use. + */ + +World:: +World( void ) +{ + bgmObj = NULL; + + toLeft = NULL; + toRight = NULL; } -void World::deleteEntities(void){ - while(!mob.empty()){ +/** + * The entity vector destroyer. + * + * This function will free all memory used by all entities, and then empty the + * vectors they were stored in. + */ + +void World:: +deleteEntities( void ) +{ + // free mobs + while ( !mob.empty() ) { delete mob.back(); mob.pop_back(); } + + merchant.clear(); while(!npc.empty()){ delete npc.back(); npc.pop_back(); } - while(!build.empty()){ + + // free structures + while ( !build.empty() ) { delete build.back(); build.pop_back(); } - while(!object.empty()){ + + // free objects + while ( !object.empty() ) { delete object.back(); object.pop_back(); } - while(!entity.empty()){ - entity.pop_back(); - } - while(!particles.empty()){ - delete particles.back(); - particles.pop_back(); - } - while(!light.empty()){ - light.pop_back(); + + // clear entity array + entity.clear(); + + // free particles + particles.clear(); + + // clear light array + light.clear(); + + // free villages + while ( !village.empty() ) { + delete village.back(); + village.pop_back(); } } -World::~World(void){ - /*if(behind != NULL) - delete behind;*/ - +/** + * The world destructor. + * + * This will free objects used by the world itself, then free the vectors of + * entity-related objects. + */ + +World:: +~World( void ) +{ + // sdl2_mixer's object if(bgmObj) Mix_FreeMusic(bgmObj); - if(bgm) - delete[] bgm; + delete bgTex; - delete[] star; - delete[] line; delete[] toLeft; delete[] toRight; @@ -160,634 +227,464 @@ World::~World(void){ deleteEntities(); } -void World::generate(unsigned int width){ // Generates the world and sets all variables contained in the World class. - unsigned int i; - float inc; - - /* - * Calculate the world's real width. The current form of generation fails to generate - * the last GEN_INC lines, so we offset those making the real real width what was passed - * to this function. - * - * Abort if the width is invalid. - * - */ - - if(width <= 0) - abort(); +/** + * Generates a world of the specified width. + * + * This will mainly populate the WorldData array, mostly preparing the World + * object for usage. + */ + +void World:: +generate( unsigned int width ) +{ + // iterator for `for` loops + std::vector<WorldData>::iterator wditer; + + // see below for description + float geninc = 0; + + // check for valid width + if ( (int)width <= 0 ) + UserError("Invalid world dimensions"); + + // allocate space for world + worldData = std::vector<WorldData> (width + GROUND_HILLINESS, WorldData { false, {0,0}, 0, 0 }); + lineCount = worldData.size(); + + // prepare for generation + worldData.front().groundHeight = GROUND_HEIGHT_INITIAL; + wditer = worldData.begin(); + + // give every GROUND_HILLINESSth entry a groundHeight value + for(unsigned int i = GROUND_HILLINESS; i < worldData.size(); i += GROUND_HILLINESS, wditer += GROUND_HILLINESS) + worldData[i].groundHeight = (*wditer).groundHeight + (randGet() % 8 - 4); + + // create slopes from the points that were just defined, populate the rest of the WorldData structure + + for(wditer = worldData.begin(); wditer != worldData.end(); wditer++){ + if ((*wditer).groundHeight) + // 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; + + (*wditer).groundColor = randGet() % 32 / 8; + (*wditer).grassUnpressed = true; + (*wditer).grassHeight[0] = (randGet() % 16) / 3 + 2; + (*wditer).grassHeight[1] = (randGet() % 16) / 3 + 2; + + // bound checks + if ( (*wditer).groundHeight < GROUND_HEIGHT_MINIMUM ) + (*wditer).groundHeight = GROUND_HEIGHT_MINIMUM; + else if ( (*wditer).groundHeight > GROUND_HEIGHT_MAXIMUM ) + (*wditer).groundHeight = GROUND_HEIGHT_MAXIMUM; - lineCount = (width + GEN_INC) / HLINE; - - /* - * Allocate enough memory for the world to be stored. - */ - - line = new struct line_t[lineCount]; - memset(line,0,lineCount * sizeof(struct line_t)); - - /* - * Set an initial y to base generation off of, as generation references previous lines. - */ - - line[0].y = GEN_INIT; - - /* - * Populate every GEN_INCth line structure. The remaining lines will be based off of these. - */ - - for(i = GEN_INC;i < lineCount;i += GEN_INC){ - - /* - * Generate a y value, ensuring it stays within a reasonable range. - */ - - line[i].y = rand() % 8 - 4 + line[i - GEN_INC].y; // Add +/- 4 to the previous line - - if(line[i].y < GEN_MIN)line[i].y = GEN_MIN; // Minimum bound - else if(line[i].y > GEN_MAX)line[i].y = GEN_MAX; // Maximum bound - - } - - /* - * Generate values for the remaining lines here. - */ - - for(i = 0;i < lineCount - GEN_INC;i++){ - - /* - * Every GEN_INCth line calculate the slope between the current line and the one - * GEN_INC lines before it. This value is then divided into an increment that is - * added to lines between these two points resulting in a smooth slope. - * - */ - - if(!(i % GEN_INC)) - - inc = (line[i + GEN_INC].y - line[i].y) / (float)GEN_INC; - - /* - * Add the increment to create the smooth slope. - */ - - else line[i].y = line[i - 1].y + inc; - - /* - * Generate a color value for the line. This will be referenced in World->draw(), - * by setting an RGB value of color (red), color - 50 (green), color - 100 (blue). - */ - - line[i].color = rand() % 32 / 8; // 100 to 120 + if( (*wditer).groundHeight <= 0 ) + (*wditer).groundHeight = GROUND_HEIGHT_MINIMUM; - /* - * Each line has two 'blades' of grass, here we generate random heights for them. - */ - - line[i].gh[0] = (getRand() % 16) / 3.5 + 2; // Not sure what the range resolves to here... - line[i].gh[1] = (getRand() % 16) / 3.5 + 2; // - - line[i].gs = true; // Show the blades of grass (modified by the player) - - } - - /* - * Calculate the x coordinate to start drawing this world from so that it is centered at (0,0). - */ - - x_start = 0 - getWidth(this) / 2; + } + + // define x-coordinate of world's leftmost 'line' + worldStart = (width - GROUND_HILLINESS) * HLINE / 2 * -1; - /* - * Assign coordinates for the stars, seen at nighttime. - */ - - for(i = 0;i < 100;i++){ - star[i].x = getRand() % getTheWidth() - getTheWidth() / 2; - star[i].y = getRand() % SCREEN_HEIGHT + 100; + // create empty star array, should be filled here as well... + star = std::vector<vec2> (100, vec2 { 0, 400 } ); + for ( auto &s : star ) { + s.x = (getRand() % (-worldStart * 2)) + worldStart; + s.y = (getRand() % SCREEN_HEIGHT) + 100.0f; } } -void World::generateFunc(unsigned int width,float(*func)(float)){ - unsigned int i; - - /* - * Check for a valid width. - */ - - if((lineCount = width) <= 0) - abort(); - - /* - * Allocate memory for the line array. - */ - - line = new struct line_t[lineCount]; - memset(line,0,lineCount*sizeof(struct line_t)); - - /* - * Populate entries in the line array, using `func` to get y values. - */ - - for(i = 0;i < lineCount;i++){ - line[i].y = func(i); - - if(line[i].y < 0)line[i].y = 0; // Minimum bound - if(line[i].y > 2000)line[i].y = 2000; // Maximum bound - - line[i].color = rand() % 20 + 100; - - line[i].gh[0] = (getRand() % 16) / 3.5 + 2; - line[i].gh[1] = (getRand() % 16) / 3.5 + 2; - - line[i].gs = true; - } - - x_start = 0 - getWidth(this) / 2; - - for(i = 0;i < 100;i++){ - star[i].x = getRand() % getTheWidth() - getTheWidth() / 2; - star[i].y = getRand() % SCREEN_HEIGHT + 100; - } -} +/** + * Updates all entity and player coordinates with their velocities. + * + * Also handles music fading, although that could probably be placed elsewhere. + */ -void World::update(Player *p,unsigned int delta){ - - /* - * Update the player's coordinates. - */ - +void World:: +update( Player *p, unsigned int delta ) +{ + // update player coords p->loc.y += p->vel.y * delta; p->loc.x +=(p->vel.x * p->speed) * delta; - /* - * Update coordinates of all entities except for structures. - */ - - for(auto &e : entity){ + // update entity coords + for ( auto &e : entity ) { e->loc.y += e->vel.y * delta; - if(e->type != STRUCTURET && e->canMove){ + // dont let structures move? + if ( e->type != STRUCTURET && e->canMove ) { e->loc.x += e->vel.x * delta; - if(e->vel.x < 0)e->left = true; - else if(e->vel.x > 0)e->left = false; + // update boolean directions + if ( e->vel.x < 0 ) + e->left = true; + else if ( e->vel.x > 0 ) + e->left = false; } } + // iterate through particles + particles.erase( std::remove_if( particles.begin(), particles.end(), [&delta](Particles &part){return part.kill(delta);}), particles.end()); + for ( auto part = particles.begin(); part != particles.end(); part++ ) { + if ( (*part).canMove ) { + (*part).loc.y += (*part).vely * delta; + (*part).loc.x += (*part).velx * delta; + + for ( auto &b : build ) { + if ( b->bsubtype == FOUNTAIN ) { + if ( (*part).loc.x >= b->loc.x && (*part).loc.x <= b->loc.x + b->width ) { + if ( (*part).loc.y <= b->loc.y + b->height * .25) + particles.erase( part ); - for(unsigned int i=0;i<particles.size();i++){ - if(particles[i]->kill(delta)){ - delete particles[i]; - particles.erase(particles.begin()+i); - }else if(particles[i]->canMove){ - particles[i]->loc.y += particles[i]->vely * delta; - particles[i]->loc.x += particles[i]->velx * delta; - - for(auto &b : build){ - if(b->bsubtype==FOUNTAIN){ - if(particles[i]->loc.x >= b->loc.x && particles[i]->loc.x <= b->loc.x + b->width){ - if(particles[i]->loc.y <= b->loc.y + b->height * .25){ - delete particles[i]; - particles.erase(particles.begin()+i); - } } } } } } - if(ui::dialogImportant){ + // handle music fades + if ( ui::dialogImportant ) Mix_FadeOutMusic(2000); - }else if(!Mix_PlayingMusic()){ + else if( !Mix_PlayingMusic() ) Mix_FadeInMusic(bgmObj,-1,2000); - } } -void World::setBGM(std::string path){ - bgm = new char[path.size() + 1]; - strcpy(bgm,path.c_str()); - bgmObj = Mix_LoadMUS(bgm); +/** + * Set the world's BGM. + * + * This will load a sound file to be played while the player is in this world. + * If no file is found, no music should play. + */ + +void World:: +setBGM( std::string path ) +{ + if( !path.empty() ) + bgmObj = Mix_LoadMUS( (bgm = path).c_str() ); } -void World::bgmPlay(World *prev){ - if(prev){ - if(bgm != prev->bgm){ - Mix_FadeOutMusic(800); - //Mix_VolumeMusic(50); - Mix_PlayMusic(bgmObj,-1); // Loop infinitely +/** + * Toggle play/stop of the background music. + * + * If new music is to be played a crossfade will occur, otherwise... uhm. + */ + +void World:: +bgmPlay( World *prev ) const +{ + if ( prev ) { + if ( bgm != prev->bgm ) { + // new world, new music + Mix_FadeOutMusic( 800 ); + Mix_PlayMusic( bgmObj, -1 ); } - }else{ - Mix_FadeOutMusic(800); - //Mix_VolumeMusic(50); - Mix_PlayMusic(bgmObj,-1); // Loop infinitely + } else { + // first call + Mix_FadeOutMusic( 800 ); + Mix_PlayMusic( bgmObj, -1 ); } } -int worldShade = 0; - -extern vec2 offset; -extern unsigned int tickCount; - -void World::draw(Player *p){ - static float yoff=DRAW_Y_OFFSET; // Initialize stuff - static int shade,bgshade; - static World *current=this; - unsigned int i; - int is,ie,v_offset,cx_start,width; - struct line_t *cline; - float base; - - bgshade = worldShade << 1; // *2 - base = worldGetYBase(this); +/** + * The world draw function. + * + * This function will draw the background layers, entities, and player to the + * screen. + */ + +void World:: +draw( Player *p ) +{ + // iterators + int i, iStart, iEnd; + + // shade value for draws -- may be unnecessary + int shadeBackground = -worldShade; + + // player's offset in worldData[] + int pOffset; + + // world width in pixels + int width = worldData.size() * HLINE; + + // shade value for GLSL + float shadeAmbient = -worldShade / 50.0f + 0.5f; // -0.5f to 1.5f + if ( shadeAmbient < 0 ) + shadeAmbient = 0; + else if ( shadeAmbient > 0.9f ) + shadeAmbient = 1; /* - * Draw the background images in the appropriate order. - */ + * Draw background images. + */ -//LLLOOP: - /*if(current->infront){ - current=current->infront; - goto LLLOOP; - }*/ + glEnable( GL_TEXTURE_2D ); - if(current->x_start < SCREEN_WIDTH * -.5 ) - cx_start = current->x_start * 1.5; - else - cx_start = (int)(SCREEN_WIDTH * -.5); - - width = (-cx_start) << 1; + // the sunny wallpaper is faded with the night depending on tickCount - glEnable(GL_TEXTURE_2D); - - bgTex->bind(0); - safeSetColorA(255,255,255,255 - worldShade * 4); - glBegin(GL_QUADS); - glTexCoord2i(0,0);glVertex2i( cx_start,SCREEN_HEIGHT); - glTexCoord2i(1,0);glVertex2i(-cx_start,SCREEN_HEIGHT); - glTexCoord2i(1,1);glVertex2i(-cx_start,0); - glTexCoord2i(0,1);glVertex2i( cx_start,0); + bgTex->bind( 0 ); + safeSetColorA( 255, 255, 255, 255 - worldShade * 4 ); + + glBegin( GL_QUADS ); + glTexCoord2i( 0, 0 ); glVertex2i( worldStart, SCREEN_HEIGHT ); + glTexCoord2i( 1, 0 ); glVertex2i( -worldStart, SCREEN_HEIGHT ); + glTexCoord2i( 1, 1 ); glVertex2i( -worldStart, 0 ); + glTexCoord2i( 0, 1 ); glVertex2i( worldStart, 0 ); glEnd(); bgTex->bindNext(); - safeSetColorA(255,255,255,worldShade * 4); - glBegin(GL_QUADS); - glTexCoord2i(0,0);glVertex2i( cx_start,SCREEN_HEIGHT); - glTexCoord2i(1,0);glVertex2i(-cx_start,SCREEN_HEIGHT); - glTexCoord2i(1,1);glVertex2i(-cx_start,0); - glTexCoord2i(0,1);glVertex2i( cx_start,0); + safeSetColorA( 255, 255, 255, worldShade * 4 ); + + glBegin( GL_QUADS ); + glTexCoord2i( 0, 0 ); glVertex2i( worldStart, SCREEN_HEIGHT ); + glTexCoord2i( 1, 0 ); glVertex2i( -worldStart, SCREEN_HEIGHT ); + glTexCoord2i( 1, 1 ); glVertex2i( -worldStart, 0 ); + glTexCoord2i( 0, 1 ); glVertex2i( worldStart, 0 ); glEnd(); - glDisable(GL_TEXTURE_2D); - - /* - * Draws stars if it is an appropriate time of day for them. - */ + + glDisable( GL_TEXTURE_2D ); + + // draw the stars if the time deems it appropriate + + //if (((( weather == WorldWeather::Dark ) & ( tickCount % DAY_CYCLE )) < DAY_CYCLE / 2) || + // ((( weather == WorldWeather::Sunny ) & ( tickCount % DAY_CYCLE )) > DAY_CYCLE * .75) ){ + if ( worldShade > 0 ) { - if((((weather==DARK )&(tickCount%DAY_CYCLE))<DAY_CYCLE/2) || - (((weather==SUNNY)&(tickCount%DAY_CYCLE))>DAY_CYCLE*.75) ){ - - if(tickCount % DAY_CYCLE){ // The above if statement doesn't check for exact midnight. - - safeSetColorA(255,255,255,bgshade + getRand() % 30 - 15); - for(i = 0; i < 100; i++){ - glRectf(star[i].x+offset.x*.9, - star[i].y, - star[i].x+offset.x*.9+HLINE, - star[i].y+HLINE - ); - } - + safeSetColorA( 255, 255, 255, 255 - (getRand() % 30 - 15) ); + + for ( i = 0; i < 100; i++ ) { + glRectf(star[i].x + offset.x * .9, + star[i].y, + star[i].x + offset.x * .9 + HLINE, + star[i].y + HLINE + ); } - } - + } - glEnable(GL_TEXTURE_2D); - - /* - * Draw the mountains. - */ - bgTex->bindNext(); - safeSetColorA(150-bgshade,150-bgshade,150-bgshade,220); + // draw remaining background items - glBegin(GL_QUADS); - for(int i = 0; i <= width/1920; i++){ - glTexCoord2i(0,1);glVertex2i(width/-2+(1920*i )+offset.x*.85,base); - glTexCoord2i(1,1);glVertex2i(width/-2+(1920*(i+1))+offset.x*.85,base); - glTexCoord2i(1,0);glVertex2i(width/-2+(1920*(i+1))+offset.x*.85,base+1080); - glTexCoord2i(0,0);glVertex2i(width/-2+(1920*i )+offset.x*.85,base+1080); + glEnable( GL_TEXTURE_2D ); + + bgTex->bindNext(); + safeSetColorA( 150 + shadeBackground * 2, 150 + shadeBackground * 2, 150 + shadeBackground * 2, 255 ); + + glBegin( GL_QUADS ); + for ( i = 0; i <= (int)(worldData.size() * HLINE / 1920); i++ ) { + glTexCoord2i( 0, 1 ); glVertex2i( width / 2 * -1 + (1920 * i ) + offset.x * .85, GROUND_HEIGHT_MINIMUM ); + glTexCoord2i( 1, 1 ); glVertex2i( width / 2 * -1 + (1920 * (i + 1)) + offset.x * .85, GROUND_HEIGHT_MINIMUM ); + glTexCoord2i( 1, 0 ); glVertex2i( width / 2 * -1 + (1920 * (i + 1)) + offset.x * .85, GROUND_HEIGHT_MINIMUM + 1080 ); + glTexCoord2i( 0, 0 ); glVertex2i( width / 2 * -1 + (1920 * i ) + offset.x * .85, GROUND_HEIGHT_MINIMUM + 1080 ); } glEnd(); - /* - * Draw four layers of trees. - */ - - for(i = 0; i < 4; i++){ + for ( i = 0; i < 4; i++ ) { bgTex->bindNext(); - safeSetColorA(bgDraw[i][0]-bgshade,bgDraw[i][0]-bgshade,bgDraw[i][0]-bgshade,bgDraw[i][1]); - - glBegin(GL_QUADS); - for(int j = cx_start; j <= -cx_start; j += 600){ - glTexCoord2i(0,1);glVertex2i( j +offset.x*bgDraw[i][2],base); - glTexCoord2i(1,1);glVertex2i((j+600)+offset.x*bgDraw[i][2],base); - glTexCoord2i(1,0);glVertex2i((j+600)+offset.x*bgDraw[i][2],base+400); - glTexCoord2i(0,0);glVertex2i( j +offset.x*bgDraw[i][2],base+400); + safeSetColorA( bgDraw[i][0] + shadeBackground * 2, bgDraw[i][0] + shadeBackground * 2, bgDraw[i][0] + shadeBackground * 2, bgDraw[i][1] ); + + glBegin( GL_QUADS ); + for( int j = worldStart; j <= -worldStart; j += 600 ){ + glTexCoord2i( 0, 1 ); glVertex2i( j + offset.x * bgDraw[i][2], GROUND_HEIGHT_MINIMUM ); + glTexCoord2i( 1, 1 ); glVertex2i( (j + 600) + offset.x * bgDraw[i][2], GROUND_HEIGHT_MINIMUM ); + glTexCoord2i( 1, 0 ); glVertex2i( (j + 600) + offset.x * bgDraw[i][2], GROUND_HEIGHT_MINIMUM + 400 ); + glTexCoord2i( 0, 0 ); glVertex2i( j + offset.x * bgDraw[i][2], GROUND_HEIGHT_MINIMUM + 400 ); } glEnd(); } - glDisable(GL_TEXTURE_2D); + glDisable( GL_TEXTURE_2D ); - glColor3ub(0,0,0); - glRectf(cx_start,GEN_MIN,-cx_start,0); + // draw black under backgrounds - /* - * World drawing is done recursively, meaning that this function jumps - * back as many 'layers' as it can and then draws, eventually coming - * back to the initial or 'root' layer. LOOP1 does the recursion back - * to the furthest behind layer, modifying shade and y offsets as it - * does. - * - */ + glColor3ub( 0, 0, 0 ); + glRectf( worldStart, GROUND_HEIGHT_MINIMUM, -worldStart, 0 ); - current=this; - shade=worldShade; + pOffset = (offset.x + p->width / 2 - worldStart) / HLINE; -//LOOP1: + /* + * Prepare for world ground drawing. + */ + + // only draw world within player vision + + if ((iStart = pOffset - (SCREEN_WIDTH / 2 / HLINE) - GROUND_HILLINESS) < 0) + iStart = 0; - //if(current->behind){ - - /* - * Add to the y offset and shade values (explained further below) - * and recurse. - * - */ - - /*yoff+=DRAW_Y_OFFSET; - shade+=DRAW_SHADE; - current=current->behind; - goto LOOP1; - }*/ - - /* - * Here is where the actual world drawing begins. A goto is made to - * LOOP2 once the current layer is drawn and the function shifts to - * draw the next closest layer. - */ - -//LOOP2: + if ((iEnd = pOffset + (SCREEN_WIDTH / 2 / HLINE) + GROUND_HILLINESS + HLINE) > (int)worldData.size()) + iEnd = worldData.size(); + else if (iEnd < GROUND_HILLINESS) + iEnd = GROUND_HILLINESS; - /* - * Calculate the offset in the line array that the player is (or would) - * currently be on. This function then calculates reasonable values for - * the 'for' loop below that draws the layer. - */ + // draw particles and buildings - v_offset=(offset.x + p->width / 2 - current->x_start) / HLINE; - - // is -> i start + std::for_each( particles.begin(), particles.end(), [](Particles part) { if ( part.behind ) part.draw(); }); - is=v_offset - (SCREEN_WIDTH / 2 / HLINE) - GEN_INC; - if(is<0)is=0; // Minimum bound + for ( auto &b : build ) + b->draw(); + + // draw light elements? - // ie -> i end + glEnable( GL_TEXTURE_2D ); + + glActiveTexture( GL_TEXTURE0 ); + bgTex->bindNext(); - ie=v_offset + (SCREEN_WIDTH / 2 / HLINE) + GEN_INC + HLINE; - if(ie>(int)current->lineCount)ie=current->lineCount; // Maximum bound - else if(ie < GEN_INC)ie = GEN_INC; + std::unique_ptr<GLfloat[]> pointArrayBuf = std::make_unique<GLfloat[]> (2 * (light.size() + p->light)); + auto pointArray = pointArrayBuf.get(); - /* - * Make more direct variables for quicker referencing. - */ + for ( i = 0; i < (int)light.size(); i++ ) { + pointArray[2 * i ] = light[i].loc.x - offset.x; + pointArray[2 * i + 1] = light[i].loc.y; + } - cline =current->line; - cx_start=current->x_start; + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); - /* - * Invert shading if desired. - */ + glUseProgram( shaderProgram ); + glUniform1i( glGetUniformLocation( shaderProgram, "sampler"), 0 ); + glUniform1f( glGetUniformLocation( shaderProgram, "amb" ), shadeAmbient ); - shade*=-1; + if ( p->light ) { + pointArray[2 * (light.size() + 1) ] = (float)( p->loc.x + SCREEN_WIDTH / 2 ); + pointArray[2 * (light.size() + 1) + 1] = (float)( p->loc.y ); + } - /* - * Draw structures. We draw structures behind the dirt/grass so that the building's - * corners don't stick out. - */ - - for(auto &part : particles){ - if(part->behind) - part->draw(); + if ( light.size() + (int)p->light == 0) + glUniform1i( glGetUniformLocation( shaderProgram, "numLight"), 0); + else { + glUniform1i ( glGetUniformLocation( shaderProgram, "numLight" ), light.size() + (int)p->light ); + glUniform2fv( glGetUniformLocation( shaderProgram, "lightLocation"), light.size() + (int)p->light, pointArray ); + glUniform3f ( glGetUniformLocation( shaderProgram, "lightColor" ), 1.0f, 1.0f, 1.0f ); } - for(auto &b : current->build){ - b->draw(); - } - /* - * Draw the layer up until the grass portion, which is done later. - */ - - bool hey=false; - glEnable(GL_TEXTURE_2D); - glActiveTexture(GL_TEXTURE0); - bgTex->bindNext(); + + /* + * Draw the dirt. + */ + + glBegin( GL_QUADS ); + + // faulty + /*glTexCoord2i(0 ,0);glVertex2i(pOffset - (SCREEN_WIDTH / 1.5),0); + glTexCoord2i(64,0);glVertex2i(pOffset + (SCREEN_WIDTH / 1.5),0); + glTexCoord2i(64,1);glVertex2i(pOffset + (SCREEN_WIDTH / 1.5),GROUND_HEIGHT_MINIMUM); + glTexCoord2i(0 ,1);glVertex2i(pOffset - (SCREEN_WIDTH / 1.5),GROUND_HEIGHT_MINIMUM);*/ - GLfloat pointArray[light.size() + (int)p->light][2]; - for(uint w = 0; w < light.size(); w++){ - pointArray[w][0] = light[w].loc.x - offset.x; - pointArray[w][1] = light[w].loc.y; - } - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); //for the s direction - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); //for the t direction - glUseProgram(shaderProgram); - glUniform1i(glGetUniformLocation(shaderProgram, "sampler"), 0); - glUniform1f(glGetUniformLocation(shaderProgram, "amb"), float(shade+50.0f)/100.0f); - if(p->light){ - //glUniform1i(glGetUniformLocation(shaderProgram, "numLight"), 1); - //glUniform2f(glGetUniformLocation(shaderProgram, "lightLocation"), p->loc.x - offset.x+SCREEN_WIDTH/2, p->loc.y); - //glUniform3f(glGetUniformLocation(shaderProgram, "lightColor"), 1.0f,1.0f,1.0f); - pointArray[light.size()+1][0] = (float)(p->loc.x + SCREEN_WIDTH/2); - pointArray[light.size()+1][1] = (float)(p->loc.y); - } - if(light.size()+(int)p->light == 0){ - glUniform1i(glGetUniformLocation(shaderProgram, "numLight"), 0); - }else{ - glUniform1i (glGetUniformLocation(shaderProgram, "numLight"), light.size()+(int)p->light); - glUniform2fv(glGetUniformLocation(shaderProgram, "lightLocation"), light.size()+(int)p->light, (GLfloat *)&pointArray); - glUniform3f (glGetUniformLocation(shaderProgram, "lightColor"), 1.0f,1.0f,1.0f); - } + for ( i = iStart; i < iEnd; i++ ) { + if ( worldData[i].groundHeight <= 0 ) { + worldData[i].groundHeight = GROUND_HEIGHT_MINIMUM - 1; + glColor4ub( 0, 0, 0, 255 ); + } else + safeSetColorA( 150, 150, 150, 255 ); - glBegin(GL_QUADS); + glTexCoord2i( 0, 0 ); glVertex2i(worldStart + i * HLINE , worldData[i].groundHeight - GRASS_HEIGHT ); + glTexCoord2i( 1, 0 ); glVertex2i(worldStart + i * HLINE + HLINE , worldData[i].groundHeight - GRASS_HEIGHT ); + + glTexCoord2i( 1, (int)(worldData[i].groundHeight / 64) + worldData[i].groundColor ); glVertex2i(worldStart + i * HLINE + HLINE, 0 ); + glTexCoord2i( 0, (int)(worldData[i].groundHeight / 64) + worldData[i].groundColor ); glVertex2i(worldStart + i * HLINE , 0 ); + + if ( worldData[i].groundHeight == GROUND_HEIGHT_MINIMUM - 1 ) + worldData[i].groundHeight = 0; + } - glTexCoord2i(0 ,0);glVertex2i(v_offset - (SCREEN_WIDTH / 1.5),0); - glTexCoord2i(64,0);glVertex2i(v_offset + (SCREEN_WIDTH / 1.5),0); - glTexCoord2i(64,1);glVertex2i(v_offset + (SCREEN_WIDTH / 1.5),base); - glTexCoord2i(0 ,1);glVertex2i(v_offset - (SCREEN_WIDTH / 1.5),base); - - for(i=is;i<(unsigned)ie-GEN_INC;i++){ - cline[i].y+=(yoff-DRAW_Y_OFFSET); // Add the y offset - if(!cline[i].y){ - cline[i].y=base; - hey=true; - glColor4ub(0,0,0,255); - }else safeSetColorA(150+shade*2,150+shade*2,150+shade*2,255); - glTexCoord2i(0,0); glVertex2i(cx_start+i*HLINE ,cline[i].y-GRASS_HEIGHT); - glTexCoord2i(1,0); glVertex2i(cx_start+i*HLINE+HLINE,cline[i].y-GRASS_HEIGHT); - glTexCoord2i(1,(int)(cline[i].y/64)+cline[i].color);glVertex2i(cx_start+i*HLINE+HLINE,0); - glTexCoord2i(0,(int)(cline[i].y/64)+cline[i].color);glVertex2i(cx_start+i*HLINE ,0); - cline[i].y-=(yoff-DRAW_Y_OFFSET); // Restore the line's y value - if(hey){ - hey=false; - cline[i].y=0; - } - } glEnd(); + glUseProgram(0); glDisable(GL_TEXTURE_2D); - /* - * Draw grass on every line. - */ - float cgh[2]; + /* + * Draw the grass/the top of the ground. + */ - glEnable(GL_TEXTURE_2D); - glActiveTexture(GL_TEXTURE0); + glEnable( GL_TEXTURE_2D ); + + glActiveTexture( GL_TEXTURE0 ); bgTex->bindNext(); - glUseProgram(shaderProgram); - glUniform1i(glGetUniformLocation(shaderProgram, "sampler"), 0); - //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); //for the s direction - //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); //for the t direction - //glBegin(GL_QUADS); + + glUseProgram( shaderProgram ); + glUniform1i( glGetUniformLocation( shaderProgram, "sampler"), 0); - for(i=is;i<(unsigned)ie-GEN_INC;i++){ - - /* - * Load the current line's grass values - */ - - if(cline[i].y)memcpy(cgh,cline[i].gh,2*sizeof(float)); - else memset(cgh,0 ,2*sizeof(float)); - - - - /* - * Flatten the grass if the player is standing on it. - */ + float cgh[2]; + for ( i = iStart; i < iEnd - GROUND_HILLINESS; i++ ) { - if(!cline[i].gs){ - cgh[0]/=4; - cgh[1]/=4; + // load the current line's grass values + if ( worldData[i].groundHeight ) + memcpy( cgh, worldData[i].grassHeight, 2 * sizeof( float )); + else + memset( cgh, 0 , 2 * sizeof( float )); + + // flatten the grass if the player is standing on it. + if( !worldData[i].grassUnpressed ){ + cgh[0] /= 4; + cgh[1] /= 4; } - /* - * Actually draw the grass. - */ + // actually draw the grass. - cline[i].y+=(yoff-DRAW_Y_OFFSET); - safeSetColorA(255,255,255,255); - glBegin(GL_QUADS); - glTexCoord2i(0,0);glVertex2i(cx_start+i*HLINE ,cline[i].y+cgh[0]); - glTexCoord2i(1,0);glVertex2i(cx_start+i*HLINE+HLINE/2,cline[i].y+cgh[0]); - glTexCoord2i(1,1);glVertex2i(cx_start+i*HLINE+HLINE/2,cline[i].y-GRASS_HEIGHT); - glTexCoord2i(0,1);glVertex2i(cx_start+i*HLINE ,cline[i].y-GRASS_HEIGHT); - glEnd(); - - glBegin(GL_QUADS); - glTexCoord2i(0,0);glVertex2i(cx_start+i*HLINE+HLINE/2,cline[i].y+cgh[1]); - glTexCoord2i(1,0);glVertex2i(cx_start+i*HLINE+HLINE ,cline[i].y+cgh[1]); - glTexCoord2i(1,1);glVertex2i(cx_start+i*HLINE+HLINE ,cline[i].y-GRASS_HEIGHT); - glTexCoord2i(0,1);glVertex2i(cx_start+i*HLINE+HLINE/2,cline[i].y-GRASS_HEIGHT); + safeSetColorA( 255, 255, 255, 255 ); + + glBegin( GL_QUADS ); + glTexCoord2i( 0, 0 ); glVertex2i( worldStart + i * HLINE , worldData[i].groundHeight + cgh[0] ); + glTexCoord2i( 1, 0 ); glVertex2i( worldStart + i * HLINE + HLINE / 2, worldData[i].groundHeight + cgh[0] ); + glTexCoord2i( 1, 1 ); glVertex2i( worldStart + i * HLINE + HLINE / 2, worldData[i].groundHeight - GRASS_HEIGHT ); + glTexCoord2i( 0, 1 ); glVertex2i( worldStart + i * HLINE , worldData[i].groundHeight - GRASS_HEIGHT ); + glTexCoord2i( 0, 0 ); glVertex2i( worldStart + i * HLINE + HLINE / 2, worldData[i].groundHeight + cgh[1] ); + glTexCoord2i( 1, 0 ); glVertex2i( worldStart + i * HLINE + HLINE , worldData[i].groundHeight + cgh[1] ); + glTexCoord2i( 1, 1 ); glVertex2i( worldStart + i * HLINE + HLINE , worldData[i].groundHeight - GRASS_HEIGHT ); + glTexCoord2i( 0, 1 ); glVertex2i( worldStart + i * HLINE + HLINE / 2, worldData[i].groundHeight - GRASS_HEIGHT ); glEnd(); - - cline[i].y-=(yoff-DRAW_Y_OFFSET); } - //glEnd(); + glUseProgram(0); glDisable(GL_TEXTURE_2D); /* - * Draw non-structure entities. - */ - for(auto &part : particles){if(!part->behind)part->draw();} - for(auto &n : current->npc){ - n->loc.y+=(yoff-DRAW_Y_OFFSET); + * Draw remaining entities. + */ + + std::for_each( particles.begin(), particles.end(), [](Particles part) { if ( !part.behind ) part.draw(); }); + + for ( auto &n : npc ) n->draw(); - n->loc.y-=(yoff-DRAW_Y_OFFSET); - } - for(auto &m : current->mob){ - m->loc.y+=(yoff-DRAW_Y_OFFSET); + + for ( auto &m : mob ) m->draw(); - m->loc.y-=(yoff-DRAW_Y_OFFSET); - } - for(auto &o : current->object){ - if(o->alive){ - o->loc.y+=(yoff-DRAW_Y_OFFSET); - o->draw(); - o->loc.y-=(yoff-DRAW_Y_OFFSET); - } - } - - /* - * If we're drawing the closest/last world, handle and draw the player. - */ + + for ( auto &o : object ) + o->draw(); - if(current==this){ - - /* - * Calculate the line that the player is on - */ - - unsigned int ph = (p->loc.x + p->width / 2 - x_start) / HLINE; - - /* - * If the player is on the ground, flatten the grass where the player is standing - * by setting line.gs to false. - */ - - if(p->ground==1){ - for(i=0;i<lineCount-GEN_INC;i++){ - if(i < ph + 6 && - i > ph - 6 ) - cline[i].gs=false; - else cline[i].gs=true; - } - }else{ - for(i=0;i<lineCount-GEN_INC;i++){ - cline[i].gs=true; - } - } - - /* - * Draw the player. - */ - - p->draw(); - + /* + * Handle grass-squishing. + */ + + // calculate the line that the player is on + int ph = ( p->loc.x + p->width / 2 - worldStart ) / HLINE; + + // flatten grass under the player if the player is on the ground + if ( p->ground ) { + for ( i = 0; i < (int)(worldData.size() - GROUND_HILLINESS); i++ ) + worldData[i].grassUnpressed = !( i < ph + 6 && i > ph - 6 ); + } else { + for ( i = 0; i < (int)(worldData.size() - GROUND_HILLINESS); i++ ) + worldData[i].grassUnpressed = true; } - - /* - * Restore the inverted shading if it was inverted above. - */ - - shade*=-1; - + /* - * Draw the next closest world if it exists. - */ - - /*if(current->infront){ - yoff -= DRAW_Y_OFFSET; - shade -= DRAW_SHADE; - - current=current->infront; - goto LOOP2; - - }else{*/ - - /* - * If finished, reset the yoff and shade variables for the next call. - */ - - yoff=DRAW_Y_OFFSET; - shade=0; - //} + * Draw the player. + */ + + p->draw(); } -void World::singleDetect(Entity *e){ +/** + * Handles physics and such for a single entity. + * + * This function is kept private, as World::detect() should be used instead to + * handle stuffs for all entities at once. + */ + +void World:: +singleDetect( Entity *e ) +{ + std::string killed; unsigned int i,j; int l; @@ -795,12 +692,12 @@ void World::singleDetect(Entity *e){ * Kill any dead entities. */ - if(!e->alive||e->health<=0){ - for(i=0;i<entity.size();i++){ - if(entity[i]==e){ - switch(e->type){ + if ( !e->alive || e->health <= 0 ) { + for ( i = 0; i < entity.size(); i++) { + if ( entity[i] == e ){ + switch ( e->type ) { case STRUCTURET: - std::cout<<"Killed a building..."<<std::endl; + killed = "structure"; for(j=0;j<build.size();j++){ if(build[j]==e){ delete build[j]; @@ -810,7 +707,7 @@ void World::singleDetect(Entity *e){ } break; case NPCT: - std::cout<<"Killed an NPC..."<<std::endl; + killed = "NPC"; for(j=0;j<npc.size();j++){ if(npc[j]==e){ delete npc[j]; @@ -820,7 +717,7 @@ void World::singleDetect(Entity *e){ } break; case MOBT: - std::cout<<"Killed a mob..."<<std::endl; + killed = "mob"; /*for(j=0;j<mob.size();j++){ if(mob[j]==e){ delete mob[j]; @@ -830,7 +727,7 @@ void World::singleDetect(Entity *e){ }*/ break; case OBJECTT: - std::cout<<"Killed an object..."<<std::endl; + killed = "object"; for(j=0;j<object.size();j++){ if(object[j]==e){ delete object[j]; @@ -842,6 +739,7 @@ void World::singleDetect(Entity *e){ default: break; } + std::cout << "Killed a " << killed << "..." << std::endl; entity.erase(entity.begin()+i); return; } @@ -853,16 +751,17 @@ void World::singleDetect(Entity *e){ /* * Handle only living entities. */ - + if(e->alive){ - if(e->type == MOBT && Mobp(e)->subtype == MS_TRIGGER)return; + if ( e->type == MOBT && Mobp(e)->subtype == MS_TRIGGER ) + return; /* * Calculate the line that this entity is currently standing on. */ - l=(e->loc.x + e->width / 2 - x_start) / HLINE; + l=(e->loc.x + e->width / 2 - worldStart) / HLINE; if(l < 0) l=0; i = l; if(i > lineCount-1) i=lineCount-1; @@ -871,39 +770,11 @@ void World::singleDetect(Entity *e){ * If the entity is under the world/line, pop it back to the surface. */ - if(e->loc.y < line[i].y){ - - /* - * Check that the entity isn't trying to run through a wall. - */ - - //if(e->loc.y + e->height > line[i-(int)e->width/2/HLINE].y && - // e->loc.y + e->height > line[i+(int)e->width/2/HLINE].y ){ - - e->loc.y=line[i].y - .001 * deltaTime; - e->ground=true; - e->vel.y=0; - - //}else{ - - /* - * Push the entity out of the wall if it's trying to go through it. - */ - - /*do{ - e->loc.x+=.001 * e->vel.x>0?-1:1; - - l=(e->loc.x - e->width / 2 - x_start) / HLINE; - if(l < 0){ - std::cout<<"push kill lol "<<e->type<<std::endl; - e->alive = false; return; } - i = l; - if(i > lineCount-1){ - std::cout<<"push kill lol "<<e->type<<std::endl; - e->alive = false; return; } - }while(line[i].y>e->loc.y+ e->height); - - }*/ + if ( e->loc.y < worldData[i].groundHeight ) { + + e->loc.y= worldData[i].groundHeight - .001 * deltaTime; + e->ground=true; + e->vel.y=0; /* * Handle gravity if the entity is above the line. @@ -912,7 +783,7 @@ void World::singleDetect(Entity *e){ }else{ if(e->type == STRUCTURET && e->loc.y > 2000){ - e->loc.y = line[i].y; + e->loc.y = worldData[i].groundHeight; e->vel.y = 0; e->ground = true; return; @@ -924,129 +795,126 @@ void World::singleDetect(Entity *e){ * Insure that the entity doesn't fall off either edge of the world. */ - if(e->loc.x < x_start){ // Left bound + if(e->loc.x < worldStart){ // Left bound e->vel.x=0; - e->loc.x=(float)x_start + HLINE / 2; + e->loc.x=(float)worldStart + HLINE / 2; - }else if(e->loc.x + e->width + HLINE > x_start + getWidth(this)){ // Right bound + }else if(e->loc.x + e->width + HLINE > worldStart + worldStart * -2){ // Right bound e->vel.x=0; - e->loc.x=x_start + getWidth(this) - e->width - HLINE; + e->loc.x=worldStart + worldStart * -2 - e->width - HLINE; } } } -void World::detect(Player *p){ - - /* - * Handle the player. - */ +/** + * Handle entity logic for the world. + * + * This function runs World::singleDetect() for the player and every entity + * currently in a vector of this world. Particles and village entrance/exiting + * are also handled here. + */ + +void World:: +detect( Player *p ) +{ + int l; - //auto pl = std::async(&World::singleDetect,this,p); - std::thread(&World::singleDetect,this, p).detach(); + // handle the player + std::thread( &World::singleDetect, this, p).detach(); - /* - * Handle all remaining entities in this world. - */ - -//LOOOOP: - for(auto &e : entity) + // handle other entities + for ( auto &e : entity ) std::thread(&World::singleDetect,this,e).detach(); - //hey->singleDetect(e); - for(auto &part : particles){ - int l; - unsigned int i; - l=(part->loc.x + part->width / 2 - x_start) / HLINE; - if(l < 0) l=0; - i = l; - if(i > lineCount-1) i=lineCount-1; - if(part->loc.y < line[i].y){ - part->loc.y = line[i].y; - part->vely = 0; - part->velx = 0; - part->canMove = false; - }else{ - if(part->gravity && part->vely > -2)part->vely-=.003 * deltaTime; - } - } - for(auto &b : build){ - switch(b->bsubtype){ - case FOUNTAIN: - for(int r = 0; r < (rand()%25)+10;r++){ - addParticle( rand()%HLINE*3 + b->loc.x + b->width/2, - b->loc.y + b->height, - HLINE*1.25, - HLINE*1.25, - rand()%2 == 0?-(rand()%7)*.01:(rand()%7)*.01, - ((4+rand()%6)*.05), - {0,0,255}, - 2500); - - particles.back()->fountain = true; - } - break; - case FIRE_PIT: - for(int r = 0; r < (rand()%20)+10;r++){ - addParticle(rand()%(int)(b->width/2) + b->loc.x+b->width/4, b->loc.y+3*HLINE, HLINE, HLINE, rand()%2 == 0?-(rand()%3)*.01:(rand()%3)*.01,((4+rand()%6)*.005), {255,0,0}, 400); - particles.back()->gravity = false; - particles.back()->behind = true; - } - break; - default: break; + + // handle particles + for ( auto &part : particles ) { + + // get particle's current world line + l = (part.loc.x + part.width / 2 - worldStart) / HLINE; + + if ( l < 0 ) + l = 0; + + if ( l > (int)(lineCount - 1) ) + l = lineCount - 1; + + // handle ground collision + if ( part.loc.y < worldData[l].groundHeight ) { + part.loc.y = worldData[l].groundHeight; + part.vely = 0; + part.velx = 0; + part.canMove = false; + } else if ( part.gravity && part.vely > -2 ) + part.vely -= .003 * deltaTime; + } + + // handle particle creation + for ( auto &b : build ) { + switch ( b->bsubtype ) { + case FOUNTAIN: + for ( unsigned int r = (randGet() % 25) + 11; r--; ) { + addParticle(randGet() % HLINE * 3 + b->loc.x + b->width / 2, // x + b->loc.y + b->height, // y + HLINE * 1.25, // width + HLINE * 1.25, // height + randGet() % 7 * .01 * (randGet() % 2 == 0 ? -1 : 1), // vel.x + (4 + randGet() % 6) * .05, // vel.y + { 0, 0, 255 }, // RGB color + 2500 // duration (ms) + ); + + particles.back().fountain = true; + } + break; + + case FIRE_PIT: + for(unsigned int r = (randGet() % 20) + 11; r--; ) { + addParticle(randGet() % (int)(b->width / 2) + b->loc.x + b->width / 4, // x + b->loc.y + 3 * HLINE, // y + HLINE, // width + HLINE, // height + randGet() % 3 * .01 * (randGet() % 2 == 0 ? -1 : 1), // vel.x + (4 + randGet() % 6) * .005, // vel.y + { 255, 0, 0 }, // RGB color + 400 // duration (ms) + ); + + particles.back().gravity = false; + particles.back().behind = true; + } + break; + + default: + break; } } - for(auto &v : village){ - if(p->loc.x > v.start.x && p->loc.x < v.end.x){ - if(!v.in){ - ui::passiveImportantText(5000,"Welcome to %s",v.name.c_str()); - v.in = true; + // draws the village welcome message if the player enters the village bounds + for ( auto &v : village ) { + if ( p->loc.x > v->start.x && p->loc.x < v->end.x ) { + if ( !v->in ) { + ui::passiveImportantText( 5000, "Welcome to %s", v->name.c_str() ); + v->in = true; } - }else{ - v.in = false; - } + } else + v->in = false; } - - /*if(hey->infront){ - hey = hey->infront; - goto LOOOOP; - }*/ } -void World::addStructure(BUILD_SUB sub, float x,float y, char *tex, const char *inside){ +void World::addStructure(BUILD_SUB sub, float x,float y, std::string tex, std::string inside){ build.push_back(new Structures()); build.back()->inWorld = this; build.back()->textureLoc = tex; + build.back()->spawn(sub,x,y); - - if(inside) - strcpy((build.back()->inside = new char[1 + strlen(inside)]),inside); - else - strcpy((build.back()->inside = new char[1]),"\0"); - - //strcpy((build.back()->outside = new char[1 + strlen((char *)(currentXML+4))]),(char *)(currentXML+4)); + build.back()->inside = inside; + entity.push_back(build.back()); } - -/*void World::addVillage(int bCount, int npcMin, int npcMax,const char *inside){ - std::cout << npcMin << ", " << npcMax << std::endl; - //int xwasd; - for(int i = 0; i < bCount; i++){ - addStructure(HOUSE,x_start + (i * 300),100,inside); - std::cout<<"1\n"; - HERE: - xwasd = (rand()%(int)x+1000*HLINE); - for(auto &bu : build){ - if(xwasd > bu->loc.x && xwasd < bu->loc.x+bu->width)goto HERE; - } - std::cout<<"2\n"; - addStructure(t,HOUSE,xwasd,y,inside); - std::cout<<"3\n"; - } -}*/ void World::addMob(int t,float x,float y){ mob.push_back(new Mob(t)); @@ -1070,55 +938,37 @@ void World::addNPC(float x,float y){ entity.push_back(npc.back()); } -void World::addObject(/*ITEM_ID i*/std::string in,const char *p, float x, float y){ +void World::addMerchant(float x, float y){ + merchant.push_back(new Merchant()); + merchant.back()->spawn(x,y); + + npc.push_back(merchant.back()); + entity.push_back(npc.back()); +} + +void World::addObject( std::string in, std::string p, float x, float y){ object.push_back(new Object(in,p)); object.back()->spawn(x,y); entity.push_back(object.back()); } -void World::addParticle(float x, float y, float w, float h, float vx, float vy, Color color, int d){ - particles.push_back(new Particles(x,y,w,h,vx,vy,color,d)); - particles.back()->canMove = true; +void World:: +addParticle( float x, float y, float w, float h, float vx, float vy, Color color, int d ) +{ + particles.emplace_back( x, y, w, h, vx, vy, color, d ); + particles.back().canMove = true; } void World::addLight(vec2 loc, Color color){ + Light l; if(light.size() < 64){ - light.push_back(Light()); - light.back().loc = loc; - light.back().color = color; + l.loc = loc; + l.color = color; + light.push_back(l); } } -/*void World::removeObject(Object i){ - object.delete[](i); -}*/ - -/* - * The rest of these functions are explained well enough in world.h ;) -*/ - -/*void World::addLayer(unsigned int width){ - if(behind){ - behind->addLayer(width); - return; - } - behind=new World(); - behind->generate(width); - behind->infront=this; - behind->star=star; - behind->bgmObj=bgmObj; - behind->bgTex=bgTex; -}*/ - -NPC *World::getAvailableNPC(void){ - for(auto &n : npc){ - if(n->aiFunc.empty()) - return n; - } - return (NPC *)NULL; -} - char *World::setToLeft(const char *file){ if(toLeft) delete[] toLeft; @@ -1138,13 +988,20 @@ char *World::setToRight(const char *file){ return toRight; } -World *World::goWorldLeft(Player *p){ +World *World:: +goWorldLeft( Player *p ) +{ World *tmp; - if(toLeft && p->loc.x < x_start + (int)HLINE * 15){ + + // check if player is at world edge + if(toLeft && p->loc.x < worldStart + HLINE * 15.0f){ + + // load world (`toLeft` conditional confirms existance) tmp = loadWorldFromXML(toLeft); - p->loc.x = -tmp->x_start - HLINE * 10; - p->loc.y = tmp->line[tmp->lineCount - 1].y; + // adjust player location + p->loc.x = tmp->worldStart - HLINE * -10.0f; + p->loc.y = tmp->worldData[tmp->lineCount - 1].groundHeight; return tmp; } @@ -1154,43 +1011,29 @@ World *World::goWorldLeft(Player *p){ World *World::goWorldRight(Player *p){ World *tmp; - if(toRight && p->loc.x + p->width > -x_start - HLINE * 15){ + if(toRight && p->loc.x + p->width > -worldStart - HLINE * 15){ tmp = loadWorldFromXML(toRight); - p->loc.x = tmp->x_start + (int)HLINE * 10; - p->loc.y = tmp->line[0].y; + p->loc.x = tmp->worldStart + HLINE * 10; + p->loc.y = GROUND_HEIGHT_MINIMUM; return tmp; } return this; } -/*World *World::goWorldBack(Player *p){ - if(behind&&p->loc.x>(int)(0-getWidth(behind)/2)&&p->loc.x<getWidth(behind)/2){ - return behind; - } - return this; -} - -World *World::goWorldFront(Player *p){ - if(infront&&p->loc.x>(int)(0-getWidth(infront)/2)&&p->loc.x<getWidth(infront)/2){ - return infront; - } - return this; -}*/ - -std::vector<char *>inside; -World *World::goInsideStructure(Player *p){ +World *World:: +goInsideStructure( Player *p ) +{ World *tmp; char *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 ){ - inside.push_back(new char[1 + strlen(currentXML)]); - strcpy(inside.back(),(char *)(currentXML+4)); + inside.push_back((std::string)(currentXML.c_str() + 4)); - tmp = loadWorldFromXML(b->inside); + tmp = loadWorldFromXML(b->inside.c_str()); ui::toggleBlackFast(); ui::waitForCover(); @@ -1200,16 +1043,17 @@ World *World::goInsideStructure(Player *p){ } } }else{ - strcpy((current = new char[strlen((char *)(currentXML + 4)) + 1]),(char *)(currentXML + 4)); - tmp = loadWorldFromXML(inside.back()); + strcpy((current = new char[strlen((const char *)(currentXML.c_str() + 4)) + 1]),(const char *)(currentXML.c_str() + 4)); + tmp = loadWorldFromXML(inside.back().c_str()); for(auto &b : tmp->build){ - if(!strcmp(current,b->inside)){ - p->loc.x = b->loc.x + (b->width / 2); - delete[] inside.back(); + if(!strcmp(current,b->inside.c_str())){ inside.pop_back(); ui::toggleBlackFast(); ui::waitForCover(); + + p->loc.x = b->loc.x + (b->width / 2); + ui::toggleBlackFast(); return tmp; @@ -1223,18 +1067,14 @@ World *World::goInsideStructure(Player *p){ void World::addHole(unsigned int start,unsigned int end){ unsigned int i; for(i=start;i<end;i++){ - line[i].y=0; + worldData[i].groundHeight = 0; } } -int World::getTheWidth(void){ - World *hey=this; -/*LOOP: - if(hey->infront){ - hey=hey->infront; - goto LOOP; - }*/ - return -hey->x_start*2; +int World:: +getTheWidth( void ) const +{ + return worldStart * -2; } void World::save(void){ @@ -1268,11 +1108,6 @@ void World::save(void){ out.close(); } -#include <sstream> - -extern int commonAIFunc(NPC *); -extern void commonTriggerFunc(Mob *); - void World::load(void){ std::string save,data,line; const char *filedata; @@ -1331,26 +1166,17 @@ IndoorWorld::IndoorWorld(void){ IndoorWorld::~IndoorWorld(void){ delete bgTex; - delete[] star; - delete[] line; deleteEntities(); } void IndoorWorld::generate(unsigned int width){ // Generates a flat area of width 'width' - unsigned int i; // Used for 'for' loops - lineCount=width+GEN_INC; // Sets line count to the desired width plus GEN_INC to remove incorrect line calculations. + lineCount=width+GROUND_HILLINESS; // Sets line count to the desired width plus GEN_INC to remove incorrect line calculations. if(lineCount<=0)abort(); - line = new struct line_t[lineCount]; //(struct line_t *)calloc(lineCount,sizeof(struct line_t)); // Allocate memory for the array 'line' - memset(line,0,lineCount*sizeof(struct line_t)); + worldData = std::vector<WorldData> (lineCount, WorldData { false, {0,0}, INDOOR_FLOOR_HEIGHT, 0 }); - for(i=0;i<lineCount;i++){ // Indoor areas don't have to be directly on the ground (i.e. 0)... - line[i].y=INDOOR_FLOOR_HEIGHT; - } - //behind=infront=NULL; // Set pointers to other worlds to NULL - //toLeft=toRight=NULL; // to avoid accidental calls to goWorld... functions - x_start=0-getWidth(this)/2+GEN_INC/2*HLINE; // Calculate x_start (explained in world.h) + worldStart = (width - GROUND_HILLINESS) * HLINE / 2 * -1; } void IndoorWorld::draw(Player *p){ @@ -1364,24 +1190,32 @@ void IndoorWorld::draw(Player *p){ glEnable(GL_TEXTURE_2D); - GLfloat pointArray[light.size()][2]; - for(uint w = 0; w < light.size(); w++){ - pointArray[w][0] = light[w].loc.x - offset.x; - pointArray[w][1] = light[w].loc.y; + std::unique_ptr<GLfloat[]> pointArrayBuf = std::make_unique<GLfloat[]> (2 * (light.size() + p->light)); + auto pointArray = pointArrayBuf.get(); + + for ( i = 0; i < light.size(); i++ ) { + pointArray[2 * i ] = light[i].loc.x - offset.x; + pointArray[2 * i + 1] = light[i].loc.y; } - glUseProgram(shaderProgram); - glUniform1i(glGetUniformLocation(shaderProgram, "sampler"), 0); - glUniform1f(glGetUniformLocation(shaderProgram, "amb"), 0.0f); - if(p->light){ - glUniform1i(glGetUniformLocation(shaderProgram, "numLight"), 1); - glUniform2f(glGetUniformLocation(shaderProgram, "lightLocation"), p->loc.x - offset.x+SCREEN_WIDTH/2, p->loc.y); - glUniform3f(glGetUniformLocation(shaderProgram, "lightColor"), 1.0f,1.0f,1.0f); - }else if(!light.size()){ - glUniform1i(glGetUniformLocation(shaderProgram, "numLight"), 0); - }else{ - glUniform1i(glGetUniformLocation(shaderProgram, "numLight"), light.size()); - glUniform2fv(glGetUniformLocation(shaderProgram, "lightLocation"), light.size(), (GLfloat *)&pointArray); - glUniform3f(glGetUniformLocation(shaderProgram, "lightColor"), 1.0f,1.0f,1.0f); + + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); + + glUseProgram( shaderProgram ); + glUniform1i( glGetUniformLocation( shaderProgram, "sampler"), 0 ); + glUniform1f( glGetUniformLocation( shaderProgram, "amb" ), 0.3f ); + + if ( p->light ) { + pointArray[2 * (light.size() + 1) ] = (float)( p->loc.x + SCREEN_WIDTH / 2 ); + pointArray[2 * (light.size() + 1) + 1] = (float)( p->loc.y ); + } + + if ( light.size() + (int)p->light == 0) + glUniform1i( glGetUniformLocation( shaderProgram, "numLight"), 0); + else { + glUniform1i ( glGetUniformLocation( shaderProgram, "numLight" ), light.size() + (int)p->light ); + glUniform2fv( glGetUniformLocation( shaderProgram, "lightLocation"), light.size() + (int)p->light, pointArray ); + glUniform3f ( glGetUniformLocation( shaderProgram, "lightColor" ), 1.0f, 1.0f, 1.0f ); } bgTex->bind(0); @@ -1389,13 +1223,11 @@ void IndoorWorld::draw(Player *p){ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); //for the t direction glColor4ub(255,255,255,255); - glBegin(GL_QUADS); - //for(j = x_start - SCREEN_WIDTH / 2;j < -x_start + SCREEN_WIDTH / 2; j += 512){ - glTexCoord2i(0,1); glVertex2i( x_start - SCREEN_WIDTH / 2,0); - glTexCoord2i((-x_start*2+SCREEN_WIDTH)/512,1);glVertex2i(-x_start + SCREEN_WIDTH / 2,0); - glTexCoord2i((-x_start*2+SCREEN_WIDTH)/512,0);glVertex2i(-x_start + SCREEN_WIDTH / 2,SCREEN_HEIGHT); - glTexCoord2i(0,0); glVertex2i( x_start - SCREEN_WIDTH / 2,SCREEN_HEIGHT); - //} + glBegin(GL_QUADS); + glTexCoord2i(0,1); glVertex2i( worldStart - SCREEN_WIDTH / 2,0); + glTexCoord2i((-worldStart*2+SCREEN_WIDTH)/512,1);glVertex2i(-worldStart + SCREEN_WIDTH / 2,0); + glTexCoord2i((-worldStart*2+SCREEN_WIDTH)/512,0);glVertex2i(-worldStart + SCREEN_WIDTH / 2,SCREEN_HEIGHT); + glTexCoord2i(0,0); glVertex2i( worldStart - SCREEN_WIDTH / 2,SCREEN_HEIGHT); glEnd(); glUseProgram(0); @@ -1422,14 +1254,14 @@ void IndoorWorld::draw(Player *p){ glUseProgram(shaderProgram); glUniform1i(glGetUniformLocation(shaderProgram, "sampler"), 0); glBegin(GL_QUADS); - for(;i < ie - GEN_INC;i++){ + for(;i < ie - GROUND_HILLINESS;i++){ safeSetColor(150,100,50); - x = x_start + i * HLINE; - glVertex2i(x ,line[i].y); - glVertex2i(x + HLINE,line[i].y); - glVertex2i(x + HLINE,line[i].y - 50); - glVertex2i(x ,line[i].y - 50); + x = worldStart + i * HLINE; + glVertex2i(x ,worldData[i].groundHeight); + glVertex2i(x + HLINE,worldData[i].groundHeight); + glVertex2i(x + HLINE,worldData[i].groundHeight - 50); + glVertex2i(x ,worldData[i].groundHeight - 50); } glEnd(); glUseProgram(0); @@ -1438,15 +1270,14 @@ void IndoorWorld::draw(Player *p){ * Draw all entities. */ - for(auto &part : particles) part->draw(); - for(auto &e : entity) e->draw(); - p->draw(); -} + for ( auto &part : particles ) + part.draw(); -extern bool inBattle; + for ( auto &e : entity ) + e->draw(); -std::vector<World *> battleNest; -std::vector<vec2> battleNestLoc; + p->draw(); +} Arena::Arena(World *leave,Player *p,Mob *m){ generate(800); @@ -1454,24 +1285,16 @@ Arena::Arena(World *leave,Player *p,Mob *m){ inBattle = true; mmob = m; - //exit = leave; - //pxy = p->loc; + mmob->aggressive = false; mob.push_back(m); entity.push_back(m); battleNest.push_back(leave); battleNestLoc.push_back(p->loc); - - star = new vec2[100]; - memset(star,0,100 * sizeof(vec2)); } Arena::~Arena(void){ - delete bgTex; - delete[] star; - delete[] line; - deleteEntities(); } @@ -1488,30 +1311,29 @@ World *Arena::exitArena(Player *p){ p->loc = battleNestLoc.back(); battleNestLoc.pop_back(); - //mmob->alive = false; + + mob.clear(); + mmob->alive = false; + return tmp; }else{ return this; } } -#include <tinyxml2.h> -using namespace tinyxml2; - -char *currentXML = NULL; - -extern World *currentWorld; - -World *loadWorldFromXML(const char *path){ - if(currentXML){ +World *loadWorldFromXML(std::string path){ + if ( !currentXML.empty() ) currentWorld->save(); - delete[] currentXML; - } - + return loadWorldFromXMLNoSave(path); } -World *loadWorldFromXMLNoSave(const char *path){ +/** + * Loads a world from the given XML file. + */ + +World * +loadWorldFromXMLNoSave( std::string path ) { XMLDocument xml; XMLElement *wxml; XMLElement *vil; @@ -1521,59 +1343,55 @@ World *loadWorldFromXMLNoSave(const char *path){ bool dialog,Indoor; const char *ptr,*name; - - unsigned int size = 5 + strlen(path); + + currentXML = (std::string)"xml/" + path; - if(currentXML) - delete[] currentXML; - memset((currentXML = new char[size]),0,size); - strcpy(currentXML,"xml/"); - strcat(currentXML,path); - - xml.LoadFile(currentXML); + xml.LoadFile(currentXML.c_str()); wxml = xml.FirstChildElement("World"); - vil = xml.FirstChildElement("World")->FirstChildElement("village"); if(wxml){ wxml = wxml->FirstChildElement(); + vil = xml.FirstChildElement("World")->FirstChildElement("village"); Indoor = false; tmp = new World(); }else if((wxml = xml.FirstChildElement("IndoorWorld"))){ wxml = wxml->FirstChildElement(); + vil = NULL; Indoor = true; tmp = new IndoorWorld(); } while(wxml){ name = wxml->Name(); + if(!strcmp(name,"link")){ if((ptr = wxml->Attribute("left"))) tmp->setToLeft(ptr); else if((ptr = wxml->Attribute("right"))) tmp->setToRight(ptr); - else abort(); + else + abort(); }else if(!strcmp(name,"style")){ - tmp->setStyle(wxml->Attribute("folder")); - tmp->setBackground((WORLD_BG_TYPE)wxml->UnsignedAttribute("background")); - tmp->setBGM(wxml->Attribute("bgm")); + tmp->setStyle(wxml->StrAttribute("folder")); + tmp->setBackground((WorldBGType)wxml->UnsignedAttribute("background")); + tmp->setBGM(wxml->StrAttribute("bgm")); }else if(!strcmp(name,"generation")){ if(!strcmp(wxml->Attribute("type"),"Random")){ if(Indoor) ((IndoorWorld *)tmp)->generate(wxml->UnsignedAttribute("width")); - else + else { + tmp->generate(wxml->UnsignedAttribute("width")); - }else if(Indoor){ + } + }else if(Indoor) abort(); - } }else if(!strcmp(name,"mob")){ unsigned int type; - type = wxml->UnsignedAttribute("type"); if(wxml->QueryFloatAttribute("x",&spawnx) != XML_NO_ERROR) - tmp->addMob(type,getRand() % tmp->getTheWidth() / 2,100); + tmp->addMob(type,0,100); else tmp->addMob(type,spawnx,wxml->FloatAttribute("y")); - if(wxml->QueryBoolAttribute("aggressive",&dialog) == XML_NO_ERROR) tmp->mob.back()->aggressive = dialog; @@ -1581,7 +1399,7 @@ World *loadWorldFromXMLNoSave(const char *path){ const char *npcname; if(wxml->QueryFloatAttribute("x",&spawnx) != XML_NO_ERROR) - tmp->addNPC(getRand() % tmp->getTheWidth() / 2.0f,100); + tmp->addNPC(0,100); else tmp->addNPC(spawnx,wxml->FloatAttribute("y")); @@ -1598,14 +1416,13 @@ World *loadWorldFromXMLNoSave(const char *path){ else tmp->npc.back()->dialogIndex = 9999; }else if(!strcmp(name,"structure")){ - ptr = wxml->Attribute("inside"); tmp->addStructure((BUILD_SUB)wxml->UnsignedAttribute("type"), wxml->QueryFloatAttribute("x",&spawnx) != XML_NO_ERROR ? getRand() % tmp->getTheWidth() / 2.0f : spawnx, 100, - (char*)wxml->Attribute("texture"), - ptr); + wxml->StrAttribute("texture"), + wxml->StrAttribute("inside")); }else if(!strcmp(name,"trigger")){ tmp->addMob(MS_TRIGGER,wxml->FloatAttribute("x"),0,commonTriggerFunc); tmp->mob.back()->heyid = wxml->Attribute("id"); @@ -1614,35 +1431,74 @@ World *loadWorldFromXMLNoSave(const char *path){ wxml = wxml->NextSiblingElement(); } + Village *vptr; + if(vil){ - tmp->village.push_back(vil->Attribute("name")); + tmp->village.push_back(new Village(vil->Attribute("name"), tmp)); + vptr = tmp->village.back(); vil = vil->FirstChildElement(); } while(vil){ name = vil->Name(); - randx = getRand() % tmp->getTheWidth() - (tmp->getTheWidth() / 2.0f); + randx = 0; + //static BuySell bs; /** * READS DATA ABOUT STRUCTURE CONTAINED IN VILLAGE */ + if(!strcmp(name,"structure")){ - ptr = vil->Attribute("inside"); tmp->addStructure((BUILD_SUB)vil->UnsignedAttribute("type"), + vil->QueryFloatAttribute("x", &spawnx) != XML_NO_ERROR ? randx : spawnx, + 100, + vil->StrAttribute("texture"), + vil->StrAttribute("inside")); + }else if(!strcmp(name, "stall")){ + if(!strcmp(vil->Attribute("type"),"market")){ + std::cout << "Market" << std::endl; + tmp->addStructure((BUILD_SUB)70, vil->QueryFloatAttribute("x", &spawnx) != XML_NO_ERROR ? randx : spawnx, 100, - (char*)vil->Attribute("texture"), - ptr); + vil->StrAttribute("texture"), + vil->StrAttribute("inside")); + tmp->addMerchant(0,100); + if(vil->FirstChildElement("buy")){ + std::cout << "Buy" << std::endl; + //Trade goodMeme(1,"Dank MayMay",1,"Sword"); + //tmp->merchant.back()->trade.push_back(Trade()); + }if(vil->FirstChildElement("sell")){ + std::cout << "Sell" << std::endl; + }if(vil->FirstChildElement("trade")){ + std::cout << "Trade" << std::endl; + tmp->merchant.back()->trade.push_back(Trade(vil->FirstChildElement("trade")->IntAttribute("quantity"), + vil->FirstChildElement("trade")->Attribute("item"), + vil->FirstChildElement("trade")->IntAttribute("quantity1"), + vil->FirstChildElement("trade")->Attribute("item1"))); + } + strcpy(tmp->merchant.back()->name,"meme"); - tmp->village.back().build.push_back(tmp->build.back()); + }else if(!strcmp(vil->Attribute("type"),"trader")){ + std::cout << "Trader" << std::endl; + tmp->addStructure((BUILD_SUB)71, + vil->QueryFloatAttribute("x", &spawnx) != XML_NO_ERROR ? + randx : spawnx, + 100, + vil->StrAttribute("texture"), + vil->StrAttribute("inside")); + } } - if(tmp->village.back().build.back()->loc.x < tmp->village.back().start.x){ - tmp->village.back().start.x = tmp->village.back().build.back()->loc.x; + + vptr->build.push_back(tmp->build.back()); + + if(vptr->build.back()->loc.x < vptr->start.x){ + vptr->start.x = vptr->build.back()->loc.x; } - if(tmp->village.back().build.back()->loc.x + tmp->village.back().build.back()->width > tmp->village.back().end.x){ - tmp->village.back().end.x = tmp->village.back().build.back()->loc.x + tmp->village.back().build.back()->width; + + if(vptr->build.back()->loc.x + vptr->build.back()->width > vptr->end.x){ + vptr->end.x = vptr->build.back()->loc.x + vptr->build.back()->width; } //go to the next element in the village block @@ -1656,4 +1512,12 @@ World *loadWorldFromXMLNoSave(const char *path){ } return tmp; -}
\ No newline at end of file + +} + +Village::Village(const char *meme, World *w){ + name = meme; + start.x = w->getTheWidth() / 2.0f; + end.x = -start.x; + in = false; +} |