- 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
*/
GLuint loadTexture(const char *fileName);
+
+ void freeTextures(void);
}
/**
int getdir(const char *dir, std::vector<std::string> &files);
void strVectorSortAlpha(std::vector<std::string> *v);
+const char *readFile(const char *path);
+
int strCreateFunc(const char *equ);
extern void *NULLPTR;
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;
class NPC : public Entity{
public:
std::vector<int (*)(NPC *)>aiFunc;
- unsigned int dialogIndex;
+ int dialogIndex;
NPC();
~NPC();
public:
BUILD_SUB bsubtype;
char *inside;
- //char *outside;
Structures();
~Structures();
}
};
-void itemUse(void *p);
void initInventorySprites(void);
+void destroyInventory(void);
+
char *getItemTexturePath(ITEM_ID id);
int getItemWidth(ITEM_ID);
int getItemHeight(ITEM_ID);
void initFonts(void);
+ void destroyFonts(void);
+
/*
* Sets the current font/font size.
*/
*/
int getTheWidth(void);
+
+ void save(void);
+ void load(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
Mix_AllocateChannels(8);
// Run Mix_Quit when main returns
- atexit(Mix_CloseAudio);
atexit(Mix_Quit);
/*
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::vector<char>fragShaderError((logLength > 1) ? logLength : 1);
+
+ std::vector<char> fragShaderError ((logLength > 1) ? logLength : 1);
+
glGetShaderInfoLog(fragShader, logLength, NULL, &fragShaderError[0]);
std::cout << &fragShaderError[0] << std::endl;
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);
**** GAMELOOP ****
**************************/
- gameRunning=true;
+ gameRunning = true;
while(gameRunning){
mainLoop();
}
*/
Mix_HaltMusic();
+ Mix_CloseAudio();
fb.close();
+ destroyInventory();
+ ui::destroyFonts();
+ Texture::freeTextures();
+
SDL_GL_DeleteContext(mainGLContext);
SDL_DestroyWindow(window);
return object;
}
+ void freeTextures(void){
+ for(unsigned int i=0;i<LoadedTextureCounter;i++){
+ glDeleteTextures(1,&LoadedTexture[i]->tex);
+ delete[] LoadedTexture[i]->name;
+ delete LoadedTexture[i];
+ }
+ }
}
Texturec::Texturec(uint amt, ...){
}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 "<<path<<"!"<<std::endl;
+ abort();
+ }
+
+ in.seekg(0,in.end);
+ buf = new GLchar[(size = in.tellg())];
+ in.seekg(0,in.beg);
+ in.read(buf,size);
+
+ in.close();
+ return buf;
+}
/*int strCreateFunc(const char *equ){
static unsigned int size;
delete tex;
if(name)
delete[] name;
+ if(inside)
+ delete[] inside;
}
Mob::Mob(int sub){
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){
}
}
+ /*
+ * 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;
}
extern std::vector<NPC *> AIpreaddr;
void destroyEverything(void){
+ currentWorld->save();
+ delete currentWorld;
while(!AIpreload.empty())
AIpreload.pop_back();
Mix_Volume(2,100);
}
+void destroyInventory(void){
+ Mix_FreeChunk(swordSwing);
+}
+
char *getItemTexturePath(ITEM_ID id){
return item[id].textureLoc;
}
bool inBattle = false;
Mix_Chunk *battleStart;
+Mix_Chunk *sanic;
+
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).
*/
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
fadeEnable ^= true;
fadeWhite = true;
fadeFast = true;
- battleStart = Mix_LoadWAV("assets/sounds/frig.wav");
Mix_PlayChannel(1,battleStart,0);
}
}
entity.pop_back();
}
while(!particles.empty()){
- //delete particles.back();
+ delete particles.back();
particles.pop_back();
}
while(!light.empty()){
delete bgTex;
delete[] star;
delete[] line;
+
+ delete[] toLeft;
+ delete[] toRight;
deleteEntities();
}
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 "<<save<<" ..."<<std::endl;
+
+ //data.append(std::to_string(npc.size()) + "\n");
+ for(auto &n : npc)
+ data.append(std::to_string(n->dialogIndex) + "\n");
+
+ data.append("dOnE\0");
+ out.write(data.c_str(),data.size());
+
+ out.close();
+}
+
+#include <sstream>
+
+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<<line<<std::endl;
+ }
+
+ //abort();
+}
+
IndoorWorld::IndoorWorld(void){
}
char *currentXML = NULL;
-extern int commonAIFunc(NPC *);
+extern World *currentWorld;
World *loadWorldFromXML(const char *path){
XMLDocument xml;
unsigned int size = 5 + strlen(path);
- if(currentXML)
+ if(currentXML){
+ currentWorld->save();
delete[] currentXML;
+ }
memset((currentXML = new char[size]),0,size);
strcpy(currentXML,"xml/");
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");
}
wxml = wxml->NextSiblingElement();
}
+
+ std::ifstream dat (((std::string)currentXML + ".dat").c_str());
+ if(dat.good()){
+ dat.close();
+ tmp->load();
+ }
+
return tmp;
}
<IndoorWorld>
<style background="1" bgm="assets/music/theme_jazz.wav" />
<generation type="Random" width="300" />
+
+ <npc name="Bob" />
</IndoorWorld>