From 1e6676c35ce4990981e8cda389ba39108437d66d Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Wed, 20 Jan 2016 08:42:46 -0500 Subject: WIP save/load --- Changelog | 6 +++ include/Texture.h | 2 + include/common.h | 2 + include/entities.h | 15 +++--- include/inventory.h | 3 +- include/ui.h | 2 + include/world.h | 3 ++ main.cpp | 42 +++++---------- src/Texture.cpp | 7 +++ src/common.cpp | 19 ++++++- src/entities.cpp | 2 + src/gameplay.cpp | 105 +++++++++++++++++++++++++++++-------- src/inventory.cpp | 4 ++ src/ui.cpp | 16 ++++-- src/world.cpp | 64 ++++++++++++++++++++-- xml/playerSpawnHill1_Building1.xml | 2 + 16 files changed, 227 insertions(+), 67 deletions(-) diff --git a/Changelog b/Changelog index a4c3ede..8b01fe7 100644 --- a/Changelog +++ b/Changelog @@ -547,3 +547,9 @@ - removed layers - switched world linking from pointers to file names, rewrote all world-linking code - worlds are now loaded dynamically + +1/19/2015: +========== + + - memory management + - began reconsidering save/load stuff diff --git a/include/Texture.h b/include/Texture.h index 85225d8..03593bf 100644 --- a/include/Texture.h +++ b/include/Texture.h @@ -28,6 +28,8 @@ namespace Texture{ */ GLuint loadTexture(const char *fileName); + + void freeTextures(void); } /** diff --git a/include/common.h b/include/common.h index ae832f1..fa7356a 100644 --- a/include/common.h +++ b/include/common.h @@ -205,6 +205,8 @@ unsigned int millis(void); int getdir(const char *dir, std::vector &files); void strVectorSortAlpha(std::vector *v); +const char *readFile(const char *path); + int strCreateFunc(const char *equ); extern void *NULLPTR; diff --git a/include/entities.h b/include/entities.h index d434546..6328770 100644 --- a/include/entities.h +++ b/include/entities.h @@ -63,15 +63,13 @@ public: bool gravity; bool behind; Particles(float x, float y, float w, float h, float vx, float vy, Color c, float d){ - loc.x = (x); - loc.y = (y); - width = (w); - height = (h); + loc.x = x; + loc.y = y; + width = w; + height = h; velx = vx; vely = vy; - color.red = (c.red); - color.green = (c.green); - color.blue = (c.blue); + color = c; duration = d; fountain = false; gravity = true; @@ -166,7 +164,7 @@ public: class NPC : public Entity{ public: std::vectoraiFunc; - unsigned int dialogIndex; + int dialogIndex; NPC(); ~NPC(); @@ -180,7 +178,6 @@ class Structures : public Entity{ public: BUILD_SUB bsubtype; char *inside; - //char *outside; Structures(); ~Structures(); diff --git a/include/inventory.h b/include/inventory.h index b035f91..a08954a 100644 --- a/include/inventory.h +++ b/include/inventory.h @@ -106,8 +106,9 @@ public: } }; -void itemUse(void *p); void initInventorySprites(void); +void destroyInventory(void); + char *getItemTexturePath(ITEM_ID id); int getItemWidth(ITEM_ID); int getItemHeight(ITEM_ID); diff --git a/include/ui.h b/include/ui.h index b769bbf..c018008 100644 --- a/include/ui.h +++ b/include/ui.h @@ -41,6 +41,8 @@ namespace ui { void initFonts(void); + void destroyFonts(void); + /* * Sets the current font/font size. */ diff --git a/include/world.h b/include/world.h index a1cc870..3209284 100644 --- a/include/world.h +++ b/include/world.h @@ -272,6 +272,9 @@ public: */ int getTheWidth(void); + + void save(void); + void load(void); }; /* diff --git a/main.cpp b/main.cpp index 7487e4c..76ea66e 100644 --- a/main.cpp +++ b/main.cpp @@ -166,25 +166,6 @@ void logic(void); void render(void); void mainLoop(void); -std::string readFile(const char *filePath) { - std::string content; - std::ifstream fileStream(filePath, std::ios::in); - - if(!fileStream.is_open()) { - std::cerr << "Could not read file " << filePath << ". File does not exist." << std::endl; - return ""; - } - - std::string line = ""; - while(!fileStream.eof()) { - std::getline(fileStream, line); - content.append(line + "\n"); - } - - fileStream.close(); - return content; -} - /* * This offset is used as the player offset in the world drawing so * everything can be moved according to the player @@ -253,7 +234,6 @@ int main(/*int argc, char *argv[]*/){ Mix_AllocateChannels(8); // Run Mix_Quit when main returns - atexit(Mix_CloseAudio); atexit(Mix_Quit); /* @@ -355,21 +335,21 @@ int main(/*int argc, char *argv[]*/){ std::cout << "Initializing shaders!" << std::endl; - fragShader = glCreateShader(GL_FRAGMENT_SHADER); - - std::string shaderFileContents = readFile("test.frag"); - const GLchar *shaderSource = shaderFileContents.c_str(); + const GLchar *shaderSource = readFile("test.frag"); - GLint bufferln = GL_FALSE; - int logLength; + GLint bufferln = 0; + int logLength; + fragShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragShader, 1, &shaderSource, NULL); glCompileShader(fragShader); glGetShaderiv(fragShader, GL_COMPILE_STATUS, &bufferln); glGetShaderiv(fragShader, GL_INFO_LOG_LENGTH, &logLength); - std::vectorfragShaderError((logLength > 1) ? logLength : 1); + + std::vector fragShaderError ((logLength > 1) ? logLength : 1); + glGetShaderInfoLog(fragShader, logLength, NULL, &fragShaderError[0]); std::cout << &fragShaderError[0] << std::endl; @@ -388,6 +368,7 @@ int main(/*int argc, char *argv[]*/){ glGetProgramInfoLog(shaderProgram, logLength, NULL, &programError[0]); std::cout << &programError[0] << std::endl; + delete[] shaderSource; //glEnable(GL_DEPTH_TEST); //THIS DOESN'T WORK ON LINUX glEnable(GL_MULTISAMPLE); @@ -432,7 +413,7 @@ int main(/*int argc, char *argv[]*/){ **** GAMELOOP **** **************************/ - gameRunning=true; + gameRunning = true; while(gameRunning){ mainLoop(); } @@ -446,9 +427,14 @@ int main(/*int argc, char *argv[]*/){ */ Mix_HaltMusic(); + Mix_CloseAudio(); fb.close(); + destroyInventory(); + ui::destroyFonts(); + Texture::freeTextures(); + SDL_GL_DeleteContext(mainGLContext); SDL_DestroyWindow(window); diff --git a/src/Texture.cpp b/src/Texture.cpp index 5e367a9..0dd1eff 100644 --- a/src/Texture.cpp +++ b/src/Texture.cpp @@ -63,6 +63,13 @@ namespace Texture{ return object; } + void freeTextures(void){ + for(unsigned int i=0;itex); + delete[] LoadedTexture[i]->name; + delete LoadedTexture[i]; + } + } } Texturec::Texturec(uint amt, ...){ diff --git a/src/common.cpp b/src/common.cpp index 2d35313..334671e 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -93,7 +93,24 @@ void strVectorSortAlpha(std::vector *v){ }while(change); } - +const char *readFile(const char *path){ + std::ifstream in (path,std::ios::in); + unsigned int size; + GLchar *buf; + + if(!in.is_open()){ + std::cout<<"Error reading file "< dopt; int commonAIFunc(NPC *speaker){ XMLDocument xml; XMLElement *exml,*oxml; + const char *name; unsigned int idx = 0; bool stop = false; + /* + * Load the current world's XML file into memory for reading. + */ + xml.LoadFile(currentXML); exml = xml.FirstChildElement("Dialog"); + /* + * Search for the correct dialog block. + */ + while(strcmp(exml->Attribute("name"),speaker->name)) exml = exml->NextSiblingElement(); exml = exml->FirstChildElement(); + /* + * Search for which text block should be used. + */ + do{ if(!strcmp(exml->Name(),"text")){ - if(exml->UnsignedAttribute("id") == speaker->dialogIndex){ + if(exml->UnsignedAttribute("id") == (unsigned)speaker->dialogIndex){ + + /* + * Handle any 'give' requests. + */ if((oxml = exml->FirstChildElement("give"))){ while(oxml){ @@ -43,64 +60,106 @@ int commonAIFunc(NPC *speaker){ } } + /* + * Handle any 'take' requests. + */ + + if((oxml = exml->FirstChildElement("take"))){ + while(oxml){ + player->inv->takeItem((ITEM_ID)oxml->UnsignedAttribute("id"),oxml->UnsignedAttribute("count")); + oxml = oxml->NextSiblingElement(); + } + } + + /* + * Handle dialog options. + */ + if((oxml = exml->FirstChildElement("option"))){ - const char *op; - char *bp1 = new char[1],*bp2,*tmp; - bp1[0] = '\0'; + + /* + * Convert the list of options into a single colon-separated string. + */ + + std::string optstr; + while(oxml){ - op = oxml->Attribute("text"); - - bp2 = new char[strlen(bp1) + strlen(op) + 2]; - strcpy(bp2,bp1); - bp2[idx++] = ':'; - strcpy(bp2+idx,op); - idx += strlen(op); + /* + * Create a buffer big enough for the next option. + */ + + optstr.append((std::string)":" + oxml->Attribute("text")); - tmp = bp1; - bp1 = bp2; - delete[] tmp; + /* + * Append the next option. + */ dopt.push_back(oxml); oxml = oxml->NextSiblingElement(); } - ui::dialogBox(speaker->name,bp1,false,exml->GetText()); + /* + * Get the player's choice, then set the XMLElement to the option's block. + */ + + ui::dialogBox(speaker->name,optstr.c_str(),false,exml->GetText()); ui::waitForDialog(); - if(ui::dialogOptChosen){ + + if(ui::dialogOptChosen) exml = dopt[ui::dialogOptChosen-1]; - } + while(!dopt.empty()) dopt.pop_back(); }else{ + + /* + * No options - simply print the text. + */ + ui::dialogBox(speaker->name,"",false,exml->GetText()); ui::waitForDialog(); } + + /* + * 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){ + if(exml->QueryUnsignedAttribute("callid",&idx) == XML_NO_ERROR) n->dialogIndex = idx; - } n->addAIFunc(commonAIFunc,false); break; } } } + + /* + * 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) + + if(exml->QueryBoolAttribute("stop",&stop) == XML_NO_ERROR && stop){ + speaker->dialogIndex = -1; return 0; - else if(exml->QueryBoolAttribute("pause",&stop) == XML_NO_ERROR && stop) + }else if(exml->QueryBoolAttribute("pause",&stop) == XML_NO_ERROR && stop){ + speaker->dialogIndex = -1; return 1; - else return commonAIFunc(speaker); + }else return commonAIFunc(speaker); } return 0; } } + exml = exml->NextSiblingElement(); + }while(exml); + return 0; } @@ -155,6 +214,8 @@ extern std::vector AIpreload; extern std::vector AIpreaddr; void destroyEverything(void){ + currentWorld->save(); + delete currentWorld; while(!AIpreload.empty()) AIpreload.pop_back(); diff --git a/src/inventory.cpp b/src/inventory.cpp index b6819d1..108051c 100644 --- a/src/inventory.cpp +++ b/src/inventory.cpp @@ -29,6 +29,10 @@ void initInventorySprites(void){ Mix_Volume(2,100); } +void destroyInventory(void){ + Mix_FreeChunk(swordSwing); +} + char *getItemTexturePath(ITEM_ID id){ return item[id].textureLoc; } diff --git a/src/ui.cpp b/src/ui.cpp index eecd7ef..2896102 100644 --- a/src/ui.cpp +++ b/src/ui.cpp @@ -67,6 +67,8 @@ unsigned int fadeIntensity = 0; bool inBattle = false; Mix_Chunk *battleStart; +Mix_Chunk *sanic; + namespace ui { /* @@ -119,9 +121,20 @@ namespace ui { DEBUG_printf("Initialized FreeType2.\n",NULL); #endif // DEBUG dialogClick = Mix_LoadWAV("assets/click.wav"); + battleStart = Mix_LoadWAV("assets/sounds/frig.wav"); + sanic = Mix_LoadWAV("assets/sounds/sanic.wav"); Mix_Volume(1,50); } + void destroyFonts(void){ + FT_Done_Face(ftf); + FT_Done_FreeType(ftl); + + Mix_FreeChunk(dialogClick); + Mix_FreeChunk(battleStart); + Mix_FreeChunk(sanic); + } + /* * Sets a new font family to use (*.ttf). */ @@ -740,8 +753,6 @@ DONE: break; case SDLK_LSHIFT: if(debug){ - Mix_Chunk *sanic; - sanic = Mix_LoadWAV("assets/sounds/sanic.wav"); Mix_PlayChannel(1,sanic,-1); player->speed = 4.0f; }else @@ -884,7 +895,6 @@ DONE: fadeEnable ^= true; fadeWhite = true; fadeFast = true; - battleStart = Mix_LoadWAV("assets/sounds/frig.wav"); Mix_PlayChannel(1,battleStart,0); } } diff --git a/src/world.cpp b/src/world.cpp index 3ad877b..ed1b522 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -102,7 +102,7 @@ void World::deleteEntities(void){ entity.pop_back(); } while(!particles.empty()){ - //delete particles.back(); + delete particles.back(); particles.pop_back(); } while(!light.empty()){ @@ -121,6 +121,9 @@ World::~World(void){ delete bgTex; delete[] star; delete[] line; + + delete[] toLeft; + delete[] toRight; deleteEntities(); } @@ -1150,6 +1153,51 @@ int World::getTheWidth(void){ return -hey->x_start*2; } +void World::save(void){ + static std::string data; + + std::string save = (std::string)currentXML + ".dat"; + std::ofstream out (save,std::ios::out | std::ios::binary); + + std::cout<<"Saving to "<dialogIndex) + "\n"); + + data.append("dOnE\0"); + out.write(data.c_str(),data.size()); + + out.close(); +} + +#include + +extern int commonAIFunc(NPC *); + +void World::load(void){ + std::string save,data,line; + + save = (std::string)currentXML + ".dat"; + data = readFile(save.c_str()); + std::istringstream iss (data); + + for(auto &n : npc){ + std::getline(iss,line); + if((n->dialogIndex = std::stoi(line)) != -1) + n->addAIFunc(commonAIFunc,false); + } + + while(std::getline(iss,line)){ + if(line == "dOnE") + break; + + std::cout<save(); delete[] currentXML; + } memset((currentXML = new char[size]),0,size); strcpy(currentXML,"xml/"); @@ -1388,6 +1438,7 @@ World *loadWorldFromXML(const char *path){ dialog = false; if(wxml->QueryBoolAttribute("hasDialog",&dialog) == XML_NO_ERROR && dialog) tmp->npc.back()->addAIFunc(commonAIFunc,false); + else tmp->npc.back()->dialogIndex = -1; }else if(!strcmp(name,"structure")){ ptr = wxml->Attribute("inside"); @@ -1398,5 +1449,12 @@ World *loadWorldFromXML(const char *path){ } wxml = wxml->NextSiblingElement(); } + + std::ifstream dat (((std::string)currentXML + ".dat").c_str()); + if(dat.good()){ + dat.close(); + tmp->load(); + } + return tmp; } diff --git a/xml/playerSpawnHill1_Building1.xml b/xml/playerSpawnHill1_Building1.xml index 1580bd2..f33fcf5 100644 --- a/xml/playerSpawnHill1_Building1.xml +++ b/xml/playerSpawnHill1_Building1.xml @@ -2,6 +2,8 @@