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 int offsetX = (int)(engine.playerPosX);
29 int offsetY = (int)(engine.playerPosY);
31 map.offsetX = offsetX;
32 map.offsetY = offsetY;
34 Math::limitInt(&offsetX, 0, ((MAPWIDTH - 40) * BRICKSIZE));
35 Math::limitInt(&offsetY, 0, ((MAPHEIGHT - 30) * BRICKSIZE));
37 int mapx = offsetX >> BRICKSHIFT;
38 int mapy = offsetY >> BRICKSHIFT;
41 for (int x = 0 ; x < 21 ; x++)
43 for (int y = 0 ; y < 16 ; y++)
45 brick = map.data[mapx + x][mapy + y];
47 r.x = ((x * BRICKSIZE) - (offsetX & (BRICKSIZE - 1)));
48 r.y = ((y * BRICKSIZE) - (offsetY & (BRICKSIZE - 1)));
49 r.w = r.h = BRICKSIZE;
51 if ((brick >= MAP_BREAKABLE) && (brick < MAP_WATERANIM))
53 graphics.blit(graphics.tile[brick], r.x, r.y, graphics.screen, false);
56 if ((brick >= MAP_NORESET) && (brick < MAP_DECORATION))
58 graphics.drawRect(r.x, r.y, 32, 4, graphics.yellow, graphics.screen);
66 void drawMapTopLayer()
70 int offsetX = map.offsetX;
71 int offsetY = map.offsetY;
73 Math::limitInt(&offsetX, 0, ((MAPWIDTH - 40) * BRICKSIZE));
74 Math::limitInt(&offsetY, 0, ((MAPHEIGHT - 30) * BRICKSIZE));
76 int mapx = offsetX >> BRICKSHIFT;
77 int mapy = offsetY >> BRICKSHIFT;
81 for (int x = 0 ; x < 21 ; x++)
83 for (int y = 0 ; y < 16 ; y++)
85 r.x = ((x * BRICKSIZE) - (offsetX & (BRICKSIZE - 1)));
86 r.y = ((y * BRICKSIZE) - (offsetY & (BRICKSIZE - 1)));
87 r.w = r.h = BRICKSIZE;
89 brick = map.data[mapx + x][mapy + y];
96 if ((brick < MAP_BREAKABLE) || (brick >= MAP_WATERANIM))
98 if (brick == MAP_WATER)
100 if (map.data[mapx + x][mapy + y + 1] >= MAP_BREAKABLE)
102 addBubble((mapx + x) * BRICKSIZE, (mapy + y) * BRICKSIZE);
106 if (brick == MAP_WATERANIM)
108 brick = graphics.getWaterAnim();
110 else if (brick == MAP_SLIME)
112 brick = graphics.getSlimeAnim();
114 else if ((brick >= MAP_LAVAANIM) && (brick < MAP_TOPLAYER))
116 map.data[mapx + x][mapy + y] = graphics.getLavaAnim(brick);
117 brick = map.data[mapx + x][mapy + y];
120 graphics.blit(graphics.tile[brick], r.x, r.y, graphics.screen, false);
126 void addBlips(List *blipList, int mapX, int mapY, int type)
134 blipType = graphics.getSprite("MIAArrow", true);
135 ent = (Entity*)map.miaList.getHead();
138 blipType = graphics.getSprite("ItemArrow", true);
139 ent = (Entity*)map.itemList.getHead();
142 blipType = graphics.getSprite("EnemyArrow", true);
143 ent = (Entity*)map.enemyList.getHead();
152 while (ent->next != NULL)
154 ent = (Entity*)ent->next;
156 if (ent->health <= 0)
161 if (!requiredEnemy(ent->name))
170 if ((ent->id < ITEM_MISC) || (ent->id == ITEM_MISC_INVISIBLE))
176 x = (int)(ent->x + ent->width) >> BRICKSHIFT;
177 y = (int)(ent->y + ent->height) >> BRICKSHIFT;
185 if ((x >= 165) && (y >= 125) && (x <= 475) && (y <= 355))
187 blip = new RadarBlip();
188 blip->set(x, y, type);
189 blipList->add (blip);
194 graphics.blit(blipType->image[0], 220 + (type * 50), 100, graphics.screen, true);
196 graphics.blit(blipType->image[1], 510, 140 + (type * 50), graphics.screen, true);
198 graphics.blit(blipType->image[2], 220 + (type * 50), 380, graphics.screen, true);
200 graphics.blit(blipType->image[3], 125, 140 + (type * 50), graphics.screen, true);
205 void addMiniMapDoors(SDL_Surface *panel, int mapX, int mapY)
207 Train *train = (Train*)map.trainList.getHead();
210 int width, height, color;
212 while (train->next != NULL)
214 train = (Train*)train->next;
218 color = graphics.white;
220 x = (int)train->x >> BRICKSHIFT;
222 y = (int)train->y >> BRICKSHIFT;
224 if ((x >= mapX) && (x <= mapX + 64) && (y >= mapY) && (y <= mapY + 48))
229 if (train->type == TR_TRAIN)
233 else if ((train->type >= TR_SLIDEDOOR) && (train->type <= TR_BRONZE_SLIDEDOOR))
245 case TR_GOLD_SLIDEDOOR:
246 color = graphics.yellow;
250 case TR_SILVER_SLIDEDOOR:
251 color = graphics.grey;
255 case TR_BRONZE_SLIDEDOOR:
256 color = SDL_MapRGB(graphics.screen->format, 0xff, 0x99, 0x00);
261 case TR_LOCKED_SLIDEDOOR:
262 color = SDL_MapRGB(graphics.screen->format, 0xff, 0x00, 0xff);
266 graphics.drawRect(x * 5, y * 5, width, height, color, panel);
271 void showMap(int centerX, int centerY)
281 int minX = (map.limitLeft >> BRICKSHIFT);
282 int maxX = (map.limitRight >> BRICKSHIFT) - 44;
283 int minY = (map.limitUp >> BRICKSHIFT);
284 int maxY = (map.limitDown >> BRICKSHIFT) - 33;
286 Math::limitInt(&x1, minX, maxX);
287 Math::limitInt(&x2, minX, maxX);
288 Math::limitInt(&y1, minY, maxY);
289 Math::limitInt(&y2, minY, maxY);
291 SDL_FillRect(graphics.screen, NULL, graphics.black);
292 graphics.updateScreen();
295 SDL_Surface *panel = graphics.createSurface(320, 240);
296 SDL_Surface *background = graphics.loadImage("gfx/main/mapBackground.png");
297 SDL_SetAlpha(background, 130);
299 graphics.blit(background, 0, 0, panel, false);
301 for (int y = 0 ; y < 48 ; y++)
303 for (int x = 0 ; x < 64 ; x++)
305 if (map.data[x1 + x][y1 + y] == MAP_WATER)
307 graphics.drawRect(x * 5, y * 5, 5, 5, graphics.blue, panel);
312 addMiniMapDoors(panel, x1, y1);
314 for (int y = 0 ; y < 48 ; y++)
316 for (int x = 0 ; x < 64 ; x++)
318 int color = graphics.black;
320 if (map.data[x1 + x][y1 + y] == MAP_AIR)
322 color = graphics.black;
324 else if (map.data[x1 + x][y1 + y] == MAP_WATER)
326 color = graphics.black;
328 else if (map.data[x1 + x][y1 + y] == MAP_SLIME)
330 color = graphics.green;
332 else if (map.data[x1 + x][y1 + y] == MAP_LAVA)
334 color = graphics.red;
336 else if (map.data[x1 + x][y1 + y] >= MAP_DECORATION)
338 color = graphics.black;
340 if (map.data[x1 + x][y1 + y - 1] == MAP_WATER)
342 color = graphics.blue;
344 else if (map.data[x1 + x][y1 + y + 1] == MAP_WATER)
346 color = graphics.blue;
349 else if (map.data[x1 + x][y1 + y] < MAP_WATERANIM)
351 color = graphics.darkGreen;
354 if (color != graphics.black)
356 graphics.drawRect(x * 5, y * 5, 5, 5, color, panel);
361 graphics.blit(background, 0, 0, graphics.screen, false);
362 SDL_FreeSurface(background);
366 RadarBlip *blip = new RadarBlip();
367 blip->set(160 + ((centerX - x1) * 5), 120 + ((centerY - y1) * 5), 0);
370 addBlips(&blipList, x1, y1, 1);
371 addBlips(&blipList, x1, y1, 2);
372 addBlips(&blipList, x1, y1, 3);
374 Sprite *enemySignal = graphics.getSprite("EnemySignal", true);
375 Sprite *miaSignal = graphics.getSprite("MIASignal", true);
376 Sprite *bobSignal = graphics.getSprite("BobSignal", true);
377 Sprite *itemSignal = graphics.getSprite("ItemSignal", true);
379 graphics.setFontColor(0xff, 0xff, 0xff, 0x00, 0x00, 0x00);
380 graphics.setFontSize(3);
381 graphics.drawString(_(game.stageName), 320, 30, TXT_CENTERED, graphics.screen);
383 graphics.setFontSize(0);
385 graphics.drawRect(160, 414, 7, 7, graphics.yellow, graphics.white, graphics.screen);
386 graphics.drawString(_("MIAs"), 175, 410, TXT_LEFT, graphics.screen);
388 graphics.drawRect(290, 414, 7, 7, graphics.blue, graphics.white, graphics.screen);
389 graphics.drawString(_("Items"), 305, 410, TXT_LEFT, graphics.screen);
391 graphics.drawRect(415, 414, 7, 7, graphics.red, graphics.white, graphics.screen);
392 graphics.drawString(_("Enemies"), 430, 410, TXT_LEFT, graphics.screen);
394 graphics.setFontSize(1);
395 snprintf(string, sizeof string, "%s - %.2d:%.2d:%.2d", _("Mission Time"), game.currentMissionHours, game.currentMissionMinutes, game.currentMissionSeconds);
396 graphics.drawString(string, 320, 60, TXT_CENTERED, graphics.screen);
397 graphics.drawString(_("Press Button to Continue..."), 320, 450, TXT_CENTERED, graphics.screen);
408 graphics.updateScreen();
409 graphics.animateSprites();
411 graphics.drawRect(160, 120, 320, 240, graphics.black, graphics.white, graphics.screen);
412 graphics.blit(panel, 160, 120, graphics.screen, false);
414 if ((config.isControl(CONTROL::MAP)) || (config.isControl(CONTROL::PAUSE)) || (engine.keyState[SDL_SCANCODE_ESCAPE]))
416 engine.keyState[SDL_SCANCODE_ESCAPE] = 0;
417 config.resetControl(CONTROL::MAP);
418 config.resetControl(CONTROL::PAUSE);
422 blip = (RadarBlip*)blipList.getHead();
424 while (blip->next != NULL)
426 blip = (RadarBlip*)blip->next;
431 graphics.blit(bobSignal->getCurrentFrame(), blip->x, blip->y, graphics.screen, true);
434 graphics.blit(miaSignal->getCurrentFrame(), blip->x, blip->y, graphics.screen, true);
437 graphics.blit(itemSignal->getCurrentFrame(), blip->x, blip->y, graphics.screen, true);
440 graphics.blit(enemySignal->getCurrentFrame(), blip->x, blip->y, graphics.screen, true);
450 SDL_FillRect(graphics.screen, NULL, graphics.black);
451 graphics.updateScreen();
458 void evaluateMapAttribute(Entity *ent, int mapAttribute)
460 switch (mapAttribute)
465 case MAP_AIR_CEILING_1:
466 mapAttribute = MAP_AIR;
469 if (map.isCavesTileset)
471 mapAttribute = MAP_AIR;
474 case MAP_AIR_CEILING_2:
475 if (map.isGrasslandsTileset)
477 mapAttribute = MAP_AIR;
479 else if (map.isCavesTileset)
481 mapAttribute = MAP_WATER;
485 if (map.isCavesTileset)
487 mapAttribute = MAP_WATER;
492 switch (mapAttribute)
495 if ((ent->environment != ENV_AIR) && (!(ent->flags & ENT_INANIMATE)))
497 if (!(ent->flags & ENT_SWIMS))
501 ent->dy = PLAYER_JUMP_SPEED;
506 if ((ent == &player) && ((game.hasAquaLung) || (engine.cheatExtras)))
508 player.setSprites(graphics.getSprite("BobRight", true), graphics.getSprite("BobLeft", true), graphics.getSprite("BobSpin", true));
512 ent->environment = ENV_AIR;
516 audio.playSound(SND_WATEROUT, CH_TOUCH, ent->x);
519 ent->checkEnvironment();
529 ent->falling = false;
531 if (ent->environment == ENV_AIR)
533 audio.playSound(SND_WATERIN, CH_TOUCH, ent->x);
534 if ((mapAttribute == MAP_SLIME) || (mapAttribute == MAP_LAVA))
538 // On ice levels water is harmful (because it's very very cold!)
539 if ((map.isIceLevel) && (mapAttribute == MAP_WATER))
541 mapAttribute = MAP_LAVA;
545 if (mapAttribute == MAP_WATER)
547 ent->environment = ENV_WATER;
548 if ((ent == &player) && ((game.hasAquaLung) || (engine.cheatExtras)))
550 player.setSprites(graphics.getSprite("AquaBobRight", true), graphics.getSprite("AquaBobLeft", true), graphics.getSprite("AquaBobSpin", true));
553 else if (mapAttribute == MAP_SLIME)
555 ent->environment = ENV_SLIME;
557 else if (mapAttribute == MAP_LAVA)
559 ent->environment = ENV_LAVA;
565 void raiseWaterLevel()
567 if (map.waterLevel == map.requiredWaterLevel)
572 int y = (int)map.waterLevel;
574 if ((int)map.waterLevel != map.requiredWaterLevel)
576 for (int x = 0 ; x < MAPWIDTH ; x++)
578 if ((map.data[x][y] == MAP_AIR) || (map.isLiquid(x, y)))
580 map.data[x][y] = MAP_WATER;
583 if ((map.data[x][y] >= MAP_DECORATION) && (map.data[x][y] <= MAP_WATERANIM))
585 map.data[x][y] = MAP_WATER;
588 if (map.data[x][y] >= MAP_TOPLAYER)
590 map.data[x][y] = MAP_WATER;
593 if (map.data[x][y - 1] >= MAP_TOPLAYER)
595 map.data[x][y] = MAP_WATER;
598 if ((map.data[x][y - 1] == MAP_AIR) || (map.isLiquid(x, y - 1)))
600 map.data[x][y - 1] = MAP_WATERANIM;
603 if ((map.data[x][y - 1] >= MAP_DECORATION) && (map.data[x][y - 1] <= MAP_WATERANIM))
605 map.data[x][y - 1] = MAP_WATERANIM;
609 map.waterLevel -= 0.1;
611 int x = (int)(player.x + player.dx) >> BRICKSHIFT;
612 int y = (int)(player.y + player.height - 1) >> BRICKSHIFT;
614 int mapAttribute = map.data[x][y];
616 if ((mapAttribute == MAP_WATER) && (player.environment == MAP_AIR))
618 evaluateMapAttribute(&player, mapAttribute);
625 map.windChangeTime--;
627 if (map.windChangeTime <= 0)
631 if (Math::rrand(0, 1) == 0)
632 map.windPower = Math::rrand(-3, 3);
635 map.windChangeTime = Math::rrand(60, 600);
641 void parseMapDataLine(const char *line, int y)
648 sscanf(line, "%d", &tileIndex);
650 map.data[x][y] = tileIndex;
667 bool loadMapData(const char *filename)
671 if (!engine.loadData(filename))
672 graphics.showErrorAndExit("The requested map '%s' was not found.", filename);
674 char *token = strtok((char*)engine.dataBuffer, "\n");
675 parseMapDataLine(token, 0);
681 token = strtok(NULL, "\n");
683 parseMapDataLine(token, y);