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