Removed that logo from this bramch aswell..
[dbw.git] / src / map.cpp
blobb2452c72c6ca5f301cbbb852b2ebd70007099cef
1 /*
2 Copyright © 2004 Parallel Realities
3 Copyright © 2007-2008 Kővágó Zoltán <DirtY.iCE.hu@gmail.com>
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.
22 #include "CAudio.h"
23 #include "CEngine.h"
24 #include "CGame.h"
25 #include "CGraphics.h"
26 #include "CMath.h"
27 #include "CMap.h"
28 #include "CRadarBlip.h"
29 #include "CTrain.h"
30 #include "gettext.hpp"
31 #include "map.h"
33 void doOffsets()
35 map.offsetX = (int)(engine.playerPosX) - bx;
36 map.offsetY = (int)(engine.playerPosY) - by;
38 Math::limitInt(&(map.offsetX), 0, ((MAPWIDTH - 40) * BRICKSIZE));
39 Math::limitInt(&(map.offsetY), 0, ((MAPHEIGHT - 30) * BRICKSIZE));
43 void drawMap()
45 SDL_Rect r;
47 int mapx = map.offsetX >> BRICKSHIFT;
48 int mapy = map.offsetY >> BRICKSHIFT;
49 int brick = 0;
51 int xtimes = (graphics.width / 32) + (graphics.width % 32 ? 2 : 1);
52 int ytimes = (graphics.height / 32) + (graphics.width % 32 ? 2 : 1);
54 for (int x = 0; (x < xtimes) && ((mapx + x) < MAPWIDTH); x++)
56 for (int y = 0; (y < ytimes) && ((mapy + y) < MAPHEIGHT); y++)
58 brick = map.data[mapx + x][mapy + y];
60 r.x = ((x * BRICKSIZE) - (map.offsetX & BRICKSIZE - 1));
61 r.y = ((y * BRICKSIZE) - (map.offsetY & BRICKSIZE - 1));
62 r.w = r.h = BRICKSIZE;
64 if ((brick >= MAP_BREAKABLE) && (brick < MAP_WATERANIM))
66 graphics.blit(graphics.tile[brick], r.x, r.y, graphics.screen, false);
68 /// DEBUG ???
69 if ((brick >= MAP_NORESET) && (brick < MAP_DECORATION))
71 graphics.drawRect(r.x, r.y, 32, 4, graphics.yellow, graphics.screen);
78 void drawMapTopLayer()
80 SDL_Rect r;
82 int offsetX = map.offsetX;
83 int offsetY = map.offsetY;
85 Math::limitInt(&offsetX, 0, ((MAPWIDTH - 40) * BRICKSIZE));
86 Math::limitInt(&offsetY, 0, ((MAPHEIGHT - 30) * BRICKSIZE));
88 int mapx = offsetX >> BRICKSHIFT;
89 int mapy = offsetY >> BRICKSHIFT;
91 int brick;
93 int xtimes = (graphics.width / 32) + (graphics.width % 32 ? 2 : 1);
94 int ytimes = (graphics.height / 32) + (graphics.width % 32 ? 2 : 1);
96 for (int x = 0; (x < xtimes) && ((mapx + x) < MAPWIDTH); x++)
98 for (int y = 0; (y < ytimes) && ((mapy + y) < MAPHEIGHT); y++)
100 r.x = ((x * BRICKSIZE) - (offsetX & BRICKSIZE - 1));
101 r.y = ((y * BRICKSIZE) - (offsetY & BRICKSIZE - 1));
102 r.w = r.h = BRICKSIZE;
104 brick = map.data[mapx + x][mapy + y];
106 if (brick == 0)
108 continue;
111 if ((brick < MAP_BREAKABLE) || (brick >= MAP_WATERANIM))
113 if (brick == MAP_WATER)
115 if (map.data[mapx + x][mapy + y + 1] >= MAP_BREAKABLE)
117 addBubble((mapx + x) * BRICKSIZE, (mapy + y) * BRICKSIZE);
121 if (brick == MAP_WATERANIM)
123 brick = graphics.getWaterAnim();
125 else if (brick == MAP_SLIME)
127 brick = graphics.getSlimeAnim();
129 else if ((brick >= MAP_LAVAANIM) && (brick < MAP_TOPLAYER))
131 map.data[mapx + x][mapy + y] = graphics.getLavaAnim(brick);
132 brick = map.data[mapx + x][mapy + y];
135 graphics.blit(graphics.tile[brick], r.x, r.y, graphics.screen, false);
141 void addBlips(List *blipList, int mapX, int mapY, int type)
143 Sprite *blipType;
144 Entity *ent;
146 switch (type)
148 case 1:
149 blipType = graphics.getSprite("MIAArrow", true);
150 ent = (Entity*)map.miaList.getHead();
151 break;
152 case 2:
153 blipType = graphics.getSprite("ItemArrow", true);
154 ent = (Entity*)map.itemList.getHead();
155 break;
156 case 3:
157 blipType = graphics.getSprite("EnemyArrow", true);
158 ent = (Entity*)map.enemyList.getHead();
159 break;
160 default:
161 return;
164 RadarBlip *blip;
165 int x, y;
167 while (ent->next != NULL)
169 ent = (Entity*)ent->next;
171 if (ent->health <= 0)
172 continue;
174 if (type == 3)
176 if (!requiredEnemy(ent->name))
178 continue;
182 // Items
183 if (type == 2)
185 if ((ent->id < ITEM_MISC) || (ent->id == ITEM_MISC_INVISIBLE))
187 continue;
191 x = (int)(ent->x + ent->width) >> BRICKSHIFT;
192 y = (int)(ent->y + ent->height) >> BRICKSHIFT;
194 x -= mapX;
195 y -= mapY;
197 x = (160) + (x * 5);
198 y = (120) + (y * 5);
200 if ((x >= 165) && (y >= 125) && (x <= 475) && (y <= 355))
202 blip = new RadarBlip();
203 blip->set(x, y, type);
204 blipList->add (blip);
206 else
208 if (y < 125)
209 graphics.blit(blipType->image[0], bx + 220 + (type * 50), by + 100, graphics.screen, true);
210 if (x > 475)
211 graphics.blit(blipType->image[1], bx + 510, by + 140 + (type * 50), graphics.screen, true);
212 if (y > 355)
213 graphics.blit(blipType->image[2], bx + 220 + (type * 50), by + 380, graphics.screen, true);
214 if (x < 165)
215 graphics.blit(blipType->image[3], bx + 125, by + 140 + (type * 50), graphics.screen, true);
220 void addMiniMapDoors(SDL_Surface *panel, int mapX, int mapY)
222 Train *train = (Train*)map.trainList.getHead();
224 int x, y;
225 int width, height, color;
227 while (train->next != NULL)
229 train = (Train*)train->next;
231 width = 5;
232 height = 5;
233 color = graphics.white;
235 x = (int)train->x >> BRICKSHIFT;
237 y = (int)train->y >> BRICKSHIFT;
239 if ((x >= mapX) && (x <= mapX + 64) && (y >= mapY) && (y <= mapY + 48))
241 x -= mapX;
242 y -= mapY;
244 if (train->type == TR_TRAIN)
246 width = 10;
248 else if ((train->type >= TR_SLIDEDOOR) && (train->type <= TR_BRONZE_SLIDEDOOR))
250 width = 10;
252 else
254 height = 10;
257 switch (train->type)
259 case TR_GOLD_DOOR:
260 case TR_GOLD_SLIDEDOOR:
261 color = graphics.yellow;
262 break;
264 case TR_SILVER_DOOR:
265 case TR_SILVER_SLIDEDOOR:
266 color = graphics.grey;
267 break;
269 case TR_BRONZE_DOOR:
270 case TR_BRONZE_SLIDEDOOR:
271 color = SDL_MapRGB(graphics.screen->format, 0xff, 0x99, 0x00);
272 break;
274 case TR_DOOR:
275 case TR_LOCKED_DOOR:
276 case TR_LOCKED_SLIDEDOOR:
277 color = SDL_MapRGB(graphics.screen->format, 0xff, 0x00, 0xff);
278 break;
281 graphics.drawRect(x * 5, y * 5, width, height, color, panel);
286 void showMap(int centerX, int centerY)
288 char string[100];
289 int x1, y1, x2, y2;
291 x1 = centerX - 32;
292 x2 = centerX + 32;
293 y1 = centerY - 24;
294 y2 = centerY + 24;
296 int minX = (map.limitLeft >> BRICKSHIFT);
297 int maxX = (map.limitRight >> BRICKSHIFT) - 44;
298 int minY = (map.limitUp >> BRICKSHIFT);
299 int maxY = (map.limitDown >> BRICKSHIFT) - 33;
301 Math::limitInt(&x1, minX, maxX);
302 Math::limitInt(&x2, minX, maxX);
303 Math::limitInt(&y1, minY, maxY);
304 Math::limitInt(&y2, minY, maxY);
306 SDL_FillRect(graphics.screen, NULL, graphics.black);
307 graphics.updateScreen();
309 SDL_Surface *panel = graphics.createSurface(320, 240);
310 SDL_Surface *background = graphics.loadImage("gfx/main/mapBackground.png");
311 SDL_SetAlpha(background, SDL_SRCALPHA|SDL_RLEACCEL, 128);
313 graphics.blit(background, 0, 0, panel, false);
315 int color = graphics.black;
317 for (int y = 0 ; y < 48 ; y++)
319 for (int x = 0 ; x < 64 ; x++)
321 if (map.data[x1 + x][y1 + y] == MAP_WATER)
323 graphics.drawRect(x * 5, y * 5, 5, 5, graphics.blue, panel);
328 addMiniMapDoors(panel, x1, y1);
330 for (int y = 0 ; y < 48 ; y++)
332 for (int x = 0 ; x < 64 ; x++)
334 color = -1;
336 if (map.data[x1 + x][y1 + y] == MAP_AIR)
338 color = -1;
340 else if (map.data[x1 + x][y1 + y] == MAP_WATER)
342 color = -1;
344 else if (map.data[x1 + x][y1 + y] == MAP_SLIME)
346 color = graphics.green;
348 else if (map.data[x1 + x][y1 + y] == MAP_LAVA)
350 color = graphics.red;
352 else if (map.data[x1 + x][y1 + y] >= MAP_DECORATION)
354 color = -1;
356 if (map.data[x1 + x][y1 + y - 1] == MAP_WATER)
358 color = graphics.blue;
360 else if (map.data[x1 + x][y1 + y + 1] == MAP_WATER)
362 color = graphics.blue;
365 else if (map.data[x1 + x][y1 + y] < MAP_WATERANIM)
367 color = graphics.darkGreen;
370 if (color > -1)
372 graphics.drawRect(x * 5, y * 5, 5, 5, color, panel);
377 SDL_Surface * tmp_bckg = graphics.background;
378 graphics.background = background;
379 graphics.drawBackground();
380 graphics.background = tmp_bckg;
381 SDL_FreeSurface(background);
383 List blipList;
385 RadarBlip *blip = new RadarBlip();
386 blip->set(160 + ((centerX - x1) * 5), 120 + ((centerY - y1) * 5), 0);
387 blipList.add(blip);
389 addBlips(&blipList, x1, y1, 1);
390 addBlips(&blipList, x1, y1, 2);
391 addBlips(&blipList, x1, y1, 3);
393 Sprite *enemySignal = graphics.getSprite("EnemySignal", true);
394 Sprite *miaSignal = graphics.getSprite("MIASignal", true);
395 Sprite *bobSignal = graphics.getSprite("BobSignal", true);
396 Sprite *itemSignal = graphics.getSprite("ItemSignal", true);
398 graphics.setFontColor(0xff, 0xff, 0xff, 0x00, 0x00, 0x00);
399 graphics.setFontSize(3);
400 graphics.drawString(game.stageName, bx + 320, by + 30, TXT_CENTERED, graphics.screen);
402 graphics.setFontSize(0);
404 graphics.drawRect(bx + 160, by + 414, 7, 7, graphics.yellow, graphics.white, graphics.screen);
405 graphics.drawString(_("MIAs"), bx + 175, by + 410, TXT_LEFT, graphics.screen);
407 graphics.drawRect(bx + 290, by + 414, 7, 7, graphics.blue, graphics.white, graphics.screen);
408 graphics.drawString(_("Items"), bx + 320, by + 417, TXT_CENTERED, graphics.screen);
410 graphics.drawRect(bx + 415, by + 414, 7, 7, graphics.red, graphics.white, graphics.screen);
411 graphics.drawString(_("Enemies"), bx + 480, by + 410, TXT_RIGHT, graphics.screen);
413 graphics.setFontSize(1);
414 sprintf(string, "%s - %.2d:%.2d:%.2d", _("Mission Time").c_str(), game.currentMissionHours, game.currentMissionMinutes, game.currentMissionSeconds);
415 graphics.drawString(string, bx + 320, by + 60, TXT_CENTERED, graphics.screen);
416 graphics.drawString(_("Press Button to Continue..."), bx + 320, by + 450, TXT_CENTERED, graphics.screen);
418 engine.flushInput();
419 engine.clearInput();
421 while (true)
423 engine.getInput();
424 graphics.updateScreen();
425 graphics.animateSprites();
427 graphics.drawRect(bx + 160, by + 120, 320, 240, graphics.black, graphics.white, graphics.screen);
428 graphics.blit(panel, bx + 160, by + 120, graphics.screen, false);
430 if ((engine.isKey(KEY_MAP)) || (engine.isKey(KEY_PAUSE)) || (engine.keyState[SDLK_ESCAPE]))
432 break;
435 blip = (RadarBlip*)blipList.getHead();
437 while (blip->next != NULL)
439 blip = (RadarBlip*)blip->next;
441 switch (blip->type)
443 case 0:
444 graphics.blit(bobSignal->getCurrentFrame(), bx + blip->x, by + blip->y, graphics.screen, true);
445 break;
446 case 1:
447 graphics.blit(miaSignal->getCurrentFrame(), bx + blip->x, by + blip->y, graphics.screen, true);
448 break;
449 case 2:
450 graphics.blit(itemSignal->getCurrentFrame(), bx + blip->x, by + blip->y, graphics.screen, true);
451 break;
452 case 3:
453 graphics.blit(enemySignal->getCurrentFrame(), bx + blip->x, by + blip->y, graphics.screen, true);
454 break;
458 SDL_Delay(16);
461 blipList.clear();
463 SDL_FillRect(graphics.screen, NULL, graphics.black);
464 graphics.updateScreen();
466 engine.flushInput();
467 engine.clearInput();
470 void evaluateMapAttribute(Entity *ent, int mapAttribute)
472 switch (mapAttribute)
474 case MAP_AIR_WALL_1:
475 case MAP_AIR_WALL_2:
476 case MAP_AIR_WALL_3:
477 case MAP_AIR_CEILING_1:
478 mapAttribute = MAP_AIR;
479 break;
480 case MAP_AIR_WALL_4:
481 if (map.isCavesTileset)
483 mapAttribute = MAP_AIR;
485 break;
486 case MAP_AIR_CEILING_2:
487 if (map.isGrasslandsTileset)
489 mapAttribute = MAP_AIR;
491 else if (map.isCavesTileset)
493 mapAttribute = MAP_WATER;
495 break;
496 case MAP_WATER_WALL:
497 if (map.isCavesTileset)
499 mapAttribute = MAP_WATER;
501 break;
504 switch (mapAttribute)
506 case MAP_AIR:
507 if ((ent->environment != ENV_AIR) && (!(ent->flags & ENT_INANIMATE)))
509 if (!(ent->flags & ENT_SWIMS))
511 if (ent->dy < 0)
513 ent->dy = PLAYER_JUMP_SPEED;
516 if (ent == &player)
518 if ((ent == &player) && ((game.hasAquaLung) || (engine.cheatExtras)))
520 player.setSprites(graphics.getSprite("BobRight", true), graphics.getSprite("BobLeft", true), graphics.getSprite("BobSpin", true));
524 ent->environment = ENV_AIR;
526 if (ent->dy < 0)
528 audio.playSound(SND_WATEROUT, CH_TOUCH);
531 ent->checkEnvironment();
534 ent->falling = true;
535 case MAP_SOLID:
536 break;
537 case MAP_WATER:
538 case MAP_SLIME:
539 case MAP_LAVA:
541 ent->falling = false;
543 if (ent->environment == ENV_AIR)
545 audio.playSound(SND_WATERIN, CH_TOUCH);
546 if ((mapAttribute == MAP_SLIME) || (mapAttribute == MAP_LAVA))
547 ent->thinktime = 1;
550 // On ice levels water is harmful (because it's very very cold!)
551 if ((map.isIceLevel) && (mapAttribute == MAP_WATER))
553 mapAttribute = MAP_LAVA;
554 ent->thinktime = 1;
557 if (mapAttribute == MAP_WATER)
559 ent->environment = ENV_WATER;
560 if ((ent == &player) && ((game.hasAquaLung) || (engine.cheatExtras)))
562 player.setSprites(graphics.getSprite("AquaBobRight", true), graphics.getSprite("AquaBobLeft", true), graphics.getSprite("AquaBobSpin", true));
565 else if (mapAttribute == MAP_SLIME)
567 ent->environment = ENV_SLIME;
569 else if (mapAttribute == MAP_LAVA)
571 ent->environment = ENV_LAVA;
573 break;
577 void raiseWaterLevel()
579 if (map.waterLevel == map.requiredWaterLevel)
581 return;
584 int y = (int)map.waterLevel;
586 if ((int)map.waterLevel != map.requiredWaterLevel)
588 for (int x = 0 ; x < MAPWIDTH ; x++)
590 if ((map.data[x][y] == MAP_AIR) || (map.isLiquid(x, y)))
592 map.data[x][y] = MAP_WATER;
595 if ((map.data[x][y] >= MAP_DECORATION) && (map.data[x][y] <= MAP_WATERANIM))
597 map.data[x][y] = MAP_WATER;
600 if (map.data[x][y] >= MAP_TOPLAYER)
602 map.data[x][y] = MAP_WATER;
605 if (map.data[x][y - 1] >= MAP_TOPLAYER)
607 map.data[x][y] = MAP_WATER;
610 if ((map.data[x][y - 1] == MAP_AIR) || (map.isLiquid(x, y - 1)))
612 map.data[x][y - 1] = MAP_WATERANIM;
615 if ((map.data[x][y - 1] >= MAP_DECORATION) && (map.data[x][y - 1] <= MAP_WATERANIM))
617 map.data[x][y - 1] = MAP_WATERANIM;
621 map.waterLevel -= 0.1;
623 int x = (int)(player.x + player.dx) >> BRICKSHIFT;
624 int y = (int)(player.y + player.height - 1) >> BRICKSHIFT;
626 int mapAttribute = map.data[x][y];
628 if ((mapAttribute == MAP_WATER) && (player.environment == MAP_AIR))
630 evaluateMapAttribute(&player, mapAttribute);
635 void doWind()
637 map.windChangeTime--;
639 if (map.windChangeTime <= 0)
641 map.windPower = 0;
643 if (Math::rrand(0, 1) == 0)
644 map.windPower = Math::rrand(-3, 3);
646 // change wind time
647 map.windChangeTime = Math::rrand(60, 600);
650 addWindParticles();
653 void parseMapDataLine(char *line, int y)
655 int tileIndex = 0;
656 int x = 0;
658 while (true)
660 sscanf(line, "%d", &tileIndex);
662 map.data[x][y] = tileIndex;
664 while (true)
666 *line++;
668 if (*line == ' ')
669 break;
672 x++;
674 if (x == MAPWIDTH)
675 break;
679 bool loadMapData(char *filename)
681 map.clear();
683 if (!engine.loadData(filename))
684 graphics.showErrorAndExit(_("The requested map '%s' was not found."), filename);
686 char *token = strtok((char*)engine.dataBuffer, "\n");
687 parseMapDataLine(token, 0);
689 int y = 1;
691 while (true)
693 token = strtok(NULL, "\n");
695 parseMapDataLine(token, y);
697 y++;
698 if (y == MAPHEIGHT)
699 break;
702 getMapTokens();
704 adjustObjectives();
705 initMIAPhrases();
707 return true;