]> git.mxchange.org Git - quix0rs-blobwars.git/blob - src/map.cpp
Use time_t to store time data.
[quix0rs-blobwars.git] / src / map.cpp
1 /*
2 Copyright (C) 2004-2011 Parallel Realities
3 Copyright (C) 2011-2015 Perpendicular Dimensions
4
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.
9
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.
13
14 See the GNU General Public License for more details.
15
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.
19
20 */
21
22 #include "map.h"
23
24 void drawMap()
25 {
26         SDL_Rect r;
27
28         int offsetX = (int)(engine.playerPosX);
29         int offsetY = (int)(engine.playerPosY);
30
31         map.offsetX = offsetX;
32         map.offsetY = offsetY;
33
34         Math::limitInt(&offsetX, 0, ((MAPWIDTH - 40) * BRICKSIZE));
35         Math::limitInt(&offsetY, 0, ((MAPHEIGHT - 30) * BRICKSIZE));
36
37         int mapx = offsetX >> BRICKSHIFT;
38         int mapy = offsetY >> BRICKSHIFT;
39         int brick = 0;
40
41         for (int x = 0 ; x < 21 ; x++)
42         {
43                 for (int y = 0 ; y < 16 ; y++)
44                 {
45                         brick = map.data[mapx + x][mapy + y];
46
47                         r.x = ((x * BRICKSIZE) - (offsetX & (BRICKSIZE - 1)));
48                         r.y = ((y * BRICKSIZE) - (offsetY & (BRICKSIZE - 1)));
49                         r.w = r.h = BRICKSIZE;
50
51                         if ((brick >= MAP_BREAKABLE) && (brick < MAP_WATERANIM))
52                         {
53                                 graphics.blit(graphics.tile[brick], r.x, r.y, graphics.screen, false);
54                                 
55                                 #if DEBUG
56                                 if ((brick >= MAP_NORESET) && (brick < MAP_DECORATION))
57                                 {
58                                         graphics.drawRect(r.x, r.y, 32, 4, graphics.yellow, graphics.screen);
59                                 }
60                                 #endif
61                         }
62                 }
63         }
64 }
65
66 void drawMapTopLayer()
67 {
68         SDL_Rect r;
69
70         int offsetX = map.offsetX;
71         int offsetY = map.offsetY;
72
73         Math::limitInt(&offsetX, 0, ((MAPWIDTH - 40) * BRICKSIZE));
74         Math::limitInt(&offsetY, 0, ((MAPHEIGHT - 30) * BRICKSIZE));
75
76         int mapx = offsetX >> BRICKSHIFT;
77         int mapy = offsetY >> BRICKSHIFT;
78
79         int brick;
80
81         for (int x = 0 ; x < 21 ; x++)
82         {
83                 for (int y = 0 ; y < 16 ; y++)
84                 {
85                         r.x = ((x * BRICKSIZE) - (offsetX & (BRICKSIZE - 1)));
86                         r.y = ((y * BRICKSIZE) - (offsetY & (BRICKSIZE - 1)));
87                         r.w = r.h = BRICKSIZE;
88
89                         brick = map.data[mapx + x][mapy + y];
90
91                         if (brick == 0)
92                         {
93                                 continue;
94                         }
95
96                         if ((brick < MAP_BREAKABLE) || (brick >= MAP_WATERANIM))
97                         {
98                                 if (brick == MAP_WATER)
99                                 {
100                                         if (map.data[mapx + x][mapy + y + 1] >= MAP_BREAKABLE)
101                                         {
102                                                 addBubble((mapx + x) * BRICKSIZE, (mapy + y) * BRICKSIZE);
103                                         }
104                                 }
105
106                                 if (brick == MAP_WATERANIM)
107                                 {
108                                         brick = graphics.getWaterAnim();
109                                 }
110                                 else if (brick == MAP_SLIME)
111                                 {
112                                         brick = graphics.getSlimeAnim();
113                                 }
114                                 else if ((brick >= MAP_LAVAANIM) && (brick < MAP_TOPLAYER))
115                                 {
116                                         map.data[mapx + x][mapy + y] = graphics.getLavaAnim(brick);
117                                         brick = map.data[mapx + x][mapy + y];
118                                 }
119
120                                 graphics.blit(graphics.tile[brick], r.x, r.y, graphics.screen, false);
121                         }
122                 }
123         }
124 }
125
126 void addBlips(List *blipList, int mapX, int mapY, int type)
127 {
128         Sprite *blipType;
129         Entity *ent;
130
131         switch (type)
132         {
133                 case 1:
134                         blipType = graphics.getSprite("MIAArrow", true);
135                         ent = (Entity*)map.miaList.getHead();
136                         break;
137                 case 2:
138                         blipType = graphics.getSprite("ItemArrow", true);
139                         ent = (Entity*)map.itemList.getHead();
140                         break;
141                 case 3:
142                         blipType = graphics.getSprite("EnemyArrow", true);
143                         ent = (Entity*)map.enemyList.getHead();
144                         break;
145                 default:
146                         return;
147         }
148
149         RadarBlip *blip;
150         int x, y;
151
152         while (ent->next != NULL)
153         {
154                 ent = (Entity*)ent->next;
155
156                 if (ent->health <= 0)
157                         continue;
158
159                 if (type == 3)
160                 {
161                         if (!requiredEnemy(ent->name))
162                         {
163                                 continue;
164                         }
165                 }
166
167                 // Items
168                 if (type == 2)
169                 {
170                         if ((ent->id < ITEM_MISC) || (ent->id == ITEM_MISC_INVISIBLE))
171                         {
172                                 continue;
173                         }
174                 }
175
176                 x = (int)(ent->x + ent->width) >> BRICKSHIFT;
177                 y = (int)(ent->y + ent->height) >> BRICKSHIFT;
178
179                 x -= mapX;
180                 y -= mapY;
181
182                 x = (160) + (x * 5);
183                 y = (120) + (y * 5);
184
185                 if ((x >= 165) && (y >= 125) && (x <= 475) && (y <= 355))
186                 {
187                         blip = new RadarBlip();
188                         blip->set(x, y, type);
189                         blipList->add (blip);
190                 }
191                 else
192                 {
193                         if (y < 125)
194                                 graphics.blit(blipType->image[0], 220 + (type * 50), 100, graphics.screen, true);
195                         if (x > 475)
196                                 graphics.blit(blipType->image[1], 510, 140 + (type * 50), graphics.screen, true);
197                         if (y > 355)
198                                 graphics.blit(blipType->image[2], 220 + (type * 50), 380, graphics.screen, true);
199                         if (x < 165)
200                                 graphics.blit(blipType->image[3], 125, 140 + (type * 50), graphics.screen, true);
201                 }
202         }
203 }
204
205 void addMiniMapDoors(SDL_Surface *panel, int mapX, int mapY)
206 {
207         Train *train = (Train*)map.trainList.getHead();
208
209         int x, y;
210         int width, height, color;
211
212         while (train->next != NULL)
213         {
214                 train = (Train*)train->next;
215                 
216                 width = 5;
217                 height = 5;
218                 color = graphics.white;
219                 
220                 x = (int)train->x >> BRICKSHIFT;
221                 
222                 y = (int)train->y >> BRICKSHIFT;
223                 
224                 if ((x >= mapX) && (x <= mapX + 64) && (y >= mapY) && (y <= mapY + 48))
225                 {
226                         x -= mapX;
227                         y -= mapY;
228                         
229                         if (train->type == TR_TRAIN)
230                         {
231                                 width = 10;
232                         }
233                         else if ((train->type >= TR_SLIDEDOOR) && (train->type <= TR_BRONZE_SLIDEDOOR))
234                         {
235                                 width = 10;
236                         }
237                         else
238                         {
239                                 height = 10;
240                         }
241                         
242                         switch (train->type)
243                         {
244                                 case TR_GOLD_DOOR:
245                                 case TR_GOLD_SLIDEDOOR:
246                                         color = graphics.yellow;
247                                         break;
248                                         
249                                 case TR_SILVER_DOOR:
250                                 case TR_SILVER_SLIDEDOOR:
251                                         color = graphics.grey;
252                                         break;
253                                         
254                                 case TR_BRONZE_DOOR:
255                                 case TR_BRONZE_SLIDEDOOR:
256                                         color = SDL_MapRGB(graphics.screen->format, 0xff, 0x99, 0x00);
257                                         break;
258                                         
259                                 case TR_DOOR:
260                                 case TR_LOCKED_DOOR:
261                                 case TR_LOCKED_SLIDEDOOR:
262                                         color = SDL_MapRGB(graphics.screen->format, 0xff, 0x00, 0xff);
263                                         break;
264                         }
265                         
266                         graphics.drawRect(x * 5, y * 5, width, height, color, panel);
267                 }
268         }
269 }
270
271 void showMap(int centerX, int centerY)
272 {
273         char string[100];
274         int x1, y1, x2, y2;
275
276         x1 = centerX - 32;
277         x2 = centerX + 32;
278         y1 = centerY - 24;
279         y2 = centerY + 24;
280         
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;
285
286         Math::limitInt(&x1, minX, maxX);
287         Math::limitInt(&x2, minX, maxX);
288         Math::limitInt(&y1, minY, maxY);
289         Math::limitInt(&y2, minY, maxY);
290
291         SDL_FillRect(graphics.screen, NULL, graphics.black);
292         graphics.updateScreen();
293         SDL_Delay(500);
294         
295         SDL_Surface *panel = graphics.createSurface(320, 240);
296         SDL_Surface *background = graphics.loadImage("gfx/main/mapBackground.png");
297         SDL_SetAlpha(background, 130);
298         
299         graphics.blit(background, 0, 0, panel, false);
300         
301         for (int y = 0 ; y < 48 ; y++)
302         {
303                 for (int x = 0 ; x < 64 ; x++)
304                 {
305                         if (map.data[x1 + x][y1 + y] == MAP_WATER)
306                         {
307                                 graphics.drawRect(x * 5, y * 5, 5, 5, graphics.blue, panel);
308                         }
309                 }
310         }
311         
312         addMiniMapDoors(panel, x1, y1);
313
314         for (int y = 0 ; y < 48 ; y++)
315         {
316                 for (int x = 0 ; x < 64 ; x++)
317                 {
318                         int color = graphics.black;
319
320                         if (map.data[x1 + x][y1 + y] == MAP_AIR)
321                         {
322                                 color = graphics.black;
323                         }
324                         else if (map.data[x1 + x][y1 + y] == MAP_WATER)
325                         {
326                                 color = graphics.black;
327                         }
328                         else if (map.data[x1 + x][y1 + y] == MAP_SLIME)
329                         {
330                                 color = graphics.green;
331                         }
332                         else if (map.data[x1 + x][y1 + y] == MAP_LAVA)
333                         {
334                                 color = graphics.red;
335                         }
336                         else if (map.data[x1 + x][y1 + y] >= MAP_DECORATION)
337                         {
338                                 color = graphics.black;
339                                 
340                                 if (map.data[x1 + x][y1 + y - 1] == MAP_WATER)
341                                 {
342                                         color = graphics.blue;
343                                 }
344                                 else if (map.data[x1 + x][y1 + y + 1] == MAP_WATER)
345                                 {
346                                         color = graphics.blue;
347                                 }
348                         }
349                         else if (map.data[x1 + x][y1 + y] < MAP_WATERANIM)
350                         {
351                                 color = graphics.darkGreen;
352                         }
353
354                         if (color != graphics.black)
355                         {
356                                 graphics.drawRect(x * 5, y * 5, 5, 5, color, panel);
357                         }
358                 }
359         }
360
361         graphics.blit(background, 0, 0, graphics.screen, false);
362         SDL_FreeSurface(background);
363
364         List blipList;
365
366         RadarBlip *blip = new RadarBlip();
367         blip->set(160 + ((centerX - x1) * 5), 120 + ((centerY - y1) * 5), 0);
368         blipList.add(blip);
369
370         addBlips(&blipList, x1, y1, 1);
371         addBlips(&blipList, x1, y1, 2);
372         addBlips(&blipList, x1, y1, 3);
373         
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);
378
379         graphics.setFontColor(0xff, 0xff, 0xff, 0x00, 0x00, 0x00);
380         graphics.setFontSize(3);
381         graphics.drawString(_(game.stageName), 320, 30, TXT_CENTERED, graphics.screen);
382
383         graphics.setFontSize(0);
384         
385         graphics.drawRect(160, 414, 7, 7, graphics.yellow, graphics.white, graphics.screen);
386         graphics.drawString(_("MIAs"), 175, 410, TXT_LEFT, graphics.screen);
387
388         graphics.drawRect(290, 414, 7, 7, graphics.blue, graphics.white, graphics.screen);
389         graphics.drawString(_("Items"), 305, 410, TXT_LEFT, graphics.screen);
390
391         graphics.drawRect(415, 414, 7, 7, graphics.red, graphics.white, graphics.screen);
392         graphics.drawString(_("Enemies"), 430, 410, TXT_LEFT, graphics.screen);
393
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);
398
399         engine.flushInput();
400         engine.clearInput();
401
402         doMusicInfo(-1);
403
404         while (true)
405         {
406                 engine.getInput();
407                 config.populate();
408                 graphics.updateScreen();
409                 graphics.animateSprites();
410
411                 graphics.drawRect(160, 120, 320, 240, graphics.black, graphics.white, graphics.screen);
412                 graphics.blit(panel, 160, 120, graphics.screen, false);
413
414                 if ((config.isControl(CONTROL::MAP)) || (config.isControl(CONTROL::PAUSE)) || (engine.keyState[SDL_SCANCODE_ESCAPE]))
415                 {
416                         engine.keyState[SDL_SCANCODE_ESCAPE] = 0;
417                         config.resetControl(CONTROL::MAP);
418                         config.resetControl(CONTROL::PAUSE);
419                         break;
420                 }
421
422                 blip = (RadarBlip*)blipList.getHead();
423
424                 while (blip->next != NULL)
425                 {
426                         blip = (RadarBlip*)blip->next;
427
428                         switch (blip->type)
429                         {
430                                 case 0:
431                                         graphics.blit(bobSignal->getCurrentFrame(), blip->x, blip->y, graphics.screen, true);
432                                         break;
433                                 case 1:
434                                         graphics.blit(miaSignal->getCurrentFrame(), blip->x, blip->y, graphics.screen, true);
435                                         break;
436                                 case 2:
437                                         graphics.blit(itemSignal->getCurrentFrame(), blip->x, blip->y, graphics.screen, true);
438                                         break;
439                                 case 3:
440                                         graphics.blit(enemySignal->getCurrentFrame(), blip->x, blip->y, graphics.screen, true);
441                                         break;
442                         }
443                 }
444
445                 SDL_Delay(16);
446         }
447
448         blipList.clear();
449
450         SDL_FillRect(graphics.screen, NULL, graphics.black);
451         graphics.updateScreen();
452         SDL_Delay(500);
453
454         engine.flushInput();
455         engine.clearInput();
456 }
457
458 void evaluateMapAttribute(Entity *ent, int mapAttribute)
459 {
460         switch (mapAttribute)
461         {
462                 case MAP_AIR_WALL_1:
463                 case MAP_AIR_WALL_2:
464                 case MAP_AIR_WALL_3:
465                 case MAP_AIR_CEILING_1:
466                         mapAttribute = MAP_AIR;
467                         break;
468                 case MAP_AIR_WALL_4:
469                         if (map.isCavesTileset)
470                         {
471                                 mapAttribute = MAP_AIR;
472                         }
473                         break;
474                 case MAP_AIR_CEILING_2:
475                         if (map.isGrasslandsTileset)
476                         {
477                                 mapAttribute = MAP_AIR;
478                         }
479                         else if (map.isCavesTileset)
480                         {
481                                 mapAttribute = MAP_WATER;
482                         }
483                         break;
484                 case MAP_WATER_WALL:
485                         if (map.isCavesTileset)
486                         {
487                                 mapAttribute = MAP_WATER;
488                         }
489                         break;
490         }
491
492         switch (mapAttribute)
493         {
494                 case MAP_AIR:
495                         if ((ent->environment != ENV_AIR) && (!(ent->flags & ENT_INANIMATE)))
496                         {
497                                 if (!(ent->flags & ENT_SWIMS))
498                                 {
499                                         if (ent->dy < 0)
500                                         {
501                                                 ent->dy = PLAYER_JUMP_SPEED;
502                                         }
503
504                                         if (ent == &player)
505                                         {
506                                                 if ((ent == &player) && ((game.hasAquaLung) || (engine.cheatExtras)))
507                                                 {
508                                                         player.setSprites(graphics.getSprite("BobRight", true), graphics.getSprite("BobLeft", true), graphics.getSprite("BobSpin", true));
509                                                 }
510                                         }
511
512                                         ent->environment = ENV_AIR;
513                                         
514                                         if (ent->dy < 0)
515                                         {
516                                                 audio.playSound(SND_WATEROUT, CH_TOUCH, ent->x);
517                                         }
518
519                                         ent->checkEnvironment();
520                                 }
521                         }
522                         ent->falling = true;
523                 case MAP_SOLID:
524                         break;
525                 case MAP_WATER:
526                 case MAP_SLIME:
527                 case MAP_LAVA:
528
529                         ent->falling = false;
530
531                         if (ent->environment == ENV_AIR)
532                         {
533                                 audio.playSound(SND_WATERIN, CH_TOUCH, ent->x);
534                                 if ((mapAttribute == MAP_SLIME) || (mapAttribute == MAP_LAVA))
535                                         ent->thinktime = 1;
536                         }
537                         
538                         // On ice levels water is harmful (because it's very very cold!)
539                         if ((map.isIceLevel) && (mapAttribute == MAP_WATER))
540                         {
541                                 mapAttribute = MAP_LAVA;
542                                 ent->thinktime = 1;
543                         }
544
545                         if (mapAttribute == MAP_WATER)
546                         {
547                                 ent->environment = ENV_WATER;
548                                 if ((ent == &player) && ((game.hasAquaLung) || (engine.cheatExtras)))
549                                 {
550                                         player.setSprites(graphics.getSprite("AquaBobRight", true), graphics.getSprite("AquaBobLeft", true), graphics.getSprite("AquaBobSpin", true));
551                                 }
552                         }
553                         else if (mapAttribute == MAP_SLIME)
554                         {
555                                 ent->environment = ENV_SLIME;
556                         }
557                         else if (mapAttribute == MAP_LAVA)
558                         {
559                                 ent->environment = ENV_LAVA;
560                         }
561                         break;
562         }
563 }
564
565 void raiseWaterLevel()
566 {
567         if (map.waterLevel == map.requiredWaterLevel)
568         {
569                 return;
570         }
571
572         int y = (int)map.waterLevel;
573
574         if ((int)map.waterLevel != map.requiredWaterLevel)
575         {
576                 for (int x = 0 ; x < MAPWIDTH ; x++)
577                 {
578                         if ((map.data[x][y] == MAP_AIR) || (map.isLiquid(x, y)))
579                         {
580                                 map.data[x][y] = MAP_WATER;
581                         }
582                         
583                         if ((map.data[x][y] >= MAP_DECORATION) && (map.data[x][y] <= MAP_WATERANIM))
584                         {
585                                 map.data[x][y] = MAP_WATER;
586                         }
587                         
588                         if (map.data[x][y] >= MAP_TOPLAYER)
589                         {
590                                 map.data[x][y] = MAP_WATER;
591                         }
592                         
593                         if (map.data[x][y - 1] >= MAP_TOPLAYER)
594                         {
595                                 map.data[x][y] = MAP_WATER;
596                         }
597
598                         if ((map.data[x][y - 1] == MAP_AIR) || (map.isLiquid(x, y - 1)))
599                         {
600                                 map.data[x][y - 1] = MAP_WATERANIM;
601                         }
602                         
603                         if ((map.data[x][y - 1] >= MAP_DECORATION) && (map.data[x][y - 1] <= MAP_WATERANIM))
604                         {
605                                 map.data[x][y - 1] = MAP_WATERANIM;
606                         }
607                 }
608
609                 map.waterLevel -= 0.1;
610
611                 int x = (int)(player.x + player.dx) >> BRICKSHIFT;
612                 int y = (int)(player.y + player.height - 1) >> BRICKSHIFT;
613
614                 int mapAttribute = map.data[x][y];
615
616                 if ((mapAttribute == MAP_WATER) && (player.environment == MAP_AIR))
617                 {
618                         evaluateMapAttribute(&player, mapAttribute);
619                 }
620         }
621 }
622
623 void doWind()
624 {
625         map.windChangeTime--;
626         
627         if (map.windChangeTime <= 0)
628         {
629                 map.windPower = 0;
630                 
631                 if (Math::rrand(0, 1) == 0)
632                         map.windPower = Math::rrand(-3, 3);
633                         
634                 // change wind time
635                 map.windChangeTime = Math::rrand(60, 600);
636         }
637         
638         addWindParticles();
639 }
640
641 void parseMapDataLine(const char *line, int y)
642 {
643         int tileIndex = 0;
644         int x = 0;
645
646         while (true)
647         {
648                 sscanf(line, "%d", &tileIndex);
649
650                 map.data[x][y] = tileIndex;
651
652                 while (true)
653                 {
654                         line++;
655
656                         if (*line == ' ')
657                                 break;
658                 }
659
660                 x++;
661
662                 if (x == MAPWIDTH)
663                         break;
664         }
665 }
666
667 bool loadMapData(const char *filename)
668 {
669         map.clear();
670
671         if (!engine.loadData(filename))
672                 graphics.showErrorAndExit("The requested map '%s' was not found.", filename);
673
674         char *token = strtok((char*)engine.dataBuffer, "\n");
675         parseMapDataLine(token, 0);
676
677         int y = 1;
678
679         while (true)
680         {
681                 token = strtok(NULL, "\n");
682
683                 parseMapDataLine(token, y);
684
685                 y++;
686                 if (y == MAPHEIGHT)
687                         break;
688         }
689
690         getMapTokens();
691
692         adjustObjectives();
693         initMIAPhrases();
694
695         return true;
696 }