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