1 /*
2 Copyright (C) 2009-2021 Parallel Realities
3
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.
8
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.
12
13 See the GNU General Public License for more details.
14
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, 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18 */
19
20 #include "headers.h"
21
22 #include "audio/audio.h"
23 #include "audio/music.h"
24 #include "credits.h"
25 #include "entity.h"
26 #include "event/trigger.h"
27 #include "game.h"
28 #include "geometry.h"
29 #include "graphics/graphics.h"
30 #include "map.h"
31 #include "player.h"
32 #include "system/error.h"
33 #include "system/pak.h"
34 #include "system/random.h"
35 #include "system/resources.h"
36 #include "weather.h"
37 #include "world/target.h"
38
39 static Map map;
40 static Texture *mapImages[MAX_TILES];
41 static int lavaTile, waterTile, slimeTile;
42
43 extern Entity *self, player;
44 extern Game game;
45
46 static void loadMapTiles(char *);
47 static void loadMapBackground(char *name, int);
48 static void loadAmbience(char *);
49
50 static char *extensions[] = {"ogg", "mp3", "wav", NULL};
51
loadMap(char * name,int loadEntityResources)52 void loadMap(char *name, int loadEntityResources)
53 {
54 int x, y, animTileID;
55 char itemName[MAX_MESSAGE_LENGTH], filename[MAX_LINE_LENGTH], *line, *token, *savePtr1, *savePtr2;
56 unsigned char *buffer;
57
58 savePtr1 = NULL;
59 savePtr2 = NULL;
60
61 lavaTile = LAVA_TILE_START;
62
63 slimeTile = SLIME_TILE_START;
64
65 waterTile = WATER_TILE_START + 1;
66
67 SNPRINTF(filename, sizeof(filename), "data/maps/%s.dat", name);
68
69 buffer = loadFileFromPak(filename);
70
71 /* Set the filename */
72
73 STRNCPY(map.filename, name, sizeof(map.filename));
74
75 /* Reset the weather */
76
77 setWeather(NO_WEATHER);
78
79 /* Reset the minimum and maximum scrolling */
80
81 map.minX = MAX_MAP_X;
82 map.minY = 0;
83
84 map.maxX = map.maxY = 0;
85
86 map.forceMinY = FALSE;
87
88 /* Reset the clipping */
89
90 map.darkMap = FALSE;
91
92 /* Read the data from the file into the map */
93
94 line = strtok_r((char *)buffer, "\n", &savePtr1);
95
96 /* Reset the animated tiles */
97
98 if (map.animTileTotal > 0)
99 {
100 for (x=0;x<map.animTileTotal;x++)
101 {
102 free(map.animTile[x].tile);
103 }
104
105 free(map.animTile);
106 }
107
108 map.animTileTotal = 0;
109
110 animTileID = 0;
111
112 while (line != NULL)
113 {
114 sscanf(line, "%s", itemName);
115
116 if (strcmpignorecase(itemName, "MAP_NAME") == 0)
117 {
118 sscanf(line, "%*s %[^$]s\n", itemName);
119
120 STRNCPY(map.mapName, itemName, sizeof(map.mapName));
121 }
122
123 else if (strcmpignorecase(itemName, "TILESET") == 0)
124 {
125 /* Load the map tiles */
126
127 sscanf(line, "%*s %s\n", itemName);
128
129 loadMapTiles(itemName);
130
131 STRNCPY(map.tilesetName, itemName, sizeof(map.tilesetName));
132 }
133
134 else if (strcmpignorecase(itemName, "BACKGROUND_SPEED") == 0)
135 {
136 /* Set the background speed */
137
138 sscanf(line, "%*s %s\n", itemName);
139
140 map.backgroundSpeed[0] = atof(itemName);
141 }
142
143 else if (strcmpignorecase(itemName, "WRAP_X") == 0)
144 {
145 /* Set the wrapping */
146
147 sscanf(line, "%*s %s\n", itemName);
148
149 map.wrapX[0] = (strcmpignorecase(itemName, "TRUE") == 0 ? TRUE : FALSE);
150 }
151
152 else if (strcmpignorecase(itemName, "WRAP_Y") == 0)
153 {
154 /* Set the wrapping */
155
156 sscanf(line, "%*s %s\n", itemName);
157
158 map.wrapY[0] = (strcmpignorecase(itemName, "TRUE") == 0 ? TRUE : FALSE);
159 }
160
161 else if (strcmpignorecase(itemName, "BACKGROUND_SPEED_2") == 0)
162 {
163 /* Set the background speed */
164
165 sscanf(line, "%*s %s\n", itemName);
166
167 map.backgroundSpeed[1] = atof(itemName);
168 }
169
170 else if (strcmpignorecase(itemName, "WRAP_X_2") == 0)
171 {
172 /* Set the wrapping */
173
174 sscanf(line, "%*s %s\n", itemName);
175
176 map.wrapX[1] = (strcmpignorecase(itemName, "TRUE") == 0 ? TRUE : FALSE);
177 }
178
179 else if (strcmpignorecase(itemName, "WRAP_Y_2") == 0)
180 {
181 /* Set the wrapping */
182
183 sscanf(line, "%*s %s\n", itemName);
184
185 map.wrapY[1] = (strcmpignorecase(itemName, "TRUE") == 0 ? TRUE : FALSE);
186 }
187
188 else if (strcmpignorecase(itemName, "DARK_MAP") == 0)
189 {
190 /* Set the darkness */
191
192 sscanf(line, "%*s %s\n", itemName);
193
194 map.darkMap = (strcmpignorecase(itemName, "TRUE") == 0 ? TRUE : FALSE);
195 }
196
197 else if (strcmpignorecase(itemName, "AMBIENCE") == 0)
198 {
199 /* Load the ambience */
200
201 sscanf(line, "%*s %s\n", itemName);
202
203 loadAmbience(itemName);
204
205 STRNCPY(map.ambienceName, itemName, sizeof(map.ambienceName));
206 }
207
208 else if (strcmpignorecase(itemName, "MUSIC") == 0)
209 {
210 /* Load the music */
211
212 x = sscanf(line, "%*s %s\n", itemName);
213
214 if (x > 0)
215 {
216 STRNCPY(map.musicName, itemName, sizeof(map.musicName));
217 }
218 }
219
220 else if (strcmpignorecase(itemName, "WEATHER") == 0)
221 {
222 /* Set the weather */
223
224 sscanf(line, "%*s %s\n", itemName);
225
226 x = getWeatherTypeByName(itemName);
227
228 setWeather(x);
229 }
230
231 else if (strcmpignorecase(itemName, "MIN_Y") == 0)
232 {
233 /* The map's minimum Y */
234
235 sscanf(line, "%*s %s\n", itemName);
236
237 map.forceMinY = (strcmpignorecase(itemName, "TRUE") == 0 ? TRUE : FALSE);
238
239 if (map.forceMinY == TRUE)
240 {
241 map.minY = MAX_MAP_Y;
242 }
243 }
244
245 else if (strcmpignorecase(itemName, "ANIM_TILE_COUNT") == 0)
246 {
247 /* The map's total number of animated tiles */
248
249 sscanf(line, "%*s %s\n", itemName);
250
251 map.animTileTotal = atoi(itemName);
252
253 if (map.animTileTotal > 0)
254 {
255 map.animTile = malloc(sizeof(AnimTile) * map.animTileTotal);
256
257 if (map.animTile == NULL)
258 {
259 showErrorAndExit("Failed to allocate a whole %d bytes for the animated tile count", (int)(sizeof(int *) * map.animTileTotal));
260 }
261 }
262
263 /* A set of animated tiles */
264
265 for (animTileID=0;animTileID<map.animTileTotal;animTileID++)
266 {
267 line = strtok_r(NULL, "\n", &savePtr1);
268
269 y = countTokens(line, " ");
270
271 map.animTile[animTileID].tileCount = y;
272
273 map.animTile[animTileID].tileIndex = 0;
274
275 map.animTile[animTileID].tile = malloc(sizeof(int) * y);
276
277 if (map.animTile[animTileID].tile == NULL)
278 {
279 showErrorAndExit("Failed to allocate a whole %d bytes for the animated tiles", (int)(sizeof(int) * y));
280 }
281
282 token = strtok_r(line, " ", &savePtr2);
283
284 for (x=0;x<y;x++)
285 {
286 map.animTile[animTileID].tile[x] = atoi(token);
287
288 token = strtok_r(NULL, " ", &savePtr2);
289 }
290 }
291 }
292
293 else if (strcmpignorecase(itemName, "DATA") == 0)
294 {
295 line = strtok_r(NULL, "\n", &savePtr1);
296
297 map.maxX = map.maxY = 0;
298
299 for (y=0;y<MAX_MAP_Y;y++)
300 {
301 token = strtok_r(line, " ", &savePtr2);
302
303 for (x=0;x<MAX_MAP_X;x++)
304 {
305 map.tile[y][x] = atoi(token);
306 /*
307 if (map.tile[y][x] != 0 && map.tile[y][x] <= 3)
308 {
309 map.tile[y][x] = 1 + (prand() % 3);
310 }
311
312 if (map.tile[y][x] == 132)
313 {
314 if (prand() % 50 == 0)
315 {
316 map.tile[y][x] = 123 + (prand() % 2);
317 }
318 }
319 */
320 if (map.tile[y][x] > 0)
321 {
322 if (x > map.maxX)
323 {
324 map.maxX = x;
325 }
326
327 if (y > map.maxY)
328 {
329 map.maxY = y;
330 }
331
332 if (x < map.minX)
333 {
334 map.minX = x;
335 }
336
337 if (map.forceMinY == TRUE && y < map.minY)
338 {
339 map.minY = y;
340 }
341 }
342
343 token = strtok_r(NULL, " ", &savePtr2);
344 }
345
346 if (y + 1 != MAX_MAP_Y)
347 {
348 line = strtok_r(NULL, "\n", &savePtr1);
349 }
350 }
351 /*
352 for (y=0;y<MAX_MAP_Y;y++)
353 {
354 for (x=0;x<MAX_MAP_X;x++)
355 {
356 if (map.tile[y][x] == 4 && map.tile[y + 1][x] == 0)
357 {
358 map.tile[y][x] = 7 + (prand() % 3);
359
360 map.tile[y + 1][x] = map.tile[y][x] + 3;
361 }
362 }
363 }
364 */
365 }
366
367 else if (loadEntityResources == TRUE && strcmpignorecase(itemName, "{") == 0)
368 {
369 loadResources(savePtr1);
370 }
371
372 else if (loadEntityResources == TRUE && strcmpignorecase(itemName, "}") == 0)
373 {
374 showErrorAndExit("Parse error: encountered closing } without matching {");
375 }
376
377 line = strtok_r(NULL, "\n", &savePtr1);
378 }
379 /*
380 printf("X %d - %d Y: %d - %d\n", map.minX, map.maxX, map.minY, map.maxY);
381
382 yy = 0;
383
384 if (map.minY != 0 || map.minX != 0)
385 {
386 for (y=map.minY;y<=map.maxY;y++)
387 {
388 xx = 0;
389
390 for (x=map.minX;x<=map.maxX;x++)
391 {
392 map.tile[yy][xx] = map.tile[y][x];
393
394 xx++;
395
396 map.tile[y][x] = 0;
397 }
398
399 yy++;
400 }
401
402
403 map.minX *= TILE_SIZE;
404 map.minY *= TILE_SIZE;
405
406 printf("MAP_NAME %s\nTRANSLATE_ENTITIES %d %d\n", name, map.minX, map.minY);
407
408 entities = getEntities();
409
410 player.x -= map.minX;
411 player.y -= map.minY;
412
413 for (el=entities->next;el!=NULL;el=el->next)
414 {
415 e = el->entity;
416
417 e->x -= map.minX;
418 e->y -= map.minY;
419
420 if (e->startX - map.minX > 0)
421 {
422 e->startX -= map.minX;
423 }
424
425 if (e->startY - map.minY > 0)
426 {
427 e->startY -= map.minY;
428 }
429
430 if (e->endX - map.minX > 0)
431 {
432 e->endX -= map.minX;
433 }
434
435 if (e->endY - map.minY > 0)
436 {
437 e->endY -= map.minY;
438 }
439 }
440
441 targets = getTargets();
442
443 for (x=0;x<MAX_TARGETS;x++)
444 {
445 if (targets[x].active == TRUE)
446 {
447 if (targets[x].x - map.minX > 0)
448 {
449 targets[x].x -= map.minX;
450 }
451
452 if (targets[x].y - map.minY > 0)
453 {
454 targets[x].y -= map.minY;
455 }
456 }
457 }
458 }
459 */
460 /* Set the maximum scroll position of the map */
461
462 map.maxX = (map.maxX + 1) * TILE_SIZE;
463 map.maxY = (map.maxY + 1) * TILE_SIZE;
464
465 /* Set the minimum scroll position of the map */
466
467 map.minX = map.minX * TILE_SIZE;
468 map.minY = map.minY * TILE_SIZE;
469
470 /* Set the start coordinates */
471
472 map.startX = map.startY = 0;
473
474 /* Set the thinkTime */
475
476 map.thinkTime = 3;
477
478 /* Close the file afterwards */
479
480 free(buffer);
481
482 setTransition(TRANSITION_IN, NULL);
483
484 if (game.canContinue == FALSE && game.overrideMusic == FALSE)
485 {
486 playMapMusic();
487 }
488
489 resetCameraLimits();
490
491 cameraSnapToTargetEntity();
492 }
493
saveMap()494 int saveMap()
495 {
496 int x, y;
497 char filename[MAX_LINE_LENGTH];
498 FILE *fp;
499
500 self = &player;
501
502 if (self->inUse == FALSE)
503 {
504 printf("No player start defined\n");
505
506 return FALSE;
507 }
508
509 SNPRINTF(filename, sizeof(filename), "data/maps/%s.dat", map.filename);
510
511 printf("Saving map to %s\n", filename);
512
513 fp = fopen(filename, "wb");
514
515 /* If we can't open the map then exit */
516
517 if (fp == NULL)
518 {
519 showErrorAndExit("Failed to open map %s", map.filename);
520 }
521
522 fprintf(fp, "MAP_NAME %s\n", map.mapName);
523 fprintf(fp, "MUSIC %s\n", map.musicName);
524 fprintf(fp, "TILESET %s\n", map.tilesetName);
525 fprintf(fp, "AMBIENCE %s\n", map.ambienceName);
526 fprintf(fp, "BACKGROUND_SPEED %0.1f\n", map.backgroundSpeed[0]);
527 fprintf(fp, "WRAP_X %s\n", map.wrapX[0] == TRUE ? "TRUE" : "FALSE");
528 fprintf(fp, "WRAP_Y %s\n", map.wrapY[0] == TRUE ? "TRUE" : "FALSE");
529 fprintf(fp, "BACKGROUND_SPEED_2 %0.1f\n", map.backgroundSpeed[1]);
530 fprintf(fp, "WRAP_X_2 %s\n", map.wrapX[1] == TRUE ? "TRUE" : "FALSE");
531 fprintf(fp, "WRAP_Y_2 %s\n", map.wrapY[1] == TRUE ? "TRUE" : "FALSE");
532 fprintf(fp, "WEATHER %s\n", getWeather());
533 fprintf(fp, "MIN_Y %s\n", map.forceMinY == TRUE ? "TRUE" : "FALSE");
534 fprintf(fp, "DARK_MAP %s\n", map.darkMap == TRUE ? "TRUE" : "FALSE");
535 fprintf(fp, "ANIM_TILE_COUNT %d\n", map.animTileTotal);
536
537 if (map.animTileTotal != 0)
538 {
539 for (x=0;x<map.animTileTotal;x++)
540 {
541 for (y=0;y<map.animTile[x].tileCount;y++)
542 {
543 fprintf(fp, "%d ", map.animTile[x].tile[y]);
544 }
545
546 fprintf(fp, "\n");
547 }
548 }
549
550 fprintf(fp, "DATA\n");
551
552 /* Write the data from the file into the map */
553
554 for (y=0;y<MAX_MAP_Y;y++)
555 {
556 for (x=0;x<MAX_MAP_X;x++)
557 {
558 fprintf(fp, "%d ", map.tile[y][x]);
559 }
560
561 fprintf(fp, "\n");
562 }
563
564 /* Now write out all of the Entities */
565
566 writePlayerMapStartToFile(fp);
567
568 writeEntitiesToFile(fp);
569
570 /* Now the targets */
571
572 writeTargetsToFile(fp);
573
574 /* And the triggers */
575
576 writeTriggersToFile(fp);
577
578 /* Close the file afterwards */
579
580 fclose(fp);
581
582 return TRUE;
583 }
584
doMap()585 void doMap()
586 {
587 int i;
588
589 i = 0;
590
591 map.thinkTime--;
592
593 if (map.thinkTime <= 0)
594 {
595 lavaTile++;
596
597 if (lavaTile > LAVA_TILE_END)
598 {
599 lavaTile = LAVA_TILE_START;
600 }
601
602 waterTile++;
603
604 if (waterTile > WATER_TILE_END)
605 {
606 waterTile = WATER_TILE_START + 1;
607 }
608
609 slimeTile++;
610
611 if (slimeTile > SLIME_TILE_END)
612 {
613 slimeTile = SLIME_TILE_START;
614 }
615
616 map.thinkTime = 3;
617 }
618
619 map.blendTime -= 3;
620
621 if (map.blendTime < 0)
622 {
623 map.blendTime = 0;
624 }
625
626 map.animThinkTime--;
627
628 if (map.animThinkTime < 0)
629 {
630 for (i=0;i<map.animTileTotal;i++)
631 {
632 map.animTile[i].tileIndex++;
633
634 if (map.animTile[i].tileIndex >= map.animTile[i].tileCount)
635 {
636 map.animTile[i].tileIndex = 0;
637 }
638 }
639
640 map.animThinkTime = 15;
641 }
642 }
643
loadMapTiles(char * dir)644 static void loadMapTiles(char *dir)
645 {
646 int i;
647 char filename[255];
648
649 /* Load the blank tile for the editor */
650
651 mapImages[0] = loadImage("gfx/map/0.png");
652
653 for (i=1;i<MAX_TILES;i++)
654 {
655 SNPRINTF(filename, sizeof(filename), "gfx/map/%s/%d.png", dir, i);
656
657 if (existsInPak(filename) == FALSE)
658 {
659 continue;
660 }
661
662 mapImages[i] = loadImage(filename);
663 }
664
665 SNPRINTF(filename, sizeof(filename), "gfx/map/%s/background.png", dir);
666
667 loadMapBackground(filename, 0);
668
669 SNPRINTF(filename, sizeof(filename), "gfx/map/%s/background1.png", dir);
670
671 loadMapBackground(filename, 1);
672 }
673
drawMapBackground()674 void drawMapBackground()
675 {
676 int x, y;
677
678 map.backgroundStartX[0] = map.startX * map.backgroundSpeed[0];
679 map.backgroundStartY[0] = map.startY * map.backgroundSpeed[0];
680
681 if (map.backgroundStartX[0] + SCREEN_WIDTH > map.background[0]->w && map.wrapX[0] == FALSE)
682 {
683 map.backgroundStartX[0] = map.background[0]->w - SCREEN_WIDTH;
684 }
685
686 if (map.backgroundStartY[0] + SCREEN_HEIGHT > map.background[0]->h && map.wrapY[0] == FALSE)
687 {
688 map.backgroundStartY[0] = map.background[0]->h - SCREEN_HEIGHT;
689 }
690
691 if (map.wrapX[0] == FALSE && map.wrapY[0] == FALSE)
692 {
693 drawClippedImage(map.background[0], map.backgroundStartX[0], map.backgroundStartY[0], 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
694 }
695
696 else if (map.wrapX[0] == TRUE && map.wrapY[0] == FALSE)
697 {
698 x = map.backgroundStartX[0] % map.background[0]->w;
699
700 drawClippedImage(map.background[0], x, map.backgroundStartY[0], 0, 0, map.background[0]->w - x, SCREEN_HEIGHT);
701
702 drawClippedImage(map.background[0], 0, map.backgroundStartY[0], map.background[0]->w - x, 0, x, SCREEN_HEIGHT);
703 }
704
705 else if (map.wrapX[0] == FALSE && map.wrapY[0] == TRUE)
706 {
707 y = map.backgroundStartY[0] % map.background[0]->h;
708
709 drawClippedImage(map.background[0], map.backgroundStartX[0], y, 0, 0, SCREEN_WIDTH, map.background[0]->h - y);
710
711 drawClippedImage(map.background[0], map.backgroundStartX[0], 0, 0, map.background[0]->h - y, SCREEN_WIDTH, y);
712 }
713
714 else
715 {
716 x = map.backgroundStartX[0] % map.background[0]->w;
717 y = map.backgroundStartY[0] % map.background[0]->h;
718
719 drawClippedImage(map.background[0], x, y, 0, 0, map.background[0]->w - x, map.background[0]->h - y);
720
721 drawClippedImage(map.background[0], 0, y, map.background[0]->w - x, 0, x, map.background[0]->h - y);
722
723 drawClippedImage(map.background[0], x, 0, 0, map.background[0]->h - y, map.background[0]->w - x, y);
724
725 drawClippedImage(map.background[0], 0, 0, map.background[0]->w - x, map.background[0]->h - y, x, y);
726 }
727
728 if (map.background[1] != NULL)
729 {
730 map.backgroundStartX[1] = map.startX * map.backgroundSpeed[1];
731 map.backgroundStartY[1] = map.startY * map.backgroundSpeed[1];
732
733 if (map.backgroundStartX[1] + SCREEN_WIDTH > map.background[1]->w && map.wrapX[1] == FALSE)
734 {
735 map.backgroundStartX[1] = map.background[1]->w - SCREEN_WIDTH;
736 }
737
738 if (map.backgroundStartY[1] + SCREEN_HEIGHT > map.background[1]->h && map.wrapY[1] == FALSE)
739 {
740 map.backgroundStartY[1] = map.background[1]->h - SCREEN_HEIGHT;
741 }
742
743 if (map.wrapX[1] == FALSE && map.wrapY[1] == FALSE)
744 {
745 drawClippedImage(map.background[1], map.backgroundStartX[1], map.backgroundStartY[1], 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
746 }
747
748 else if (map.wrapX[1] == TRUE && map.wrapY[1] == FALSE)
749 {
750 x = map.backgroundStartX[1] % map.background[1]->w;
751
752 drawClippedImage(map.background[1], x, map.backgroundStartY[1], 0, 0, map.background[1]->w - x, SCREEN_HEIGHT);
753
754 drawClippedImage(map.background[1], 0, map.backgroundStartY[1], map.background[1]->w - x, 0, x, SCREEN_HEIGHT);
755 }
756
757 else if (map.wrapX[1] == FALSE && map.wrapY[1] == TRUE)
758 {
759 y = map.backgroundStartY[1] % map.background[1]->h;
760
761 drawClippedImage(map.background[1], map.backgroundStartX[1], y, 0, 0, SCREEN_WIDTH, map.background[1]->h - y);
762
763 drawClippedImage(map.background[1], map.backgroundStartX[1], 0, 0, map.background[1]->h - y, SCREEN_WIDTH, y);
764 }
765
766 else
767 {
768 x = map.backgroundStartX[1] % map.background[1]->w;
769 y = map.backgroundStartY[1] % map.background[1]->h;
770
771 drawClippedImage(map.background[1], x, y, 0, 0, map.background[1]->w - x, map.background[1]->h - y);
772
773 drawClippedImage(map.background[1], 0, y, map.background[1]->w - x, 0, x, map.background[1]->h - y);
774
775 drawClippedImage(map.background[1], x, 0, 0, map.background[1]->h - y, map.background[1]->w - x, y);
776
777 drawClippedImage(map.background[1], 0, 0, map.background[1]->w - x, map.background[1]->h - y, x, y);
778 }
779 }
780 }
781
drawMap(int depth)782 void drawMap(int depth)
783 {
784 int i, x, y, mapX, x1, x2, mapY, y1, y2, tileID;
785
786 mapX = map.startX / TILE_SIZE;
787 x1 = (map.startX % TILE_SIZE) * -1;
788 x2 = x1 + SCREEN_WIDTH + (x1 == 0 ? 0 : TILE_SIZE);
789
790 mapY = map.startY / TILE_SIZE;
791 y1 = (map.startY % TILE_SIZE) * -1;
792 y2 = y1 + SCREEN_HEIGHT + (y1 == 0 ? 0 : TILE_SIZE);
793
794 /* Draw the map starting at the startX and startY */
795
796 for (y=y1;y<y2;y+=TILE_SIZE)
797 {
798 mapX = map.startX / TILE_SIZE;
799
800 for (x=x1;x<x2;x+=TILE_SIZE)
801 {
802 switch (map.tile[mapY][mapX])
803 {
804 case LAVA_TILE_START:
805 tileID = lavaTile;
806 break;
807
808 case SLIME_TILE_START:
809 tileID = slimeTile;
810 break;
811
812 case WATER_TILE_START + 1:
813 tileID = waterTile;
814 break;
815
816 default:
817 tileID = map.tile[mapY][mapX];
818 break;
819 }
820
821 i = 0;
822
823 for (i=0;i<map.animTileTotal;i++)
824 {
825 if (tileID == map.animTile[i].tile[0])
826 {
827 tileID = map.animTile[i].tile[map.animTile[i].tileIndex];
828 }
829 }
830
831 if (tileID == BLANK_TILE)
832 {
833 mapX++;
834
835 continue;
836 }
837
838 /*
839 if (mapImages[tileID] == NULL)
840 {
841 printf("Tile %d is NULL\n", tileID);
842
843 cleanup(0);
844 }
845 */
846
847 if (game.status == IN_CREDITS)
848 {
849 drawBox(x, y, TILE_SIZE, TILE_SIZE, 0, 0, 0, 255);
850 }
851
852 else
853 {
854 switch (depth)
855 {
856 case 0:
857 if (tileID >= BACKGROUND_TILE_START && tileID <= BACKGROUND_TILE_END)
858 {
859 drawImage(mapImages[tileID], x, y, FALSE, 255);
860 }
861 break;
862
863 case 1:
864 if (tileID < BACKGROUND_TILE_START)
865 {
866 drawImage(mapImages[tileID], x, y, FALSE, 255);
867 }
868 break;
869
870 case 2:
871 if (tileID == SLIME_TILE_BLEND)
872 {
873 drawImage(mapImages[WATER_TILE_START], x, y, FALSE, 128);
874 drawImage(mapImages[slimeTile], x, y, FALSE, map.blendTime);
875
876 if (map.blendTime == 0)
877 {
878 map.tile[mapY][mapX] = WATER_TILE_START;
879 }
880 }
881
882 else if (tileID == SLIME_TILE_BLEND_REVERSE)
883 {
884 drawImage(mapImages[WATER_TILE_START], x, y, FALSE, 128);
885 drawImage(mapImages[slimeTile], x, y, FALSE, 255 - map.blendTime);
886
887 if (map.blendTime == 0)
888 {
889 map.tile[mapY][mapX] = SLIME_TILE_START;
890 }
891 }
892
893 else if (tileID >= FOREGROUND_TILE_START)
894 {
895 drawImage(mapImages[tileID], x, y, FALSE, tileID >= WATER_TILE_START && tileID <= WATER_TILE_END ? 128 : 255);
896 }
897 break;
898
899 default:
900 drawImage(mapImages[tileID], x, y, FALSE, 255);
901 break;
902 }
903 }
904
905 mapX++;
906 }
907
908 mapY++;
909 }
910 }
911
centerEntityOnMap()912 void centerEntityOnMap()
913 {
914 float speed;
915
916 if (map.targetEntity == NULL)
917 {
918 return;
919 }
920
921 if (map.targetEntity->standingOn != NULL && fabs(map.targetEntity->standingOn->speed) > fabs(map.targetEntity->speed))
922 {
923 speed = map.targetEntity->standingOn->speed;
924
925 if (speed < fabs(map.targetEntity->dirX))
926 {
927 speed = fabs(map.targetEntity->dirX);
928 }
929
930 if (speed < fabs(map.targetEntity->standingOn->dirY))
931 {
932 speed = fabs(map.targetEntity->standingOn->dirY);
933 }
934 }
935
936 else
937 {
938 speed = map.targetEntity->originalSpeed > map.targetEntity->speed ? map.targetEntity->originalSpeed : map.targetEntity->speed;
939
940 if (speed < fabs(map.targetEntity->dirX))
941 {
942 speed = fabs(map.targetEntity->dirX);
943 }
944
945 if (speed < fabs(map.targetEntity->dirY))
946 {
947 speed = fabs(map.targetEntity->dirY);
948 }
949 }
950
951 if (map.cameraSpeed != -1)
952 {
953 speed = map.cameraSpeed;
954 }
955
956 map.startX = map.targetEntity->x - (SCREEN_WIDTH / 2);
957
958 if (map.startX < (map.minX != map.cameraMinX ? map.cameraMinX : map.minX))
959 {
960 map.startX = (map.minX != map.cameraMinX ? map.cameraMinX : map.minX);
961 }
962
963 else if (map.startX + SCREEN_WIDTH >= (map.maxX != map.cameraMaxX ? map.cameraMaxX : map.maxX))
964 {
965 map.startX = (map.maxX != map.cameraMaxX ? map.cameraMaxX : map.maxX) - SCREEN_WIDTH;
966
967 if (map.startX < (map.minX != map.cameraMinX ? map.cameraMinX : map.minX))
968 {
969 map.startX = (map.minX != map.cameraMinX ? map.cameraMinX : map.minX);
970 }
971 }
972
973 map.startY = map.targetEntity->y + map.targetEntity->h - SCREEN_HEIGHT / 1.5;
974
975 if (map.startY < (map.minY != map.cameraMinY ? map.cameraMinY : map.minY))
976 {
977 map.startY = (map.minY != map.cameraMinY ? map.cameraMinY : map.minY);
978 }
979
980 else if (map.startY + SCREEN_HEIGHT >= (map.maxY != map.cameraMaxY ? map.cameraMaxY : map.maxY))
981 {
982 map.startY = (map.maxY != map.cameraMaxY ? map.cameraMaxY : map.maxY) - SCREEN_HEIGHT;
983
984 if (map.startY < (map.minY != map.cameraMinY ? map.cameraMinY : map.minY))
985 {
986 map.startY = (map.minY != map.cameraMinY ? map.cameraMinY : map.minY);
987 }
988 }
989
990 if (abs(map.cameraX - map.startX) > speed)
991 {
992 map.cameraX += map.cameraX < map.startX ? speed : -speed;
993 }
994
995 else
996 {
997 map.cameraX = map.startX;
998 }
999
1000 if (abs(map.cameraY - map.startY) > speed)
1001 {
1002 if (map.cameraY < map.startY)
1003 {
1004 map.cameraY += (map.targetEntity->dirY > speed ? map.targetEntity->dirY : speed);
1005 }
1006
1007 else
1008 {
1009 map.cameraY += (map.targetEntity->dirY < -speed ? map.targetEntity->dirY : -speed);
1010 }
1011 }
1012
1013 else
1014 {
1015 map.cameraY = map.startY;
1016 }
1017
1018 map.startX = map.cameraX;
1019 map.startY = map.cameraY;
1020 }
1021
loadMapBackground(char * name,int index)1022 static void loadMapBackground(char *name, int index)
1023 {
1024 /* Load the background image */
1025
1026 if (index == 0)
1027 {
1028 map.background[index] = loadImage(name);
1029 }
1030
1031 else
1032 {
1033 if (existsInPak(name) == FALSE)
1034 {
1035 return;
1036 }
1037
1038 map.background[index] = loadImage(name);
1039 }
1040 }
1041
loadAmbience(char * dir)1042 static void loadAmbience(char *dir)
1043 {
1044 int i, j;
1045 char filename[MAX_PATH_LENGTH];
1046
1047 map.hasAmbience = FALSE;
1048
1049 if (game.audio == FALSE)
1050 {
1051 return;
1052 }
1053
1054 for (i=0;i<MAX_AMBIENT_SOUNDS;i++)
1055 {
1056 for (j=0;extensions[j]!=NULL;j++)
1057 {
1058 SNPRINTF(filename, sizeof(filename), "ambience/%s/%d.%s", dir, i, extensions[j]);
1059
1060 if (existsInPak(filename) == FALSE)
1061 {
1062 continue;
1063 }
1064
1065 map.ambience[i] = loadSound(filename);
1066
1067 map.hasAmbience = TRUE;
1068
1069 break;
1070 }
1071 }
1072 }
1073
freeMap()1074 void freeMap()
1075 {
1076 int i;
1077
1078 if (map.background[0] != NULL)
1079 {
1080 destroyTexture(map.background[0]);
1081
1082 map.background[0] = NULL;
1083 }
1084
1085 if (map.background[1] != NULL)
1086 {
1087 destroyTexture(map.background[1]);
1088
1089 map.background[1] = NULL;
1090 }
1091
1092 /* Free the Map tiles */
1093
1094 for (i=0;i<MAX_TILES;i++)
1095 {
1096 if (mapImages[i] != NULL)
1097 {
1098 destroyTexture(mapImages[i]);
1099
1100 mapImages[i] = NULL;
1101 }
1102 }
1103
1104 /* Free the sounds */
1105
1106 for (i=0;i<MAX_AMBIENT_SOUNDS;i++)
1107 {
1108 if (map.ambience[i] != NULL)
1109 {
1110 Mix_FreeChunk(map.ambience[i]);
1111
1112 map.ambience[i] = NULL;
1113 }
1114 }
1115
1116 memset(&map, 0, sizeof(Map));
1117 }
1118
tileImage(int id)1119 Texture *tileImage(int id)
1120 {
1121 return mapImages[id];
1122 }
1123
mapImageAt(int x,int y)1124 Texture *mapImageAt(int x, int y)
1125 {
1126 return mapImages[map.tile[y][x]];
1127 }
1128
mapTileAt(int x,int y)1129 int mapTileAt(int x, int y)
1130 {
1131 if (x < 0 || x >= MAX_MAP_X || y < 0 || y >= MAX_MAP_Y)
1132 {
1133 return BLANK_TILE;
1134 }
1135
1136 return map.tile[y][x];
1137 }
1138
getMapMaxX()1139 int getMapMaxX()
1140 {
1141 return map.maxX;
1142 }
1143
getMapMaxY()1144 int getMapMaxY()
1145 {
1146 return map.maxY;
1147 }
1148
setMapMaxX(int max)1149 void setMapMaxX(int max)
1150 {
1151 map.maxX = max;
1152 }
1153
setMapMaxY(int max)1154 void setMapMaxY(int max)
1155 {
1156 map.maxY = max;
1157 }
1158
setMapMinX(int min)1159 void setMapMinX(int min)
1160 {
1161 map.minX = min;
1162 }
1163
setMapMinY(int min)1164 void setMapMinY(int min)
1165 {
1166 map.minY = min;
1167 }
1168
getMapMinX()1169 int getMapMinX()
1170 {
1171 return map.minX;
1172 }
1173
getMapMinY()1174 int getMapMinY()
1175 {
1176 return map.minY;
1177 }
1178
getMapStartX()1179 int getMapStartX()
1180 {
1181 return map.startX;
1182 }
1183
getMapStartY()1184 int getMapStartY()
1185 {
1186 return map.startY;
1187 }
1188
setMapStartX(int startX)1189 void setMapStartX(int startX)
1190 {
1191 map.startX = startX;
1192
1193 if (map.startX < 0)
1194 {
1195 map.startX = 0;
1196 }
1197
1198 else if (map.startX + SCREEN_WIDTH >= map.maxX)
1199 {
1200 map.startX = map.maxX - SCREEN_WIDTH;
1201 }
1202 }
1203
setMapStartY(int startY)1204 void setMapStartY(int startY)
1205 {
1206 map.startY = startY;
1207
1208 if (map.startY < 0)
1209 {
1210 map.startY = 0;
1211 }
1212
1213 else if (map.startY + SCREEN_HEIGHT >= map.maxY)
1214 {
1215 map.startY = map.maxY - SCREEN_HEIGHT;
1216 }
1217 }
1218
mapStartXNext(int val)1219 void mapStartXNext(int val)
1220 {
1221 map.startX += val;
1222
1223 if (map.startX < 0)
1224 {
1225 map.startX = 0;
1226 }
1227
1228 else if (map.startX + SCREEN_WIDTH >= map.maxX)
1229 {
1230 map.startX = map.maxX - SCREEN_WIDTH;
1231 }
1232 }
1233
mapStartYNext(int val)1234 void mapStartYNext(int val)
1235 {
1236 map.startY += val;
1237
1238 if (map.startY < 0)
1239 {
1240 map.startY = 0;
1241 }
1242
1243 else if (map.startY + SCREEN_HEIGHT >= map.maxY)
1244 {
1245 map.startY = map.maxY - SCREEN_HEIGHT;
1246 }
1247 }
1248
setTileAt(int x,int y,int tileID)1249 void setTileAt(int x, int y, int tileID)
1250 {
1251 map.tile[y][x] = tileID;
1252 }
1253
nextTile(int id)1254 int nextTile(int id)
1255 {
1256 do
1257 {
1258 id++;
1259
1260 if (id >= MAX_TILES)
1261 {
1262 id = 0;
1263 }
1264 }
1265
1266 while (mapImages[id] == NULL);
1267
1268 return id;
1269 }
1270
prevTile(int id)1271 int prevTile(int id)
1272 {
1273 do
1274 {
1275 id--;
1276
1277 if (id < 0)
1278 {
1279 id = MAX_TILES - 1;
1280 }
1281 }
1282
1283 while (mapImages[id] == NULL);
1284
1285 return id;
1286 }
1287
cameraSnapToTargetEntity()1288 void cameraSnapToTargetEntity()
1289 {
1290 if (map.targetEntity == NULL)
1291 {
1292 return;
1293 }
1294
1295 map.startX = map.targetEntity->x - (SCREEN_WIDTH / 2);
1296
1297 if (map.startX < map.minX)
1298 {
1299 map.startX = map.minX;
1300 }
1301
1302 else if (map.startX + SCREEN_WIDTH >= map.maxX)
1303 {
1304 map.startX = map.maxX - SCREEN_WIDTH;
1305
1306 if (map.startX < map.minX)
1307 {
1308 map.startX = map.minX;
1309 }
1310 }
1311
1312 map.startY = map.targetEntity->y + map.targetEntity->h - SCREEN_HEIGHT / 1.5;
1313
1314 if (map.startY < map.minY)
1315 {
1316 map.startY = map.minY;
1317 }
1318
1319 else if (map.startY + SCREEN_HEIGHT >= map.maxY)
1320 {
1321 map.startY = map.maxY - SCREEN_HEIGHT;
1322
1323 if (map.startY < map.minY)
1324 {
1325 map.startY = map.minY;
1326 }
1327 }
1328
1329 map.cameraX = map.startX;
1330 map.cameraY = map.startY;
1331 }
1332
setCameraPosition(int x,int y)1333 void setCameraPosition(int x, int y)
1334 {
1335 map.cameraX = x;
1336 map.cameraY = y;
1337
1338 map.startX = map.cameraX;
1339 map.startY = map.cameraY;
1340 }
1341
setCameraPositionFromScript(char * position)1342 void setCameraPositionFromScript(char *position)
1343 {
1344 char *x, *y;
1345
1346 x = strtok(position, " ");
1347 y = strtok(NULL, " ");
1348
1349 setCameraPosition(atoi(x), atoi(y));
1350 }
1351
limitCamera(int minX,int minY,int maxX,int maxY)1352 void limitCamera(int minX, int minY, int maxX, int maxY)
1353 {
1354 map.cameraMinX = minX;
1355 map.cameraMinY = minY;
1356
1357 map.cameraMaxX = maxX;
1358 map.cameraMaxY = maxY;
1359 }
1360
limitCameraFromScript(char * line)1361 void limitCameraFromScript(char *line)
1362 {
1363 char limitPlayer[10];
1364 int read;
1365
1366 read = sscanf(line, "%d %d %d %d %s", &map.cameraMinX, &map.cameraMinY, &map.cameraMaxX, &map.cameraMaxY, limitPlayer);
1367
1368 if (read == 5 && strcmpignorecase(limitPlayer, "TRUE") == 0)
1369 {
1370 map.playerMinX = map.cameraMinX;
1371 map.playerMaxX = map.cameraMaxX;
1372 }
1373
1374 else
1375 {
1376 map.playerMinX = map.minX;
1377 map.playerMaxX = map.maxX;
1378 }
1379 }
1380
limitPlayerToCameraLimits()1381 void limitPlayerToCameraLimits()
1382 {
1383 map.playerMinX = map.cameraMinX;
1384 map.playerMaxX = map.cameraMaxX;
1385 }
1386
resetCameraLimits()1387 void resetCameraLimits()
1388 {
1389 map.cameraMinX = map.minX;
1390 map.cameraMinY = map.minY;
1391
1392 map.cameraMaxX = map.maxX;
1393 map.cameraMaxY = map.maxY;
1394
1395 map.playerMinX = map.minX;
1396 map.playerMaxX = map.maxX;
1397 }
1398
getCameraMinX()1399 int getCameraMinX()
1400 {
1401 return map.cameraMinX;
1402 }
1403
getCameraMinY()1404 int getCameraMinY()
1405 {
1406 return map.cameraMinY;
1407 }
1408
getCameraMaxX()1409 int getCameraMaxX()
1410 {
1411 return map.cameraMaxX;
1412 }
1413
getCameraMaxY()1414 int getCameraMaxY()
1415 {
1416 return map.cameraMaxY;
1417 }
1418
cameraAtMinimum()1419 int cameraAtMinimum()
1420 {
1421 return (map.cameraMinX == map.startX && map.cameraMinY == map.startY);
1422 }
1423
getPlayerMinX()1424 int getPlayerMinX()
1425 {
1426 return map.playerMinX;
1427 }
1428
getPlayerMaxX()1429 int getPlayerMaxX()
1430 {
1431 return map.playerMaxX;
1432 }
1433
setCameraSpeed(float speed)1434 void setCameraSpeed(float speed)
1435 {
1436 map.cameraSpeed = speed;
1437 }
1438
centerMapOnEntity(Entity * e)1439 void centerMapOnEntity(Entity *e)
1440 {
1441 map.targetEntity = e;
1442
1443 map.cameraSpeed = -1;
1444 }
1445
getMapFilename()1446 char *getMapFilename()
1447 {
1448 return map.filename;
1449 }
1450
getMapMusic()1451 char *getMapMusic()
1452 {
1453 return map.musicName;
1454 }
1455
getMapName()1456 char *getMapName()
1457 {
1458 return map.mapName;
1459 }
1460
getDistanceFromCamera(int x,int y)1461 int getDistanceFromCamera(int x, int y)
1462 {
1463 return getDistance(map.cameraX + SCREEN_WIDTH / 2, map.cameraY + SCREEN_HEIGHT / 2, x, y);
1464 }
1465
setDarkMap(int dark)1466 void setDarkMap(int dark)
1467 {
1468 map.darkMap = dark;
1469 }
1470
isDarkMap()1471 int isDarkMap()
1472 {
1473 return map.darkMap;
1474 }
1475
resetBlendTime()1476 void resetBlendTime()
1477 {
1478 map.blendTime = 255;
1479 }
1480