1 /*
2 	TODO:
3 
4 	+ Fargoal map algorithm:
5 		+ 10 random rooms, 10 corridors up to length of 12
6 		for each turn, for each room, and each corridor stops once it's hit a
7 		second space. Corridor turns are triggered either randomly or at the
8 		map boundary.
9 		* Note: It's possible to get stuck on a Fargoal map, if the map has
10 		unconnected sections and you either begin the game in a section with
11 		no down stairs, or you teleport into a section with no down or up
12 		stairs and can't teleport back out
13 
14 	+ Random gold and items
15 		30 r=5:d=6:c=47:gosub210:r=l:d=3:c=0:gosub210
16 		210 x=int(r*rnd(1)+d):fori=1tox:gosub144:poken,c:next:return
17 
18 */
19 #include "map.h"
20 #include "game.h"
21 #include "gfx.h"
22 
23 /* Tile dimensions. */
24 int tw = 16, th = 12;
25 
26 /* We are wasting memory and everything could be stuffed into a single byte? Who cares. */
27 static SPOT spots[MAP_H][MAP_W];
28 static int chars[MAP_H][MAP_W];
29 static int seen[MAP_H][MAP_W];
30 static int info[MAP_H][MAP_W];	// e.g. amount of gold, trap depth
31 
32 int spawnpoints;
33 int spawnx[5];
34 int spawny[5];
35 
36 int temple_x;
37 int temple_y;
38 
39 int swordlev;
40 
41 /* Simple minded dirty rectangles system. */
42 int DR_n = 0;
43 int DR_l[100];
44 int DR_t[100];
45 int DR_r[100];
46 int DR_b[100];
47 
48 void
map_put_spot(int x,int y,SPOT s)49 map_put_spot (int x, int y, SPOT s)
50 {
51 	spots[y][x] = s;
52 	DR_add (x, y - 1, x, y);
53 }
54 
55 
56 static void
map_put_random_stuff(SPOT s,int inf,int * rx,int * ry)57 map_put_random_stuff(SPOT s, int inf, int *rx, int *ry)
58 {
59 	int x, y;
60 
61 	do
62 	{
63 		x = rnd (1, MAP_W - 2);
64 		y = rnd (1, MAP_H - 2);
65 	}while (spots[y][x] != SPOT_FLOOR);
66 
67 	spots[y][x] = s;
68 	map_put_info (x, y, inf);
69 
70 	if (rx)
71 		*rx = x;
72 	if (ry)
73 		*ry = y;
74 }
75 
76 
77 void
map_put_char(int x,int y,int id)78 map_put_char (int x, int y, int id)
79 {
80 	int overlap;
81 	overlap = (sprite_h + th - 1) / th - 1;
82 	chars[y][x] = id;
83 	DR_add (x - 1, y - overlap, x + 1, y);
84 }
85 
86 void
map_put_info(int x,int y,int inf)87 map_put_info (int x, int y, int inf)
88 {
89 	info[y][x] = inf;
90 }
91 
92 SPOT
map_get_spot(int x,int y)93 map_get_spot (int x, int y)
94 {
95 	return spots[y][x];
96 }
97 
98 int
map_get_char(int x,int y)99 map_get_char (int x, int y)
100 {
101 	return chars[y][x];
102 }
103 
104 int
map_get_info(int x,int y)105 map_get_info (int x, int y)
106 {
107 	return info[y][x];
108 }
109 
110 void
map_init(void)111 map_init (void)
112 {
113 }
114 
115 static void
_room(int x1,int y1,int x2,int y2,int what)116 _room (int x1, int y1, int x2, int y2, int what)
117 {
118 	int x, y;
119 
120 	for (y = y1; y <= y2; y++)
121 	{
122 		for (x = x1; x <= x2; x++)
123 		{
124 			if (x > 0 && y > 0 && x < MAP_W - 1 && y < MAP_H - 1)
125 				spots[y][x] = what;
126 		}
127 	}
128 }
129 
130 static void
_attach(int x1,int y1,int x2,int y2,SPOT what,int * ax,int * ay)131 _attach (int x1, int y1, int x2, int y2, SPOT what, int *ax, int *ay)
132 {
133 	int x = x1;
134 	int y = y1;
135 
136 	while ((x != x2 || y != y2) && spots[y][x] != what)
137 	{
138 		int dx = 0, dy = 0;
139 
140 		if (x < x2)
141 			dx = 1;
142 		if (x > x2)
143 			dx = -1;
144 		if (y < y2)
145 			dy = 1;
146 		if (y > y2)
147 			dy = -1;
148 		if (dx && dy)
149 		{
150 			int f = rnd (0, 1);
151 
152 			if (f)
153 				dx = 0;
154 			else
155 				dy = 0;
156 		}
157 		x += dx;
158 		y += dy;
159 	}
160 	*ax = x;
161 	*ay = y;
162 }
163 
164 static void
_path(int x1,int y1,int x2,int y2,SPOT what)165 _path (int x1, int y1, int x2, int y2, SPOT what)
166 {
167 	int x = x1;
168 	int y = y1;
169 
170 	while (x != x2 || y != y2)
171 	{
172 		int i;
173 		int l = rnd (1, 4);
174 		int dx = 0, dy = 0;
175 
176 		if (x < x2)
177 			dx = 1;
178 		if (x > x2)
179 			dx = -1;
180 		if (y < y2)
181 			dy = 1;
182 		if (y > y2)
183 			dy = -1;
184 		if (dx && dy)
185 		{
186 			int f = rnd (0, 1);
187 
188 			if (f)
189 				dx = 0;
190 			else
191 				dy = 0;
192 		}
193 		for (i = 0; i < l; i++)
194 		{
195 			spots[y][x] = what;
196 			x += dx;
197 			y += dy;
198 			if (x == x2 && y == y2)
199 				break;
200 			if (!(x > 0 && y > 0 && x < MAP_W - 1 && y < MAP_H - 1))
201 			{
202 				x -= dx;
203 				y -= dy;
204 				break;
205 			}
206 		}
207 	}
208 	spots[y][x] = what;
209 }
210 
211 static void
_corridor(int x,int y,SPOT where,SPOT what,int * ex,int * ey)212 _corridor (int x, int y, SPOT where, SPOT what, int *ex, int *ey)
213 {
214 	int d, dx = 0, dy = 0;
215 	static int ddx[] = { 0, 1, 0, -1 };
216 	static int ddy[] = { 1, 0, -1, 0 };
217 	int l = rnd (10, 70);
218 	int i;
219 	int s = 0;
220 
221 	for (i = 0; i < l; i++)
222 	{
223 		if (s)
224 			s--;
225 		else
226 		{
227 			d = rnd (0, 3);
228 			dx = ddx[d];
229 			dy = ddy[d];
230 			s = rnd (2, 8);
231 		}
232 
233 		spots[y][x] = what;
234 
235 		x += dx;
236 		y += dy;
237 
238 		if (x > 0 && y > 0 && x < MAP_W - 1 && y < MAP_H - 1 && spots[y + dy][x + dx] == where && spots[y + dy + dx][x + dx + dy] == where && spots[y + dy - dx][x + dx - dy] == where && spots[y + dx][x + dy] == where && spots[y - dx][x - dy] == where)
239 		{
240 
241 		}
242 		else
243 		{
244 			x -= dx;
245 			y -= dy;
246 			s = 0;
247 		}
248 	}
249 	*ex = x;
250 	*ey = y;
251 }
252 
253 static void
map_wide(void)254 map_wide (void)
255 {
256 	int sx[15], sy[15];
257 	int l = 2, t = 2, mx = MAP_W / 2, my = MAP_H / 2, r = MAP_W - 3, b = MAP_H - 3;
258 	int i;
259 	int n, m;
260 	int x, y;
261 
262 	/* Random room positions. */
263 	sx[0] = rnd (l, r);
264 	sy[0] = rnd (t, b);
265 
266 	sx[1] = rnd (l, mx);
267 	sy[1] = rnd (t, my);
268 
269 	sx[2] = rnd (mx, r);
270 	sy[2] = rnd (t, my);
271 
272 	sx[3] = rnd (l, mx);
273 	sy[3] = rnd (my, b);
274 
275 	sx[4] = rnd (mx, r);
276 	sy[4] = rnd (my, b);
277 
278 	n = rnd (2, 7);
279 
280 	for (i = 5; i < n; i++)
281 	{
282 		sx[i] = rnd (l, r);
283 		sy[i] = rnd (t, b);
284 	}
285 
286 	/* Place rooms. */
287 	for (i = 0; i < n; i++)
288 	{
289 		_room (sx[i] - rnd (1, 4), sy[i] - rnd (1, 4), sx[i] + rnd (1, 4), sy[i] + rnd (1, 4), SPOT_FLOOR);
290 	}
291 
292 	/* Connect rooms. */
293 	for (i = 0; i < n; i++)
294 	{
295 		int j = i < n - 1 ? i + 1 : 0;
296 		int ax, ay;
297 		int ax2, ay2;
298 
299 		_attach (sx[i], sy[i], sx[j], sy[j], SPOT_WALL, &ax, &ay);
300 		spots[ay][ax] = SPOT_UP;
301 		_attach (sx[j], sy[j], sx[i], sy[i], SPOT_WALL, &ax2, &ay2);
302 		spots[ay2][ax2] = SPOT_DOWN;
303 		_path (ax, ay, ax2, ay2, SPOT_FLOOR);
304 	}
305 
306 
307 	/* Some random corridors*/
308 	m = rnd (2, 7);
309 	for (i = 0; i < m; i++)
310 	{
311 		int ex, ey;
312 		int f = rnd (0, 3);
313 
314 		do
315 		{
316 			x = rnd (1, MAP_W - 2);
317 			y = rnd (4, MAP_H - 2);
318 		}
319 		while (spots[y][x] != SPOT_WALL);
320 
321 		switch (f)
322 		{
323 
324 			case 0:
325 				y = MAP_H - 2;
326 				break;
327 			case 1:
328 				x = 1;
329 				break;
330 			case 2:
331 				y = 4;
332 				break;
333 			case 3:
334 				x = MAP_W - 2;
335 				break;
336 		}
337 		_corridor (x, y, SPOT_WALL, SPOT_FLOOR, &ex, &ey);
338 		{
339 			/* Avoid dead ends */
340 			int j;
341 			j = rnd (0, n - 1);
342 			_path (ex, ey, sx[j], sy[j], SPOT_FLOOR);
343 			j = rnd (0, n - 1);
344 			_path (x, y, sx[j], sy[j], SPOT_FLOOR);
345 		}
346 	}
347 }
348 
349 /*
350 	Algorithm:
351 
352 	Rooms:
353 		- Each room is ranges from 3 to 7 tiles wide and the same range for
354 		height
355 		- x position is between dungeon right wall - room width, and the left
356 		wall
357 		- y position is between bottom dungeon wall - room height, and the top
358 		wall
359 		- A position is stored for each room which is the center of the room
360 
361 	Corridors:
362 		- 10 corridors with random turning stretches of lengths between 4 to 12
363 		and each is spawned in the center of a room
364 		- During the run, a corridor stops once it's hit a second space.
365 		Corridor turns are triggered either randomly or at the map boundary
366 		- When a corridor picks a direction to turn, it can't go back the way
367 		it came
368 */
map_fargoal(void)369 static void map_fargoal(void)
370 {
371 	int i;
372 
373 	struct
374 	{
375 		int x, y;
376 	}room_center[10];
377 
378 	struct
379 	{
380 		int x, y;
381 	}dirs[]={
382 		{1, 0},		// right
383 		{0, 1},		// down
384 		{0, -1},	// up
385 		{-1, 0}		// left
386 	};
387 
388 	// Rooms
389 	for(i=0; i<10; i++)
390 	{
391 		int w, h, x, y;
392 
393 
394 		w=rnd(3, 7);
395 		h=rnd(3, 7);
396 
397 		x=rnd(1, MAP_W-2-w);
398 		y=rnd(1, MAP_H-2-h);
399 
400 		room_center[i].x=x+w/2;
401 		room_center[i].y=y+h/2;
402 
403 		_room(x, y, x+w, y+h, SPOT_FLOOR);
404 	}
405 
406 	// Corridors
407 
408 	/*
409 	15 fori=1to10
410 	16 n=r(i):z=int(4*rnd(1)+1):goto19
411 	*/
412 	for(i=0; i<10; i++)
413 	{
414 		int stone=1; // 1 for initial, 2 for has hit stone, 0 for hit floor
415 		int x=room_center[i].x;
416 		int y=room_center[i].y;
417 		int run, j=0;
418 
419 		int dir, last=-1, skip=TRUE;
420 
421 		dir=rnd(0,3);
422 
423 		/*
424 			17 ifj>1thenv=z
425 			18 z=int(4*rnd(1)+1):ifz=v(v)then18
426 			19 f=1:y1=int(9*rnd(1)+5):j=1
427 		*/
428 		while(stone)
429 		{
430 			// 17
431 			if(!skip)
432 			{
433 				if(j>1)
434 					last=dir;
435 
436 				do
437 					dir=rnd(0,3);
438 				while(dir==3-last);
439 			}
440 			else
441 			{
442 				skip=FALSE;
443 			}
444 
445 			// 19
446 			stone=1;
447 			run=rnd(0, 8)+5;
448 			j=1;
449 
450 			do
451 			{
452 				int m_x, m_y;
453 
454 				// 20 m=n+d(z):p=peek(m):ifp=36thenf=2
455 				m_x=x+dirs[dir].x;
456 				m_y=y+dirs[dir].y;
457 
458 				if(spots[m_y][m_x]!=SPOT_FLOOR)
459 					stone=2;
460 
461 				/*
462 				21 ifm<7104orm>7983then17
463 				22 gosub137:ifx<1orx>38then17
464 				*/
465 				if(m_x<1||m_x>MAP_W-2||m_y<1||m_y>MAP_H-2)
466 				{
467 					// We're on the edge
468 					break;
469 				}
470 
471 				// 23 iff=2andp=32then26
472 				// If we hit a space after hitting stone
473 				if(stone==2 && spots[m_y][m_x]==SPOT_FLOOR)
474 				{
475 					stone=0;
476 					break;
477 				}
478 
479 				/*
480 				24 pokem,c:n=m:j=j+1:ifj=y1then17
481 				25 goto20
482 				*/
483 				spots[m_y][m_x]=SPOT_FLOOR;
484 
485 				x=m_x;
486 				y=m_y;
487 
488 				j++;
489 			}while(j!=run);
490 		}
491 
492 	// 26 next
493 	}
494 }
495 
496 static void
map_sword(void)497 map_sword (void)
498 {
499 	int x, y;
500 	int x2, y2;
501 	int dir, last;
502 	struct
503 	{
504 		int x, y;
505 	} dirs[] = {
506 		{1, 0},
507 		{0, -1},
508 		{-1, 0},
509 		{0, 1}
510 	};
511 	//  469 fori=0to24:poke7063+i*40,32:next:fori=7984to8023:pokei,32:next:gosub132
512 	for (y = 0; y < 25; y++)
513 		map_put_spot (39, y, SPOT_FLOOR);
514 	for (x = 0; x < 40; x++)
515 		map_put_spot (x, 24, SPOT_FLOOR);
516 
517 	//	468 c=36:d=32:n=7105:poken,4:poke251,17:poke252,29:poke3650,5:poke3651,5:sys3616
518 	x = 1;
519 	y = 2;
520 	_room(17, 10, 21, 14, SPOT_FLOOR);
521 	map_put_spot (x, y, SPOT_MARKER + 4);
522 
523 	while (1)
524 	{
525 		while (1)
526 		{
527 			//  470 j=int(4*rnd(1)):x=j
528 			dir = rnd (0, 3);
529 			last = dir;
530 			while (1)
531 			{
532 				//  471 b=n+c(j):ifpeek(b)=cthenpokeb,j:poken+c(j)/2,d:n=b:goto470
533 				x2 = x + dirs[dir].x * 2;
534 				y2 = y + dirs[dir].y * 2;
535 
536 				if (x2 > 0 && y2 > 0 && x2 < MAP_W - 1 && y2 < MAP_H - 1 &&
537 					map_get_spot (x2, y2) == SPOT_WALL)
538 				{
539 					map_put_spot (x2, y2, SPOT_MARKER + dir);
540 					map_put_spot (x + dirs[dir].x, y + dirs[dir].y, SPOT_FLOOR);
541 					x = x2;
542 					y = y2;
543 					break;
544 				}
545 
546 				//  472 j=(j+1)*-(j<3):ifj<>xthen471
547 				dir++;
548 				if (dir == 4)
549 					dir = 0;
550 				if (dir == last)
551 					goto breakbreak;
552 			}
553 		}
554 	breakbreak:
555 		//  473 j=peek(n):poken,d:ifj<4thenn=n-c(j):goto470
556 		dir = map_get_spot (x, y);
557 		map_put_spot (x, y, SPOT_FLOOR);
558 		if (dir >= SPOT_MARKER && dir <= SPOT_MARKER + 3)
559 		{
560 			dir -= SPOT_MARKER;
561 			x -= dirs[dir].x * 2;
562 			y -= dirs[dir].y * 2;
563 		}
564 		else
565 			break;
566 	}
567 	//  474 x=int(4*rnd(1)):pokeh(x),0:ifsf=0thenpoke7523,37
568 	dir = rnd (0, 3);
569 	switch (dir)
570 	{
571 		case 0: map_put_spot (16, 12, SPOT_TREASURE); break;
572 		case 1: map_put_spot (22, 12, SPOT_TREASURE); break;
573 		case 2: map_put_spot (19, 9, SPOT_TREASURE); break;
574 		case 3: map_put_spot (19, 15, SPOT_TREASURE); break;
575 	}
576 	if (!list[1].sword)
577 		map_put_spot (19, 12, SPOT_SWORD);
578 	//  475 fori=1to24:poke7063+i*40,36:next:fori=7984to8023:pokei,36:next:goto28
579 	for (y = 0; y < 25; y++)
580 		map_put_spot (39, y, SPOT_WALL);
581 	for (x = 0; x < 40; x++)
582 		map_put_spot (x, 24, SPOT_WALL);
583 
584 }
585 
586 static int floodmap[MAP_H][MAP_W];
587 static int
do_flood(int x,int y)588 do_flood (int x, int y)
589 {
590 	if (x > 0 && y > 0 && x < MAP_W - 1 && y < MAP_H - 1 &&
591 		!floodmap[y][x] && map_get_spot (x, y) != SPOT_WALL)
592 	{
593 		int i, j;
594 		SPOT s = map_get_spot (x, y);
595 		if (s == SPOT_UP || s == SPOT_DOWN || s == SPOT_PIT || s == SPOT_ROPE)
596 			return 1;
597 		floodmap[y][x] = 1;
598 		for (i = -1; i <= 1; i++)
599 			for (j = -1; j <= 1; j++)
600 			{
601 				if (do_flood (x + i, y + j))
602 					return 1;
603 			}
604 
605 	}
606 	return 0;
607 }
608 
609 static int
flood(int x,int y)610 flood (int x, int y)
611 {
612 	memset (&floodmap, 0, sizeof floodmap);
613 	return do_flood (x, y);
614 }
615 
616 
617 void
map_enter(SPOT what,int howfar)618 map_enter (SPOT what, int howfar)
619 {
620 	int i, x, y, lev;
621 	int n, m;
622 again:
623 	lev = list[1].current_level;
624 	char_num = 2;
625 
626 	if (lev > list[1].deepest_level)
627 		list[1].deepest_level = lev;
628 
629 	{
630 		for (i = 0; i < 6; i++)
631 		{
632 			list[1].spells[i].active = 0;
633 		}
634 	}
635 	list[1].beaconx = 0;
636 	list[1].beacony = 0;
637 
638 	spawnpoints = 0;
639 
640 	for (y = 0; y < MAP_H; y++)
641 	{
642 		for (x = 0; x < MAP_W; x++)
643 		{
644 			spots[y][x] = SPOT_WALL;
645 			chars[y][x] = 0;
646 			seen[y][x] = (list[1].map & (1 << lev)) ? 1 : 0;
647 			info[y][x] = 0;
648 		}
649 	}
650 
651 	/* maps 5, 10, 15, 20.. use our special map. */
652 	if (lev == swordlev)
653 	{
654 		map_sword ();
655 	}
656 	else if (!extensions_dungeons || (lev % 5))
657 	{
658 		map_fargoal();
659 	}
660 	else
661 	{
662 		map_wide ();
663 	}
664 
665 	/* The hero. */
666 	//   37 gosub144:sys3596:sys3392:poken,k:o=n-d%:pokeo,a:gosub138:pokev3,1:gosub146
667 	map_put_random_stuff (what, howfar, &x, &y);
668 	list[1].x=x;
669 	list[1].y=y;
670 	chars[y][x] = 1;
671 
672 	/* Temple. */
673 	//    28 gosub144:poken,38:b3=n-d%
674 	map_put_random_stuff (SPOT_TEMPLE, 0, &temple_x, &temple_y);
675 
676 	/* Stairs down. */
677 	//    29 u%=int(2*rnd(1)+2):fori=1tou%:gosub144:poken,35:v%(i)=n:next
678 	n = rnd (2, 3);
679 	for (i = 0; i <= n; i++)
680 		map_put_random_stuff (SPOT_DOWN, 0, &spawnx[i], &spawny[i]);
681 	spawnpoints = n;
682 
683 	/* Some random gold and treasures. */
684 	//	30 r=5:d=6:c=47:gosub210:r=l:d=3:c=0:gosub210
685 	//  210 x=int(r*rnd(1)+d):fori=1tox:gosub144:poken,c:next:return
686 	n = rnd (0, 4) + 6;
687 	for(i = 0; i <= n; i++)
688 		map_put_random_stuff (SPOT_GOLD, 0, NULL, NULL);
689 
690 	n = MIN (25, rnd (0, lev - 1) + 3);
691 	for(i = 0; i<= n; i++)
692 		map_put_random_stuff (SPOT_TREASURE, 0, NULL, NULL);
693 
694 	monster_init();
695 
696 	/* Human monsters. */
697 	//   31 a%=int(3*rnd(1)):forj=0toa%:gosub144:n%(j)=n:q%(j)=32:gosub320:poken,b(j):d%(j)=1
698    	//   32 sn=j+1:gosub140:poke2041+j,x2+32:poke53288+j,o%(x2):next
699 	/* At least one and at most 3 human monsters.
700 	   Note how monster_strength from the previous level is re-used!
701 	 */
702 	n = rnd (0, 2);
703 	for (i = 0; i <= n; i++)
704 	{
705 		map_put_random_stuff (SPOT_VOID, 0, &x, &y);
706 		chars[y][x] = monster_create (2, monster_strength, x, y);
707 	}
708 
709 	monster_strength = lev;
710 
711 	/* Creature monsters. */
712 	//   33 b%=int(3*rnd(1)+1):v%=a%+b%:ifv%>5thenb%=5-a%
713 	//   34 l%=l:v%=l:forj=0tob%:gosub144:m%(j)=n:p%(j)=32:gosub310:poken,a(j)
714    	//   35 sn=j+a%+2:gosub140:poke2042+a%+j,x2+32:poke53289+a%+j,o%(x2):next
715 	/* At least 2 and at most 4 human monsters. */
716 	m = rnd (1, 3);
717 	/* The line below makes no sense at all ??? */
718 	if (m + n > 5)
719 		m = 5 - n;
720 
721 	for (i = 0; i <= m; i++)
722 	{
723 		map_put_random_stuff (SPOT_VOID, 0, &x, &y);
724 		chars[y][x] = monster_create (1, monster_strength, x, y);
725 	}
726 
727 	/* Up stairs. */
728 	//   36 v%(0)=0:ifl>1orsf=1thengosub144:poken,34:v%(0)=n
729 	if (lev > 1 || list[1].sword)
730 	{
731 		map_put_random_stuff (SPOT_UP, 0,
732 			&spawnx[spawnpoints], &spawny[spawnpoints]);
733 		spawnpoints++;
734 	}
735 
736 
737 	monster_max = monster_count ();
738 
739 	/* Clean up markers. */
740 	for (y = 0; y < MAP_H; y++)
741 	{
742 		for (x = 0; x < MAP_W; x++)
743 		{
744 			if (map_get_spot (x, y) == SPOT_VOID)
745 			{
746 				map_put_spot (x, y, SPOT_FLOOR);
747 			}
748 		}
749 	}
750 
751 	map_seen (list[1].x, list[1].y, 1);
752 
753 	message (FPS * 2, NULL, "Entering level %i.", list[1].current_level);
754 
755 	if (list[1].map & (1 << lev))
756 	{
757 		//  131 t%(i1)=0:gosub113:print"(home)treasure map!!":gosub423:pokev3,255:pokeo+d%,k:i1=tm:goto39
758 		list[1].map &= ~(1 << lev);
759 		message (0, NULL, "Treasure map!!");
760 	}
761 
762 	DR_n = 0;
763 	/* redraw 6 rows above as well.. */
764 	DR_add (0, -6, MAP_W - 1, MAP_H - 1);
765 
766 	global_steps = MAX (1, 20 - list[1].current_level); /* Make monsters wait a moment. */
767 
768 	if (extensions_dungeons)
769 	{
770 		for (y = 0; y < MAP_H; y++)
771 		{
772 			for (x = 0; x < MAP_W; x++)
773 			{
774 				if (map_get_spot (x, y) != SPOT_WALL && !flood (x, y))
775 				{
776 					message (0, NULL, "The goddess of luck intervenes!!");
777 					goto again;
778 				}
779 			}
780 		}
781 	}
782 
783 }
784 
785 void
map_seen(int x,int y,int rad)786 map_seen (int x, int y, int rad)
787 {
788 	int i, j;
789 	int overlap;
790 	int t = y - rad;
791 	int l = x - rad;
792 	int r = x + rad;
793 	int b = y + rad;
794 	int foundc = 0;
795 
796 	if (l < 0)
797 		l = 0;
798 	if (r > MAP_W - 1)
799 		r = MAP_W - 1;
800 	if (b > MAP_H - 1)
801 		b = MAP_H - 1;
802 	for (i = MAX (0, t); i <= b; i++)
803 	{
804 		for (j = l; j <= r; j++)
805 		{
806 			seen[i][j] = 1;
807 			if (chars[i][j])
808 				foundc = 1;
809 		}
810 	}
811 	/* A character might get visible, then everything occluded by it has to
812 	 * be redrawn. */
813 	if (foundc)
814 	{
815 		overlap = (sprite_h + th - 1) / th - 1;
816 		DR_add (l - 1, t - overlap, r + 1, b);
817 	}
818 	else
819 	{
820 		DR_add (l, t - 1, r, b);
821 	}
822 }
823 
824 void
map_hide_completely(void)825 map_hide_completely (void)
826 {
827 	memset (seen, 0, sizeof seen);
828 	DR_add (0, -1, MAP_W - 1, MAP_H - 1);
829 
830 	map_seen(list[1].x, list[1].y, 1);
831 }
832 
833 
map_crash(void)834 void map_crash (void)
835 {
836 	int i, type;
837 	int x, y;
838 
839 	for(i=0; i<1000; i++)
840 	{
841 		x=rnd(0, MAP_W-1);
842 		y=rnd(0, MAP_H-1);
843 
844 		type=rnd(0, 6);
845 
846 		if(type<2)
847 		{
848 			spots[y][x]=SPOT_WALL;
849 		}
850 		else if(type<4)
851 		{
852 			spots[y][x]=SPOT_FLOOR;
853 		}
854 		else if(type<5)
855 		{
856 			spots[y][x]=SPOT_CEILING;
857 		}
858 		else
859 		{
860 			spots[y][x]=SPOT_PIT;
861 		}
862 	}
863 }
864 
865 
866 void
DR_add(int l,int t,int r,int b)867 DR_add (int l, int t, int r, int b)
868 {
869 	int i = DR_n;
870 
871 	if (l < 0)
872 		l = 0;
873 	if (r > MAP_W - 1)
874 		r = MAP_W - 1;
875 	if (b > MAP_H - 1)
876 		b = MAP_H - 1;
877 	DR_l[i] = l;
878 	DR_t[i] = t;
879 	DR_r[i] = r;
880 	DR_b[i] = b;
881 	DR_n++;
882 	if (DR_n == 100)
883 	{
884 		DR_l[i] = 0;
885 		DR_t[i] = -6;
886 		DR_r[i] = MAP_W - 1;
887 		DR_b[i] = MAP_H - 1;
888 		DR_n = 1;
889 	}
890 }
891 
892 static void
_char_draw(int x,int y)893 _char_draw (int x, int y)
894 {
895 	int id = chars[y][x];
896 	if (id)
897 	{
898 		TYPE type = list[id].type;
899 
900 		if (!extensions_overlapfight && list[id].fighting)
901 		{
902 			int e = list[id].fighting;
903 			int back, front;
904 			float back_step, front_step;
905 
906 			if (list[id].attacked)
907 			{
908 				back = id;
909 				front = e;
910 			}
911 			else
912 			{
913 				back = e;
914 				front = id;
915 			}
916 
917 			back_step=(float)list[back].step/(extensions_speed?1:2);
918 			front_step=(float)list[front].step/(extensions_speed?1:2);
919 
920 
921 			draw_sprite (page, anims[list[back].type],
922 				x * tw + tw / 2 - sprite_w / 2 - list[back].dx * back_step,
923 				TOP + y * th + th - sprite_h - list[back].dy * back_step * 3 / 4);
924 			draw_sprite (page, anims[list[front].type],
925 				x * tw + tw / 2 - sprite_w / 2 - list[front].dx * front_step,
926 				TOP + y * th + th - sprite_h - list[front].dy * front_step * 3 / 4);
927 		}
928 		else
929 		if (type != CHAR_ASSASSIN || !list[id].spells[SPELL_INVISIBILITY].active)
930 		{
931 			float st;
932 
933 			st=(float)list[id].step/(extensions_speed?1:2);
934 
935 			draw_sprite (page, anims[type],
936 				x * tw + tw / 2 - sprite_w / 2 - list[id].dx * st,
937 				TOP + y * th + th - sprite_h - list[id].dy * st * 3 / 4);
938 		}
939 	}
940 }
941 
942 /**
943  * Redraws the map tiles in the given region.
944  * o Also possibly overlapping wall tiles from one position below b have
945  *   to be checked.
946  * o For characters, positions 2 more to the left and right, 1 more to the top,
947  *   and 4 more to the bottom have to be checked, because they might overlap
948  *   with the specified region and would get overdrawn otherwise.
949  * o Finally, floor tiles can be overlapping in the current code as well, so
950  *   there we need to check for overlap from 1 tile below now.
951  *
952  * How does it work? It's quite simple.
953  *
954  * We have 3 things to draw:
955  *
956  * 1. Tiles (Floor)
957  * 2. Objects (Walls/Items)
958  * 3. Entities (Characters/Sprites)
959  *
960  * Right now, to make it easy for artists, the first 2 are contained in the
961  * same tilesheet, and we treat everything as object, but fill the complete
962  * map with SPOT_FLOOR before drawing.
963  *
964  * This is interleaved with an objects layer, which consists of SPOT_DOWN,
965  * SPOT_PIT and SPOT_TEMPLE, as they most notably contain floor in the main
966  * theme graphics. This wouldn't be needed with a separation of tiles and
967  * objects.
968  *
969  * Next comes the objects interleaved with entities. Here we draw all the
970  * objects except the above 3, and the entities.
971  *
972  */
973 static void
DR_map_draw(int l,int t,int r,int b)974 DR_map_draw (int l, int t, int r, int b)
975 {
976 	int x, y;
977 	int overlap;
978 
979 	/* Draws the area above the map. Still a relict from the time when
980 	 * the map was as big as the screen, and now useful because characters
981 	 * and walls overlap with this area.
982 	 */
983 	if (t < 0)
984 	{
985 		int b_ = MIN (-1, b);
986 		blit (title, page, l * tw, TOP + t * th, l * tw, TOP + t * th,
987 			(1 + r - l) * tw, (1 + b_ - t) * th);
988 		t = 0;
989 	}
990 
991 	/* Draws floor layer, considering overlap from the 3 special tiles. */
992 	b = MIN (b + 1, MAP_H - 1);
993 	for (y = t; y <= b; y++)
994 	{
995 		for (x = l; x <= r; x++)
996 		{
997 			if (seen[y][x])
998 			{
999 				SPOT s = spots[y][x];
1000 				blit (tiles[SPOT_FLOOR], page, 0, th, x * tw, TOP + y * th, tw, th);
1001 
1002 				if (tileset == 2 || s == SPOT_DOWN || s ==SPOT_PIT || s == SPOT_TEMPLE || s == SPOT_STASH)
1003 					draw_sprite (page, tiles[s], x * tw, TOP + y * th - th);
1004 			}
1005 			else
1006 			{
1007 				blit (tiles[SPOT_VOID], page, 0, th, x * tw, TOP + y * th, tw, th);
1008 			}
1009 		}
1010 	}
1011 
1012 	/* Draw walls/objects/entities layer.
1013 	 * Walls can be overlapping in from the tile 1 more down.
1014 	 * Entities can overlap from tiles below, 2 to the left or right,
1015 	 * or 1 from the top.
1016 	 */
1017 	overlap = (sprite_h + th - 1) / th - 1;
1018 	b = MIN (b + overlap, MAP_H - 1); /* +1 already above */
1019 	l = MAX (l - 2, 0);
1020 	r = MIN (r + 2, MAP_W - 1);
1021 	t = MAX (t - 1, 0);
1022 	for (y = t; y <= b; y++)
1023 	{
1024 		for (x = l; x <= r; x++)
1025 		{
1026 			if (seen[y][x])
1027 			{
1028 				int ch = chars[y][x];
1029 				if (list[ch].step && list[ch].dy == 1)
1030 					_char_draw (x, y);
1031 			}
1032 		}
1033 		for (x = l; x <= r; x++)
1034 		{
1035 			if (seen[y][x])
1036 			{
1037 				SPOT s = spots[y][x];
1038 				if (s > 1)
1039 				{
1040 					if (tileset != 2 && s != SPOT_DOWN && s != SPOT_PIT && s != SPOT_TEMPLE && s != SPOT_STASH)
1041 						draw_sprite (page, tiles[s], x * tw, TOP + y * th - th);
1042 					else
1043 						masked_blit (tiles[s], page, 0, 0, x * tw, TOP + y * th - th, tw, th);
1044 				}
1045 			}
1046 			else
1047 			{
1048 				draw_sprite (page, tiles[SPOT_VOID], x * tw, TOP + y * th - th);
1049 			}
1050 		}
1051 		for (x = l; x <= r; x++)
1052 		{
1053 			if (seen[y][x])
1054 			{
1055 				int ch = chars[y][x];
1056 				if (!list[ch].step || list[ch].dy != 1)
1057 					_char_draw (x, y);
1058 			}
1059 		}
1060 	}
1061 }
1062 
1063 void
map_draw(void)1064 map_draw (void)
1065 {
1066 	int i;
1067 	for (i = 0; i < DR_n; i++)
1068 	{
1069 		set_clip (page, DR_l[i] * tw, TOP + DR_t[i] * th, (DR_r[i] + 1) * tw - 1, TOP + (DR_b[i] + 1) * th - 1);
1070 		DR_map_draw (DR_l[i], DR_t[i], DR_r[i], DR_b[i]);
1071 	}
1072 	set_clip (page, 0, 0, page->w, page->h);
1073 }
1074 
1075 void
map_blit_DRs(void)1076 map_blit_DRs (void)
1077 {
1078 	int i;
1079 
1080 	for (i = 0; i < DR_n; i++)
1081 	{
1082 		blit (page, screen, DR_l[i] * tw, TOP + DR_t[i] * th, DR_l[i] * tw, TOP + DR_t[i] * th, (1 + DR_r[i] - DR_l[i]) * tw, (1 + DR_b[i] - DR_t[i]) * th);
1083 	}
1084 
1085 	DR_n = 0;
1086 }
1087 
1088 /**
1089  * Check if any DR overlaps the given region.
1090  */
1091 int
map_check_DRs(int l,int t,int r,int b)1092 map_check_DRs (int l, int t, int r, int b)
1093 {
1094 	int i;
1095 
1096 	for (i = 0; i < DR_n; i++)
1097 	{
1098 		if (DR_l[i] <= r && DR_r[i] >= l && DR_t[i] <= b && DR_b[i] >= t)
1099 		{
1100 			return 1;
1101 		}
1102 	}
1103 	return 0;
1104 }
1105 
1106 void
map_save(PACKFILE * file)1107 map_save (PACKFILE *file)
1108 {
1109 	int x, y;
1110 
1111 	for (y = 0; y < MAP_H; y++)
1112 	{
1113 		for (x = 0; x < MAP_W; x++)
1114 		{
1115 			pack_iputl (spots[y][x], file);
1116 			pack_iputl (chars[y][x], file);
1117 			pack_iputl (seen[y][x], file);
1118 			pack_iputl (info[y][x], file);
1119 		}
1120 	}
1121 }
1122 
1123 
1124 void
map_load(PACKFILE * file)1125 map_load (PACKFILE *file)
1126 {
1127 	int x, y;
1128 
1129 	for (y = 0; y < MAP_H; y++)
1130 	{
1131 		for (x = 0; x < MAP_W; x++)
1132 		{
1133 			spots[y][x] = pack_igetl (file);
1134 			chars[y][x] = pack_igetl (file);
1135 			seen[y][x] = pack_igetl (file);
1136 			info[y][x] = pack_igetl (file);
1137 		}
1138 	}
1139 }
1140