/* spacemaze - Fly a space ship through a maze and collect all the items. Copyright (C) 2000, 2001, 2002 John Ericson This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 2000-03-25 High / John Ericson john.ericson@home.se */ #include "level.h" void LevelStartDocument(level_s *level); void LevelEndDocument(level_s *level); void LevelCharacters(level_s *level, const xmlChar *ch, int len); void LevelStartElement(level_s *level, const xmlChar *name, const xmlChar **attrs); void LevelEndElement(level_s *level, const xmlChar *name); void LevelWarning(level_s *level, const char *msg, ...); void LevelError(level_s *level, const char *msg, ...); void LevelFatalError(level_s *level, const char *msg, ...); static xmlSAXHandler LevelSAXParser = { 0, /* internalSubset */ 0, /* isStandalone */ 0, /* hasInternalSubset */ 0, /* hasExternalSubset */ 0, /* resolveEntity */ 0, /* getEntity */ 0, /* entityDecl */ 0, /* notationDecl */ 0, /* attributeDecl */ 0, /* elementDecl */ 0, /* unparsedEntityDecl */ 0, /* setDocumentLocator */ (startDocumentSAXFunc) LevelStartDocument, /* startDocument */ (endDocumentSAXFunc) LevelEndDocument, /* endDocument */ (startElementSAXFunc) LevelStartElement, /* startElement */ (endElementSAXFunc) LevelEndElement, /* endElement */ 0, /* reference */ (charactersSAXFunc) LevelCharacters, /* characters */ 0, /* ignorableWhitespace */ 0, /* processingInstruction */ 0, /* comment */ (warningSAXFunc) LevelWarning, /* warning */ (errorSAXFunc) LevelError, /* error */ (fatalErrorSAXFunc) LevelFatalError, /* fatalError */ }; static state_s state; /* Used to buffer input from the characters callback */ static char ch_buffer[1024]; static int ch_buffer_len; int LoadLevel(level_s *level, const char *filename) { int ret = 0; xmlParserCtxtPtr ctxt; ctxt = xmlCreateFileParserCtxt(filename); if (ctxt == NULL) return -1; ctxt->sax = &LevelSAXParser; ctxt->userData = level; xmlParseDocument(ctxt); if (ctxt->wellFormed) ret = 0; else ret = -1; if (&LevelSAXParser != NULL) ctxt->sax = NULL; xmlFreeParserCtxt(ctxt); return ret; } void LevelStartDocument(level_s *level) { int i; /* Clean out the level variable */ strcpy(level->name, "(Noname)"); strcpy(level->version, "1.0"); level->gravity = 0; level->sizew = 640; level->sizeh = 480; level->size = 0; level->maxplayers = 1; level->numstartpos = 0; level->numitems = 0; /* Clean out the level.item array */ for (i = 0; i < MAXITEMS; i++) { //level->item[i].x = &level->item[i].sprite.x; //level->item[i].y = &level->item[i].sprite.y; level->item[i].type = 0; /*level->item[i].sprite.x = 0; level->item[i].sprite.y = 0; level->item[i].sprite.image->w = 0; level->item[i].sprite.image->h = 0;*/ level->item[i].color = 2; level->item[i].visible = true; level->item[i].activate = 0; } /* Clean out the level.playerstart array */ for (i = 0; i < MAXPLAYERS; i++) { level->playerstart[i].x = 0; level->playerstart[i].y = 0; } /* Clean out the level.landscape array */ for (i = 0; i < MAXLEVELSIZE; i++) { level->landscape[i].x = 0; level->landscape[i].y = 0; level->landscape[i].w = 0; level->landscape[i].h = 0; level->landscape[i].type = 1; level->landscape[i].visible = true; level->landscape[i].crashable = true; level->landscape[i].color = 4; level->landscape[i].activate = 0; } state = START; /* level->numstartpos = 0; */ } void LevelEndDocument(level_s *level) { /* Since we increase the element everytime we leave them (LevelEndElement), we have to decrease all one step at the end of the document parsing to get the right size. */ level->size--; level->numstartpos--; level->numitems--; } void LevelCharacters(level_s *level, const xmlChar *ch, int len) { /* An XML parser isn't guaranteed to return the entire contents of a tag in a characters callback therefor we use a buffer to bundle it all togehter and process the string in the call to end_element. */ char output[40]; int i; /* Copy ch to output */ for (i = 0; (i < len) && (i < 30);i++) output[i] = ch[i]; /* Put an NULL at the end */ output[i] = 0; strcat(ch_buffer, output); ch_buffer_len += len; } void LevelStartElement(level_s *level, const xmlChar *name, const xmlChar **attrs) { int i; if (strcmp(name, "Level") == 0) { state += LEVEL; /* Start parsing attrib line if there is any attribs */ /* This code could be generalized since its useful on several places */ if (attrs != NULL) if (strcmp(attrs[0], "version") == 0) strcpy(level->version, attrs[1]); else printf("Unknown attribut %s in %s found. Ignoring.\n", attrs[1], name); } else if (strcmp(name, "Info") == 0) state += INFO; else if (strcmp(name, "Name") == 0) state += NAME; else if (strcmp(name, "Author") == 0) state += AUTHOR; else if (strcmp(name, "Description") == 0) state += DESCRIPTION; else if (strcmp(name, "Gametype") == 0) state += GAMETYPE; else if (strcmp(name, "Settings") == 0) state += SETTINGS; else if (strcmp(name, "Gravity") == 0) state += GRAVITY; else if (strcmp(name, "Size") == 0) state += SIZE; else if (strcmp(name, "W") == 0) state += W; else if (strcmp(name, "H") == 0) state += H; else if (strcmp(name, "Items") == 0) state += ITEMS; else if (strcmp(name, "PlayerStart") == 0) { state += PLAYERSTART; level->numstartpos++; level->item[level->numitems].type = LEVEL_OBJ_STARTPOSPLAYER1; } else if (strcmp(name, "LandingPlate") == 0) { state += LANDINGPLATE; level->item[level->numitems].type = LEVEL_OBJ_LANDINGPLATE; } else if (strcmp(name, "X") == 0) state += X; else if (strcmp(name, "Y") == 0) state += Y; else if (strcmp(name, "Box") == 0) { state += BOX; level->item[level->numitems].type = LEVEL_OBJ_BOX; /* Start parsing attrib line if there is any attribs */ if (attrs != NULL) for (i = 0; attrs[i] != NULL; i+=2) if (strcmp(attrs[i], "color") == 0) level->item[level->numitems].color = strtol(attrs[i+1], NULL, 0); else if (strcmp(attrs[i], "activate") == 0) level->item[level->numitems].activate = strtol(attrs[i+1], NULL, 0); else printf("Unknown attribut %s in %s found. Ignoring.\n", attrs[i], name); } else if (strcmp(name, "Landscape") == 0) state += LANDSCAPE; else if (strcmp(name, "Rectangle") == 0) { state += RECTANGLE; /* Start parsing attrib line if there is any attribs */ if (attrs != NULL) for (i = 0; attrs[i] != NULL; i+=2) if (strcmp(attrs[i], "color") == 0) level->landscape[level->size].color = strtol(attrs[i+1], NULL, 0); else if (strcmp(attrs[i], "visible") == 0) level->landscape[level->size].visible = strtob((char *)attrs[i+1]); else if (strcmp(attrs[i], "crashable") == 0) level->landscape[level->size].crashable = strtob((char *)attrs[i+1]); else if (strcmp(attrs[i], "activate") == 0) level->landscape[level->size].activate = strtol(attrs[i+1], NULL, 0); else printf("Unknown attribut %s in %s found. Ignoring.\n", attrs[i], name); } else printf("Unknown Element <%s> found. Ignoring.\n", name); } void LevelEndElement(level_s *level, const xmlChar *name) { char *output; ch_buffer[ch_buffer_len] = 0; output = trim(ch_buffer); strcpy(ch_buffer, output); switch (state) { case (LEVEL + INFO + NAME): strcpy(level->name, ch_buffer); break; case (LEVEL + SETTINGS + GRAVITY): /* Why cant I use strtof? */ level->gravity = (float)strtod(ch_buffer, NULL); break; case (LEVEL + SETTINGS + SIZE + W): level->sizew = strtol(ch_buffer, NULL, 0); break; case (LEVEL + SETTINGS + SIZE + H): level->sizeh = strtol(ch_buffer, NULL, 0); break; case (LEVEL + ITEMS + PLAYERSTART + X): /* level->numstartpos gets crap */ level->playerstart[level->numstartpos].x = strtol(ch_buffer, NULL, 0); break; case (LEVEL + ITEMS + PLAYERSTART + Y): level->playerstart[level->numstartpos].y = strtol(ch_buffer, NULL, 0); break; case (LEVEL + ITEMS + LANDINGPLATE + X): level->item[level->numitems].x = strtol(ch_buffer, NULL, 0); break; case (LEVEL + ITEMS + LANDINGPLATE + Y): level->item[level->numitems].y = strtol(ch_buffer, NULL, 0); break; case (LEVEL + ITEMS + BOX + X): level->item[level->numitems].x = strtol(ch_buffer, NULL, 0); break; case (LEVEL + ITEMS + BOX + Y): level->item[level->numitems].y = strtol(ch_buffer, NULL, 0); break; case (LEVEL + LANDSCAPE + RECTANGLE + X): level->landscape[level->size].x = strtol(ch_buffer, NULL, 0); break; case (LEVEL + LANDSCAPE + RECTANGLE + Y): level->landscape[level->size].y = strtol(ch_buffer, NULL, 0); break; case (LEVEL + LANDSCAPE + RECTANGLE + W): level->landscape[level->size].w = strtol(ch_buffer, NULL, 0); break; case (LEVEL + LANDSCAPE + RECTANGLE + H): level->landscape[level->size].h = strtol(ch_buffer, NULL, 0); break; case (LEVEL + INFO + AUTHOR): case (LEVEL + INFO + DESCRIPTION): case (LEVEL + INFO + GAMETYPE): /* Info we dont use at the moment */ break; } /* Reset characters buffer */ ch_buffer[0] = 0; ch_buffer_len = 0; if (strcmp(name, "Level") == 0) state -= LEVEL; else if (strcmp(name, "Info") == 0) state -= INFO; else if (strcmp(name, "Name") == 0) state -= NAME; else if (strcmp(name, "Author") == 0) state -= AUTHOR; else if (strcmp(name, "Description") == 0) state -= DESCRIPTION; else if (strcmp(name, "Gametype") == 0) state -= GAMETYPE; else if (strcmp(name, "Settings") == 0) state -= SETTINGS; else if (strcmp(name, "Gravity") == 0) state -= GRAVITY; else if (strcmp(name, "Size") == 0) state -= SIZE; else if (strcmp(name, "W") == 0) state -= W; else if (strcmp(name, "H") == 0) state -= H; else if (strcmp(name, "Items") == 0) state -= ITEMS; else if (strcmp(name, "PlayerStart") == 0) { state -= PLAYERSTART; level->numstartpos++; level->numitems++; } else if (strcmp(name, "LandingPlate") == 0) { state -= LANDINGPLATE; level->numitems++; } else if (strcmp(name, "X") == 0) state -= X; else if (strcmp(name, "Y") == 0) state -= Y; else if (strcmp(name, "Box") == 0) { state -= BOX; level->numitems++; } else if (strcmp(name, "Landscape") == 0) state -= LANDSCAPE; else if (strcmp(name, "Rectangle") == 0) { state -= RECTANGLE; level->size++; } } void LevelWarning(level_s *level, const char *msg, ...) { va_list args; char buffer[255]; strcpy(buffer, "Loading level warning: "); va_start(args, msg); vsprintf(&buffer[strlen(buffer)], msg, args); printf("%s", buffer); va_end(args); } void LevelError(level_s *level, const char *msg, ...) { va_list args; char buffer[255]; strcpy(buffer, "Loading level error: "); va_start(args, msg); vsprintf(&buffer[strlen(buffer)], msg, args); printf("%s", buffer); va_end(args); } void LevelFatalError(level_s *level, const char *msg, ...) { va_list args; char buffer[255]; strcpy(buffer, "Loading level fatal error: "); va_start(args, msg); vsprintf(&buffer[strlen(buffer)], msg, args); printf("%s", buffer); va_end(args); }