2 Copyright (C) 2004-2010 Parallel Realities
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 char string[10][1024];
29 bool allowAtSkillLevel = false;
31 bool previouslyCleared = false;
35 Persistant *persistant = NULL;
36 PersistData *persistData = NULL;
40 if (!previouslyCleared)
42 token = strtok(NULL, "\n");
46 persistData = (PersistData*)persistData->next;
48 if (persistData == NULL)
51 token = persistData->data;
55 graphics.showLoading(1, 100);
59 allowAtSkillLevel = false;
61 sscanf(token, "%s", skillLevel);
63 if ((strstr(skillLevel, "E")) && (game.skill == 0))
65 allowAtSkillLevel = true;
68 if ((strstr(skillLevel, "M")) && (game.skill == 1))
70 allowAtSkillLevel = true;
73 if ((strstr(skillLevel, "H")) && (game.skill >= 2))
75 allowAtSkillLevel = true;
78 if ((strstr(skillLevel, "X")) && (game.skill == 3))
80 allowAtSkillLevel = true;
83 // This is just for practice missions
85 allowAtSkillLevel = true;
88 if (strstr(skillLevel, "//"))
89 allowAtSkillLevel = false;
91 if (strcmp("@EOF@", skillLevel) == 0)
96 if (allowAtSkillLevel)
98 sscanf(token, "%*s %s", mapEntity);
100 if (strcmp("STAGENAME", mapEntity) == 0)
102 sscanf(token, "%*s %*s %*c %[^\"] %*c", string[0]);
104 map.setName(string[0]);
105 game.setStageName(string[0]);
107 else if (strcmp("PREVIOUSLY_VISITED", mapEntity) == 0)
109 previouslyCleared = gameData.stagePreviouslyCleared(map.name);
111 if (previouslyCleared)
113 debug(("Reading Persistance Data...\n"));
114 persistant = map.getPersistant(map.name);
115 persistData = (PersistData*)persistant->dataList.getHead();
118 else if (strcmp("TIMELIMIT", mapEntity) == 0)
120 debug(("Loading Time Limit: %s\n", token));
121 sscanf(token, "%*s %*s %d %d", ¶m[0], ¶m[1]);
122 map.remainingMinutes = param[0];
123 map.remainingSeconds = param[1];
125 else if (strcmp("TRAIN", mapEntity) == 0)
127 sscanf(token, "%*s %*s %s %d %d %d %d %d %s %s", string[0], ¶m[0], ¶m[1], ¶m[2], ¶m[3], ¶m[4], string[1], string[2]);
128 map.addTrain(string[0], param[0], param[1], param[2], param[3], param[4], engine.getValueOfDefine(string[1]), engine.getValueOfDefine(string[2]));
130 else if (strcmp("DOOR", mapEntity) == 0)
132 sscanf(token, "%*s %*s %s %s %d %d %d %d %s", string[0], string[1], ¶m[0], ¶m[1], ¶m[2], ¶m[3], string[2]);
133 map.addDoor(string[0], engine.getValueOfDefine(string[1]), param[0], param[1], param[2], param[3], engine.getValueOfDefine(string[2]));
135 else if (strcmp("SWITCH", mapEntity) == 0)
137 sscanf(token, "%*s %*s %*c %[^\"] %*c %s %*c %[^\"] %*c %*c %[^\"] %*c %s %d %d %s", string[0], string[1], string[2], string[3], string[4], ¶m[0], ¶m[1], string[5]);
138 map.addSwitch(string[0], string[1], string[2], string[3], engine.getValueOfDefine(string[4]), param[0], param[1], engine.getValueOfDefine(string[5]));
140 else if (strcmp("ITEM", mapEntity) == 0)
142 sscanf(token, "%*s %*s %d %*c %[^\"] %*c %d %d %s", ¶m[0], string[0], ¶m[1], ¶m[2], string[1]);
144 addItem(param[0], string[0], param[1], param[2], string[1], 60, 1, 0, false);
146 if (param[0] >= ITEM_MISC)
151 else if (strcmp("OBSTACLE", mapEntity) == 0)
153 sscanf(token, "%*s %*s %*c %[^\"] %*c %d %d %s", string[0], ¶m[0], ¶m[1], string[1]);
155 addObstacle(string[0], param[0], param[1], string[1]);
157 else if (strcmp("OBJECTIVE", mapEntity) == 0)
159 sscanf(token, "%*s %*s %*c %[^\"] %*c %*c %[^\"] %*c %d %s", string[0], string[1], ¶m[0], string[2]);
161 map.addObjective(string[0], string[1], param[0], engine.getValueOfDefine(string[2]));
163 else if (strcmp("START", mapEntity) == 0)
165 sscanf(token, "%*s %*s %d %d", ¶m[0], ¶m[1]);
167 player.place(param[0], param[1]);
169 game.setCheckPoint(param[0], param[1]);
170 game.setObjectiveCheckPoint();
173 else if (strcmp("ENEMY", mapEntity) == 0)
175 if (!engine.devNoMonsters)
177 sscanf(token, "%*s %*s %*c %[^\"] %*c %d %d", string[0], ¶m[0], ¶m[1]);
179 if ((game.skill == 0) && (map.waterLevel != -1))
181 addEnemy("Aqua Blob", param[0], param[1], 0);
185 addEnemy(string[0], param[0], param[1], 0);
189 else if (strcmp("MIA", mapEntity) == 0)
191 sscanf(token, "%*s %*s %*c %[^\"] %*c %d %d %s", string[0], ¶m[0], ¶m[1], string[1]);
192 addMIA(string[0], param[0], param[1], engine.getValueOfDefine(string[1]));
195 else if (strcmp("REQUIREDMIAS", mapEntity) == 0)
197 sscanf(token, "%*s %*s %d", ¶m[0]);
198 map.requiredMIAs = param[0];
200 else if (strcmp("LINEDEF", mapEntity) == 0)
202 sscanf(token, "%*s %*s %*c %[^\"] %*c %s %*c %[^\"] %*c %d %d %d %d %s", string[0], string[1], string[2], ¶m[0], ¶m[1], ¶m[2], ¶m[3], string[3]);
204 addLineDef(string[0], string[1], string[2], param[0], param[1], param[2], param[3], engine.getValueOfDefine(string[3]));
206 else if (strcmp("SPAWNPOINT", mapEntity) == 0)
208 sscanf(token, "%*s %*s %s %d %d %s %s %d %d %s", string[0], ¶m[0], ¶m[1], string[1], string[2], ¶m[2], ¶m[3], string[3]);
209 map.addSpawnPoint(string[0], param[0], param[1], engine.getValueOfDefine(string[1]), engine.getValueOfDefine(string[2]), param[2], param[3], engine.getValueOfDefine(string[3]));
211 else if (strcmp("SPAWNABLE_ENEMY", mapEntity) == 0)
213 sscanf(token, "%*s %*s %*c %[^\"] %*c", string[0]);
214 map.setAllowableEnemy(getDefinedEnemy(string[0]));
216 else if (strcmp("TELEPORTER", mapEntity) == 0)
218 sscanf(token, "%*s %*s %s %d %d %d %d %s", string[0], ¶m[0], ¶m[1], ¶m[2], ¶m[3], string[1]);
219 addTeleporter(string[0], param[0], param[1], param[2], param[3], engine.getValueOfDefine(string[1]));
221 else if (strcmp("TRAP", mapEntity) == 0)
223 sscanf(token, "%*s %*s %s %s %d %d %d %d %d %d %d %d %s %s", string[0], string[1], ¶m[0], ¶m[1], ¶m[2], ¶m[3], ¶m[4], ¶m[5], ¶m[6], ¶m[7], string[2], string[3]);
224 addTrap(string[0], engine.getValueOfDefine(string[1]), param[0], param[1], param[2], param[3], param[4], param[5], param[6], param[7], string[2], engine.getValueOfDefine(string[3]));
226 else if (strcmp("SPRITE", mapEntity) == 0)
228 sscanf(token, "%*s %*s %[^\n\r]", string[0]);
229 loadSprite(string[0]);
231 else if (strcmp("DEFENEMY", mapEntity) == 0)
233 sscanf(token, "%*s %*s %[^\n\r]", string[0]);
234 loadEnemy(string[0]);
236 else if (strcmp("TILESET", mapEntity) == 0)
238 sscanf(token, "%*s %*s %s", string[0]);
239 map.evalTileset(string[0]);
240 graphics.loadMapTiles(string[0]);
242 else if (strcmp("CLIPPING", mapEntity) == 0)
244 sscanf(token, "%*s %*s %d %d %d %d", ¶m[0], ¶m[1], ¶m[2], ¶m[3]);
245 map.setClipping(param[0], param[1], param[2], param[3]);
247 else if (strcmp("AMBIENCE", mapEntity) == 0)
249 sscanf(token, "%*s %*s %s", string[0]);
250 audio.loadSound(SND_AMBIANCE, string[0]);
252 else if (strcmp("WATERLEVEL", mapEntity) == 0)
254 sscanf(token, "%*s %*s %d", ¶m[0]);
256 map.requiredWaterLevel = param[0];
258 if (!previouslyCleared)
260 map.waterLevel = param[0];
264 map.waterLevel = 281;
269 map.waterLevel = 281;
270 map.requiredWaterLevel = 222;
273 else if (strcmp("ALPHATILES", mapEntity) == 0)
275 for (int i = 0 ; i < 15 ; i++)
280 sscanf(token, "%d", ¶m[0]);
285 debug(("Setting Alpha for Tile %d\n", param[0]));
287 SDL_SetAlpha(graphics.tile[param[0]], SDL_SRCALPHA|SDL_RLEACCEL, 130);
298 else if (strcmp("BACKGROUND", mapEntity) == 0)
300 sscanf(token, "%*s %*s %s", string[0]);
301 graphics.loadBackground(string[0]);
303 else if (strcmp("MUSIC", mapEntity) == 0)
305 sscanf(token, "%*s %*s %s", string[0]);
306 audio.loadMusic(string[0]);
308 else if (allowAtSkillLevel)
310 graphics.showErrorAndExit("Symbol '%s' not recognised or not implemented in map data", mapEntity);
315 //debug(("Ignoring Line: %s\n", token));
320 We need to make sure the player doesn't appear in a wall that was previously
321 destroyed. Things like this aren't stored so we will just remove a block they
324 if (previouslyCleared)
326 int x = game.checkPointX;
327 int y = game.checkPointY;
332 if ((map.data[x][y] >= MAP_BREAKABLE) && (map.data[x][y] <= MAP_BREAKABLE2))
334 map.data[x][y] = MAP_AIR;
339 const char *getActiveState(bool active)
349 void createPersistantMapData()
351 if (!engine.loadDefines())
353 graphics.showErrorAndExit("Could not load map define list '%s'", "data/defines.h");
356 Persistant *persistant = (Persistant*)map.createPersistant(map.name);
359 if (perfectlyCompleted())
361 debug(("createPersistantMapData :: Perfect - Skipping\n"));
383 snprintf(line, sizeof line, "%c START %d %d\n", skill, (int)game.checkPointX, (int)game.checkPointY);
384 persistant->addLine(line);
390 Teleporter *teleporter;
392 SpawnPoint *spawnPoint;
396 ent = (Entity*)map.enemyList.getHead();
398 while (ent->next != NULL)
400 ent = (Entity*)ent->next;
401 snprintf(line, sizeof line, "%c ENEMY \"%s\" %d %d\n", skill, ent->name, (int)ent->x, (int)ent->y);
402 persistant->addLine(line);
405 ent = (Entity*)map.itemList.getHead();
407 while (ent->next != NULL)
409 ent = (Entity*)ent->next;
411 // Don't save items that are dying...
412 if (ent->flags & ENT_DYING)
417 snprintf(line, sizeof line, "%c ITEM %d \"%s\" %d %d %s\n", skill, ent->id, ent->name, (int)ent->x, (int)ent->y, ent->sprite[0]->name);
418 persistant->addLine(line);
421 ent = (Entity*)map.obstacleList.getHead();
423 while (ent->next != NULL)
425 ent = (Entity*)ent->next;
426 snprintf(line, sizeof line, "%c OBSTACLE \"%s\" %d %d %s\n", skill, ent->name, (int)ent->x, (int)ent->y, ent->sprite[0]->name);
427 persistant->addLine(line);
430 swt = (Switch*)map.switchList.getHead();
432 while (swt->next != NULL)
434 swt = (Switch*)swt->next;
435 define[0] = engine.getDefineOfValue("SWT_", swt->type);
436 define[1] = (char*)getActiveState(swt->activated);
438 snprintf(line, sizeof line, "%c SWITCH \"%s\" %s \"%s\" \"%s\" %s %d %d %s\n", skill, swt->name, swt->linkName, swt->requiredObjectName, swt->activateMessage, define[0], (int)swt->x, (int)swt->y, define[1]);
440 persistant->addLine(line);
443 train = (Train*)map.trainList.getHead();
445 while (train->next != NULL)
447 train = (Train*)train->next;
449 if (train->type != TR_TRAIN)
451 if (train->type >= TR_SLIDEDOOR)
453 define[0] = engine.getDefineOfValue("_SLIDE", train->type);
457 define[0] = engine.getDefineOfValue("_DOO", train->type);
460 define[1] = (char*)getActiveState(train->active);
461 snprintf(line, sizeof line, "%c DOOR %s %s %d %d %d %d %s\n", skill, train->name, define[0], train->startX, train->startY, train->endX, train->endY, define[1]);
465 define[0] = engine.getDefineOfValue("TR_A", train->waitAtStart);
466 define[1] = (char*)getActiveState(train->active);
467 snprintf(line, sizeof line, "%c TRAIN %s %d %d %d %d %d %s %s\n", skill, train->name, train->startX, train->startY, train->endX, train->endY, train->getPause(), define[0], define[1]);
470 persistant->addLine(line);
473 trap = (Trap*)map.trapList.getHead();
475 while (trap->next != NULL)
477 trap = (Trap*)trap->next;
478 define[0] = engine.getDefineOfValue("TRAP_TYPE", trap->type);
479 define[1] = (char*)getActiveState(trap->active);
480 snprintf(line, sizeof line, "%c TRAP %s %s %d %d %d %d %d %d %d %d %s %s\n", skill, trap->name, define[0], (int)trap->damage, (int)trap->speed, (int)trap->startX, (int)trap->startY, (int)trap->endX, (int)trap->endY, (int)trap->waitTime[0], (int)trap->waitTime[1], trap->sprite->name, define[1]);
481 persistant->addLine(line);
484 teleporter = (Teleporter*)map.teleportList.getHead();
486 while (teleporter->next != NULL)
488 teleporter = (Teleporter*)teleporter->next;
489 define[0] = (char*)getActiveState(teleporter->active);
490 snprintf(line, sizeof line, "%c TELEPORTER %s %d %d %d %d %s\n", skill, teleporter->name, (int)teleporter->x, (int)teleporter->y, (int)teleporter->destX, (int)teleporter->destY, define[0]);
491 persistant->addLine(line);
494 lineDef = (LineDef*)map.lineList.getHead();
496 while (lineDef->next != NULL)
498 lineDef = (LineDef*)lineDef->next;
499 define[0] = (char*)getActiveState(lineDef->activated);
500 snprintf(line, sizeof line, "%c LINEDEF \"%s\" %s \"%s\" %d %d %d %d %s\n", skill, lineDef->name, lineDef->linkName, lineDef->activateMessage, (int)lineDef->x, (int)lineDef->y, (int)lineDef->width, (int)lineDef->height, define[0]);
501 persistant->addLine(line);
504 spawnPoint = (SpawnPoint*)map.spawnList.getHead();
506 while (spawnPoint->next != NULL)
508 spawnPoint = (SpawnPoint*)spawnPoint->next;
509 define[0] = engine.getDefineOfValue("SPW_", spawnPoint->spawnType);
511 if (strstr(define[0], "HAZARD"))
513 define[1] = engine.getDefineOfValue("HAZARD_", spawnPoint->spawnSubType);
517 define[1] = engine.getDefineOfValue("SPW_", spawnPoint->spawnSubType);
520 define[2] = (char*)getActiveState(spawnPoint->active);
521 snprintf(line, sizeof line, "%c SPAWNPOINT %s %d %d %s %s %d %d %s\n", skill, spawnPoint->name, (int)spawnPoint->x, (int)spawnPoint->y, define[0], define[1], (int)(spawnPoint->minInterval / 60), (int)(spawnPoint->maxInterval / 60), define[2]);
522 persistant->addLine(line);
525 for (int i = 0 ; i < 10 ; i++)
527 if (map.getSpawnableEnemy(i) != NULL)
529 snprintf(line, sizeof line, "%c SPAWNABLE_ENEMY \"%s\"\n", skill, map.getSpawnableEnemy(i));
530 persistant->addLine(line);
534 if (map.waterLevel != -1)
536 snprintf(line, sizeof line, "%c WATERLEVEL %d\n", skill, (int)map.waterLevel);
537 persistant->addLine(line);
540 // We don't need this anymore. Remove it to free up some memory...
541 engine.defineList.clear();