/*
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);
}