2 Copyright (C) 2004-2011 Parallel Realities
3 Copyright (C) 2011-2015 Perpendicular Dimensions
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 See the GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 char string[10][1024];
30 bool allowAtSkillLevel = false;
32 bool previouslyCleared = false;
36 Persistant *persistant = NULL;
37 PersistData *persistData = NULL;
41 if (!previouslyCleared)
43 token = strtok(NULL, "\n");
47 persistData = (PersistData*)persistData->next;
49 if (persistData == NULL)
52 token = persistData->data;
56 graphics.showLoading(1, 100);
60 allowAtSkillLevel = false;
62 sscanf(token, "%s", skillLevel);
64 if ((strstr(skillLevel, "E")) && (game.skill == 0))
66 allowAtSkillLevel = true;
69 if ((strstr(skillLevel, "M")) && (game.skill == 1))
71 allowAtSkillLevel = true;
74 if ((strstr(skillLevel, "H")) && (game.skill >= 2))
76 allowAtSkillLevel = true;
79 if ((strstr(skillLevel, "X")) && (game.skill == 3))
81 allowAtSkillLevel = true;
84 // This is just for practice missions
86 allowAtSkillLevel = true;
89 if (strstr(skillLevel, "//"))
90 allowAtSkillLevel = false;
92 if (strcmp("@EOF@", skillLevel) == 0)
97 if (allowAtSkillLevel)
99 sscanf(token, "%*s %s", mapEntity);
101 if (strcmp("STAGENAME", mapEntity) == 0)
103 sscanf(token, "%*s %*s %*c %[^\"] %*c", string[0]);
105 map.setName(string[0]);
106 game.setStageName(string[0]);
108 else if (strcmp("PREVIOUSLY_VISITED", mapEntity) == 0)
110 previouslyCleared = gameData.stagePreviouslyCleared(map.name);
112 if (previouslyCleared)
114 debug(("Reading Persistance Data...\n"));
115 persistant = map.getPersistant(map.name);
116 persistData = (PersistData*)persistant->dataList.getHead();
119 else if (strcmp("TIMELIMIT", mapEntity) == 0)
121 debug(("Loading Time Limit: %s\n", token));
122 sscanf(token, "%*s %*s %d %d", ¶m[0], ¶m[1]);
123 map.remainingMinutes = param[0];
124 map.remainingSeconds = param[1];
126 else if (strcmp("TRAIN", mapEntity) == 0)
128 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]);
129 map.addTrain(string[0], param[0], param[1], param[2], param[3], param[4], engine.getValueOfDefine(string[1]), engine.getValueOfDefine(string[2]));
131 else if (strcmp("DOOR", mapEntity) == 0)
133 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]);
134 map.addDoor(string[0], engine.getValueOfDefine(string[1]), param[0], param[1], param[2], param[3], engine.getValueOfDefine(string[2]));
136 else if (strcmp("SWITCH", mapEntity) == 0)
138 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]);
139 map.addSwitch(string[0], string[1], string[2], string[3], engine.getValueOfDefine(string[4]), param[0], param[1], engine.getValueOfDefine(string[5]));
141 else if (strcmp("ITEM", mapEntity) == 0)
143 sscanf(token, "%*s %*s %d %*c %[^\"] %*c %d %d %s", ¶m[0], string[0], ¶m[1], ¶m[2], string[1]);
145 addItem(param[0], string[0], param[1], param[2], string[1], 60, 1, 0, false);
147 if (param[0] >= ITEM_MISC)
152 else if (strcmp("OBSTACLE", mapEntity) == 0)
154 sscanf(token, "%*s %*s %*c %[^\"] %*c %d %d %s", string[0], ¶m[0], ¶m[1], string[1]);
156 addObstacle(string[0], param[0], param[1], string[1]);
158 else if (strcmp("OBJECTIVE", mapEntity) == 0)
160 sscanf(token, "%*s %*s %*c %[^\"] %*c %*c %[^\"] %*c %d %s", string[0], string[1], ¶m[0], string[2]);
162 map.addObjective(string[0], string[1], param[0], engine.getValueOfDefine(string[2]));
164 else if (strcmp("START", mapEntity) == 0)
166 sscanf(token, "%*s %*s %d %d", ¶m[0], ¶m[1]);
168 player.place(param[0], param[1]);
170 game.setCheckPoint(param[0], param[1]);
171 game.setObjectiveCheckPoint();
174 else if (strcmp("ENEMY", mapEntity) == 0)
176 if (!engine.devNoMonsters)
178 sscanf(token, "%*s %*s %*c %[^\"] %*c %d %d", string[0], ¶m[0], ¶m[1]);
180 if ((game.skill == 0) && (map.waterLevel != -1))
182 addEnemy("Aqua Blob", param[0], param[1], 0);
186 addEnemy(string[0], param[0], param[1], 0);
190 else if (strcmp("MIA", mapEntity) == 0)
192 sscanf(token, "%*s %*s %*c %[^\"] %*c %d %d %s", string[0], ¶m[0], ¶m[1], string[1]);
193 addMIA(string[0], param[0], param[1], engine.getValueOfDefine(string[1]));
196 else if (strcmp("REQUIREDMIAS", mapEntity) == 0)
198 sscanf(token, "%*s %*s %d", ¶m[0]);
199 map.requiredMIAs = param[0];
201 else if (strcmp("LINEDEF", mapEntity) == 0)
203 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]);
205 addLineDef(string[0], string[1], string[2], param[0], param[1], param[2], param[3], engine.getValueOfDefine(string[3]));
207 else if (strcmp("SPAWNPOINT", mapEntity) == 0)
209 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]);
210 map.addSpawnPoint(string[0], param[0], param[1], engine.getValueOfDefine(string[1]), engine.getValueOfDefine(string[2]), param[2], param[3], engine.getValueOfDefine(string[3]));
212 else if (strcmp("SPAWNABLE_ENEMY", mapEntity) == 0)
214 sscanf(token, "%*s %*s %*c %[^\"] %*c", string[0]);
215 map.setAllowableEnemy(getDefinedEnemy(string[0]));
217 else if (strcmp("TELEPORTER", mapEntity) == 0)
219 sscanf(token, "%*s %*s %s %d %d %d %d %s", string[0], ¶m[0], ¶m[1], ¶m[2], ¶m[3], string[1]);
220 addTeleporter(string[0], param[0], param[1], param[2], param[3], engine.getValueOfDefine(string[1]));
222 else if (strcmp("TRAP", mapEntity) == 0)
224 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]);
225 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]));
227 else if (strcmp("SPRITE", mapEntity) == 0)
229 sscanf(token, "%*s %*s %[^\n\r]", string[0]);
230 loadSprite(string[0]);
232 else if (strcmp("DEFENEMY", mapEntity) == 0)
234 sscanf(token, "%*s %*s %[^\n\r]", string[0]);
235 loadEnemy(string[0]);
237 else if (strcmp("TILESET", mapEntity) == 0)
239 sscanf(token, "%*s %*s %s", string[0]);
240 map.evalTileset(string[0]);
241 graphics.loadMapTiles(string[0]);
243 else if (strcmp("CLIPPING", mapEntity) == 0)
245 sscanf(token, "%*s %*s %d %d %d %d", ¶m[0], ¶m[1], ¶m[2], ¶m[3]);
246 map.setClipping(param[0], param[1], param[2], param[3]);
248 else if (strcmp("AMBIENCE", mapEntity) == 0)
250 sscanf(token, "%*s %*s %s", string[0]);
251 audio.loadSound(SND_AMBIANCE, string[0]);
253 else if (strcmp("WATERLEVEL", mapEntity) == 0)
255 sscanf(token, "%*s %*s %d", ¶m[0]);
257 map.requiredWaterLevel = param[0];
259 if (!previouslyCleared)
261 map.waterLevel = param[0];
265 map.waterLevel = 281;
270 map.waterLevel = 281;
271 map.requiredWaterLevel = 222;
274 else if (strcmp("ALPHATILES", mapEntity) == 0)
276 for (int i = 0 ; i < 15 ; i++)
281 sscanf(token, "%d", ¶m[0]);
286 debug(("Setting Alpha for Tile %d\n", param[0]));
288 SDL_SetAlpha(graphics.tile[param[0]], 130);
299 else if (strcmp("BACKGROUND", mapEntity) == 0)
301 sscanf(token, "%*s %*s %s", string[0]);
302 graphics.loadBackground(string[0]);
304 else if (strcmp("MUSIC", mapEntity) == 0)
306 sscanf(token, "%*s %*s %s", string[0]);
307 audio.loadMusic(string[0]);
309 else if (allowAtSkillLevel)
311 graphics.showErrorAndExit("Symbol '%s' not recognised or not implemented in map data", mapEntity);
316 //debug(("Ignoring Line: %s\n", token));
321 We need to make sure the player doesn't appear in a wall that was previously
322 destroyed. Things like this aren't stored so we will just remove a block they
325 if (previouslyCleared)
327 int x = game.checkPointX;
328 int y = game.checkPointY;
333 if ((map.data[x][y] >= MAP_BREAKABLE) && (map.data[x][y] <= MAP_BREAKABLE2))
335 map.data[x][y] = MAP_AIR;
340 const char *getActiveState(bool active)
350 void createPersistantMapData()
352 if (!engine.loadDefines())
354 graphics.showErrorAndExit("Could not load map define list '%s'", "data/defines.h");
357 Persistant *persistant = (Persistant*)map.createPersistant(map.name);
360 if (perfectlyCompleted())
362 debug(("createPersistantMapData :: Perfect - Skipping\n"));
384 snprintf(line, sizeof line, "%c START %d %d\n", skill, (int)game.checkPointX, (int)game.checkPointY);
385 persistant->addLine(line);
391 Teleporter *teleporter;
393 SpawnPoint *spawnPoint;
397 ent = (Entity*)map.enemyList.getHead();
399 while (ent->next != NULL)
401 ent = (Entity*)ent->next;
402 snprintf(line, sizeof line, "%c ENEMY \"%s\" %d %d\n", skill, ent->name, (int)ent->x, (int)ent->y);
403 persistant->addLine(line);
406 ent = (Entity*)map.itemList.getHead();
408 while (ent->next != NULL)
410 ent = (Entity*)ent->next;
412 // Don't save items that are dying...
413 if (ent->flags & ENT_DYING)
418 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);
419 persistant->addLine(line);
422 ent = (Entity*)map.obstacleList.getHead();
424 while (ent->next != NULL)
426 ent = (Entity*)ent->next;
427 snprintf(line, sizeof line, "%c OBSTACLE \"%s\" %d %d %s\n", skill, ent->name, (int)ent->x, (int)ent->y, ent->sprite[0]->name);
428 persistant->addLine(line);
431 swt = (Switch*)map.switchList.getHead();
433 while (swt->next != NULL)
435 swt = (Switch*)swt->next;
436 define[0] = engine.getDefineOfValue("SWT_", swt->type);
437 define[1] = (char*)getActiveState(swt->activated);
439 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]);
441 persistant->addLine(line);
444 train = (Train*)map.trainList.getHead();
446 while (train->next != NULL)
448 train = (Train*)train->next;
450 if (train->type != TR_TRAIN)
452 if (train->type >= TR_SLIDEDOOR)
454 define[0] = engine.getDefineOfValue("_SLIDE", train->type);
458 define[0] = engine.getDefineOfValue("_DOO", train->type);
461 define[1] = (char*)getActiveState(train->active);
462 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]);
466 define[0] = engine.getDefineOfValue("TR_A", train->waitAtStart);
467 define[1] = (char*)getActiveState(train->active);
468 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]);
471 persistant->addLine(line);
474 trap = (Trap*)map.trapList.getHead();
476 while (trap->next != NULL)
478 trap = (Trap*)trap->next;
479 define[0] = engine.getDefineOfValue("TRAP_TYPE", trap->type);
480 define[1] = (char*)getActiveState(trap->active);
481 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]);
482 persistant->addLine(line);
485 teleporter = (Teleporter*)map.teleportList.getHead();
487 while (teleporter->next != NULL)
489 teleporter = (Teleporter*)teleporter->next;
490 define[0] = (char*)getActiveState(teleporter->active);
491 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]);
492 persistant->addLine(line);
495 lineDef = (LineDef*)map.lineList.getHead();
497 while (lineDef->next != NULL)
499 lineDef = (LineDef*)lineDef->next;
500 define[0] = (char*)getActiveState(lineDef->activated);
501 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]);
502 persistant->addLine(line);
505 spawnPoint = (SpawnPoint*)map.spawnList.getHead();
507 while (spawnPoint->next != NULL)
509 spawnPoint = (SpawnPoint*)spawnPoint->next;
510 define[0] = engine.getDefineOfValue("SPW_", spawnPoint->spawnType);
512 if (strstr(define[0], "HAZARD"))
514 define[1] = engine.getDefineOfValue("HAZARD_", spawnPoint->spawnSubType);
518 define[1] = engine.getDefineOfValue("SPW_", spawnPoint->spawnSubType);
521 define[2] = (char*)getActiveState(spawnPoint->active);
522 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]);
523 persistant->addLine(line);
526 for (int i = 0 ; i < 10 ; i++)
528 if (map.getSpawnableEnemy(i) != NULL)
530 snprintf(line, sizeof line, "%c SPAWNABLE_ENEMY \"%s\"\n", skill, map.getSpawnableEnemy(i));
531 persistant->addLine(line);
535 if (map.waterLevel != -1)
537 snprintf(line, sizeof line, "%c WATERLEVEL %d\n", skill, (int)map.waterLevel);
538 persistant->addLine(line);
541 // We don't need this anymore. Remove it to free up some memory...
542 engine.defineList.clear();