1 /**
2  * @file automap.cpp
3  *
4  * Implementation of the in-game map overlay.
5  */
6 #include "all.h"
7 
8 DEVILUTION_BEGIN_NAMESPACE
9 
10 namespace {
11 /**
12  * Maps from tile_id to automap type.
13  * BUGFIX: only the first 256 elements are ever read
14  */
15 Uint16 automaptype[512];
16 
17 static Sint32 AutoMapX;
18 static Sint32 AutoMapY;
19 
20 /** color used to draw the player's arrow */
21 #define COLOR_PLAYER (PAL8_ORANGE + 1)
22 /** color for bright map lines (doors, stairs etc.) */
23 #define COLOR_BRIGHT PAL8_YELLOW
24 /** color for dim map lines/dots */
25 #define COLOR_DIM (PAL16_YELLOW + 8)
26 // color for items on automap
27 #define COLOR_ITEM (PAL8_BLUE + 1)
28 
29 #define MAPFLAG_TYPE 0x000F
30 /** these are in the second byte */
31 #define MAPFLAG_VERTDOOR 0x01
32 #define MAPFLAG_HORZDOOR 0x02
33 #define MAPFLAG_VERTARCH 0x04
34 #define MAPFLAG_HORZARCH 0x08
35 #define MAPFLAG_VERTGRATE 0x10
36 #define MAPFLAG_HORZGRATE 0x20
37 #define MAPFLAG_DIRT 0x40
38 #define MAPFLAG_STAIRS 0x80
39 
40 /**
41  * @brief Renders the given automap shape at the specified screen coordinates.
42  */
DrawAutomapTile(CelOutputBuffer out,Sint32 sx,Sint32 sy,Uint16 automap_type)43 void DrawAutomapTile(CelOutputBuffer out, Sint32 sx, Sint32 sy, Uint16 automap_type)
44 {
45 	Sint32 x1, y1, x2, y2;
46 
47 	Uint8 flags = automap_type >> 8;
48 
49 	if (flags & MAPFLAG_DIRT) {
50 		SetPixel(out, sx, sy, COLOR_DIM);
51 		SetPixel(out, sx - AmLine8, sy - AmLine4, COLOR_DIM);
52 		SetPixel(out, sx - AmLine8, sy + AmLine4, COLOR_DIM);
53 		SetPixel(out, sx + AmLine8, sy - AmLine4, COLOR_DIM);
54 		SetPixel(out, sx + AmLine8, sy + AmLine4, COLOR_DIM);
55 		SetPixel(out, sx - AmLine16, sy, COLOR_DIM);
56 		SetPixel(out, sx + AmLine16, sy, COLOR_DIM);
57 		SetPixel(out, sx, sy - AmLine8, COLOR_DIM);
58 		SetPixel(out, sx, sy + AmLine8, COLOR_DIM);
59 		SetPixel(out, sx + AmLine8 - AmLine32, sy + AmLine4, COLOR_DIM);
60 		SetPixel(out, sx - AmLine8 + AmLine32, sy + AmLine4, COLOR_DIM);
61 		SetPixel(out, sx - AmLine16, sy + AmLine8, COLOR_DIM);
62 		SetPixel(out, sx + AmLine16, sy + AmLine8, COLOR_DIM);
63 		SetPixel(out, sx - AmLine8, sy + AmLine16 - AmLine4, COLOR_DIM);
64 		SetPixel(out, sx + AmLine8, sy + AmLine16 - AmLine4, COLOR_DIM);
65 		SetPixel(out, sx, sy + AmLine16, COLOR_DIM);
66 	}
67 
68 	if (flags & MAPFLAG_STAIRS) {
69 		DrawLineTo(out, sx - AmLine8, sy - AmLine8 - AmLine4, sx + AmLine8 + AmLine16, sy + AmLine4, COLOR_BRIGHT);
70 		DrawLineTo(out, sx - AmLine16, sy - AmLine8, sx + AmLine16, sy + AmLine8, COLOR_BRIGHT);
71 		DrawLineTo(out, sx - AmLine16 - AmLine8, sy - AmLine4, sx + AmLine8, sy + AmLine8 + AmLine4, COLOR_BRIGHT);
72 		DrawLineTo(out, sx - AmLine32, sy, sx, sy + AmLine16, COLOR_BRIGHT);
73 	}
74 
75 	bool do_vert = false;
76 	bool do_horz = false;
77 	bool do_cave_horz = false;
78 	bool do_cave_vert = false;
79 	switch (automap_type & MAPFLAG_TYPE) {
80 	case 1: // stand-alone column or other unpassable object
81 		x1 = sx - AmLine16;
82 		y1 = sy - AmLine16;
83 		x2 = x1 + AmLine32;
84 		y2 = sy - AmLine8;
85 		DrawLineTo(out, sx, y1, x1, y2, COLOR_DIM);
86 		DrawLineTo(out, sx, y1, x2, y2, COLOR_DIM);
87 		DrawLineTo(out, sx, sy, x1, y2, COLOR_DIM);
88 		DrawLineTo(out, sx, sy, x2, y2, COLOR_DIM);
89 		break;
90 	case 2:
91 	case 5:
92 		do_vert = true;
93 		break;
94 	case 3:
95 	case 6:
96 		do_horz = true;
97 		break;
98 	case 4:
99 		do_vert = true;
100 		do_horz = true;
101 		break;
102 	case 8:
103 		do_vert = true;
104 		do_cave_horz = true;
105 		break;
106 	case 9:
107 		do_horz = true;
108 		do_cave_vert = true;
109 		break;
110 	case 10:
111 		do_cave_horz = true;
112 		break;
113 	case 11:
114 		do_cave_vert = true;
115 		break;
116 	case 12:
117 		do_cave_horz = true;
118 		do_cave_vert = true;
119 		break;
120 	}
121 
122 	if (do_vert) {                      // right-facing obstacle
123 		if (flags & MAPFLAG_VERTDOOR) { // two wall segments with a door in the middle
124 			x1 = sx - AmLine32;
125 			x2 = sx - AmLine16;
126 			y1 = sy - AmLine16;
127 			y2 = sy - AmLine8;
128 
129 			DrawLineTo(out, sx, y1, sx - AmLine8, y1 + AmLine4, COLOR_DIM);
130 			DrawLineTo(out, x1, sy, x1 + AmLine8, sy - AmLine4, COLOR_DIM);
131 			DrawLineTo(out, x2, y1, x1, y2, COLOR_BRIGHT);
132 			DrawLineTo(out, x2, y1, sx, y2, COLOR_BRIGHT);
133 			DrawLineTo(out, x2, sy, x1, y2, COLOR_BRIGHT);
134 			DrawLineTo(out, x2, sy, sx, y2, COLOR_BRIGHT);
135 		}
136 		if (flags & MAPFLAG_VERTGRATE) { // right-facing half-wall
137 			DrawLineTo(out, sx - AmLine16, sy - AmLine8, sx - AmLine32, sy, COLOR_DIM);
138 			flags |= MAPFLAG_VERTARCH;
139 		}
140 		if (flags & MAPFLAG_VERTARCH) { // window or passable column
141 			x1 = sx - AmLine16;
142 			y1 = sy - AmLine16;
143 			x2 = x1 + AmLine32;
144 			y2 = sy - AmLine8;
145 
146 			DrawLineTo(out, sx, y1, x1, y2, COLOR_DIM);
147 			DrawLineTo(out, sx, y1, x2, y2, COLOR_DIM);
148 			DrawLineTo(out, sx, sy, x1, y2, COLOR_DIM);
149 			DrawLineTo(out, sx, sy, x2, y2, COLOR_DIM);
150 		}
151 		if ((flags & (MAPFLAG_VERTDOOR | MAPFLAG_VERTGRATE | MAPFLAG_VERTARCH)) == 0)
152 			DrawLineTo(out, sx, sy - AmLine16, sx - AmLine32, sy, COLOR_DIM);
153 	}
154 
155 	if (do_horz) { // left-facing obstacle
156 		if (flags & MAPFLAG_HORZDOOR) {
157 			x1 = sx + AmLine16;
158 			x2 = sx + AmLine32;
159 			y1 = sy - AmLine16;
160 			y2 = sy - AmLine8;
161 
162 			DrawLineTo(out, sx, y1, sx + AmLine8, y1 + AmLine4, COLOR_DIM);
163 			DrawLineTo(out, x2, sy, x2 - AmLine8, sy - AmLine4, COLOR_DIM);
164 			DrawLineTo(out, x1, y1, sx, y2, COLOR_BRIGHT);
165 			DrawLineTo(out, x1, y1, x2, y2, COLOR_BRIGHT);
166 			DrawLineTo(out, x1, sy, sx, y2, COLOR_BRIGHT);
167 			DrawLineTo(out, x1, sy, x2, y2, COLOR_BRIGHT);
168 		}
169 		if (flags & MAPFLAG_HORZGRATE) {
170 			DrawLineTo(out, sx + AmLine16, sy - AmLine8, sx + AmLine32, sy, COLOR_DIM);
171 			flags |= MAPFLAG_HORZARCH;
172 		}
173 		if (flags & MAPFLAG_HORZARCH) {
174 			x1 = sx - AmLine16;
175 			y1 = sy - AmLine16;
176 			x2 = x1 + AmLine32;
177 			y2 = sy - AmLine8;
178 
179 			DrawLineTo(out, sx, y1, x1, y2, COLOR_DIM);
180 			DrawLineTo(out, sx, y1, x2, y2, COLOR_DIM);
181 			DrawLineTo(out, sx, sy, x1, y2, COLOR_DIM);
182 			DrawLineTo(out, sx, sy, x2, y2, COLOR_DIM);
183 		}
184 		if ((flags & (MAPFLAG_HORZDOOR | MAPFLAG_HORZGRATE | MAPFLAG_HORZARCH)) == 0)
185 			DrawLineTo(out, sx, sy - AmLine16, sx + AmLine32, sy, COLOR_DIM);
186 	}
187 
188 	// for caves the horz/vert flags are switched
189 	if (do_cave_horz) {
190 		if (flags & MAPFLAG_VERTDOOR) {
191 			x1 = sx - AmLine32;
192 			x2 = sx - AmLine16;
193 			y1 = sy + AmLine16;
194 			y2 = sy + AmLine8;
195 
196 			DrawLineTo(out, sx, y1, sx - AmLine8, y1 - AmLine4, COLOR_DIM);
197 			DrawLineTo(out, x1, sy, x1 + AmLine8, sy + AmLine4, COLOR_DIM);
198 			DrawLineTo(out, x2, y1, x1, y2, COLOR_BRIGHT);
199 			DrawLineTo(out, x2, y1, sx, y2, COLOR_BRIGHT);
200 			DrawLineTo(out, x2, sy, x1, y2, COLOR_BRIGHT);
201 			DrawLineTo(out, x2, sy, sx, y2, COLOR_BRIGHT);
202 		} else
203 			DrawLineTo(out, sx, sy + AmLine16, sx - AmLine32, sy, COLOR_DIM);
204 	}
205 
206 	if (do_cave_vert) {
207 		if (flags & MAPFLAG_HORZDOOR) {
208 			x1 = sx + AmLine16;
209 			x2 = sx + AmLine32;
210 			y1 = sy + AmLine16;
211 			y2 = sy + AmLine8;
212 
213 			DrawLineTo(out, sx, y1, sx + AmLine8, y1 - AmLine4, COLOR_DIM);
214 			DrawLineTo(out, x2, sy, x2 - AmLine8, sy + AmLine4, COLOR_DIM);
215 			DrawLineTo(out, x1, y1, sx, y2, COLOR_BRIGHT);
216 			DrawLineTo(out, x1, y1, x2, y2, COLOR_BRIGHT);
217 			DrawLineTo(out, x1, sy, sx, y2, COLOR_BRIGHT);
218 			DrawLineTo(out, x1, sy, x2, y2, COLOR_BRIGHT);
219 		} else {
220 			DrawLineTo(out, sx, sy + AmLine16, sx + AmLine32, sy, COLOR_DIM);
221 		}
222 	}
223 }
224 
DrawAutomapItem(CelOutputBuffer out,Sint32 x,Sint32 y,Uint8 color)225 void DrawAutomapItem(CelOutputBuffer out, Sint32 x, Sint32 y, Uint8 color)
226 {
227 	Sint32 x1 = x - AmLine32 / 2;
228 	Sint32 y1 = y - AmLine16 / 2;
229 	Sint32 x2 = x1 + AmLine64 / 2;
230 	Sint32 y2 = y1 + AmLine32 / 2;
231 	DrawLineTo(out, x, y1, x1, y, color);
232 	DrawLineTo(out, x, y1, x2, y, color);
233 	DrawLineTo(out, x, y2, x1, y, color);
234 	DrawLineTo(out, x, y2, x2, y, color);
235 }
236 
SearchAutomapItem(CelOutputBuffer out)237 void SearchAutomapItem(CelOutputBuffer out)
238 {
239 	Sint32 x = plr[myplr]._px;
240 	Sint32 y = plr[myplr]._py;
241 	if (plr[myplr]._pmode == PM_WALK3) {
242 		x = plr[myplr]._pfutx;
243 		y = plr[myplr]._pfuty;
244 		if (plr[myplr]._pdir == DIR_W)
245 			x++;
246 		else
247 			y++;
248 	}
249 
250 	Sint32 x1 = x - 8;
251 	if (x1 < 0)
252 		x1 = 0;
253 	else if (x1 > MAXDUNX)
254 		x1 = MAXDUNX;
255 
256 	Sint32 y1 = y - 8;
257 	if (y1 < 0)
258 		y1 = 0;
259 	else if (y1 > MAXDUNY)
260 		y1 = MAXDUNY;
261 
262 	Sint32 x2 = x + 8;
263 	if (x2 < 0)
264 		x2 = 0;
265 	else if (x2 > MAXDUNX)
266 		x2 = MAXDUNX;
267 
268 	Sint32 y2 = y + 8;
269 	if (y2 < 0)
270 		y2 = 0;
271 	else if (y2 > MAXDUNY)
272 		y2 = MAXDUNY;
273 
274 	for (Sint32 i = x1; i < x2; i++) {
275 		for (Sint32 j = y1; j < y2; j++) {
276 			if (dItem[i][j] != 0) {
277 				Sint32 px = i - 2 * AutoMapXOfs - ViewX;
278 				Sint32 py = j - 2 * AutoMapYOfs - ViewY;
279 
280 				x = (ScrollInfo._sxoff * AutoMapScale / 100 >> 1) + (px - py) * AmLine16 + gnScreenWidth / 2;
281 				y = (ScrollInfo._syoff * AutoMapScale / 100 >> 1) + (px + py) * AmLine8 + (gnScreenHeight - PANEL_HEIGHT) / 2;
282 
283 				if (PANELS_COVER) {
284 					if (invflag || sbookflag)
285 						x -= 160;
286 					if (chrflag || questlog)
287 						x += 160;
288 				}
289 				y -= AmLine8;
290 				DrawAutomapItem(out, x, y, COLOR_ITEM);
291 			}
292 		}
293 	}
294 }
295 
296 /**
297  * @brief Renders an arrow on the automap, centered on and facing the direction of the player.
298  */
DrawAutomapPlr(CelOutputBuffer out,int pnum)299 void DrawAutomapPlr(CelOutputBuffer out, int pnum)
300 {
301 	int px, py;
302 	int x, y;
303 	int playerColor;
304 
305 	playerColor = COLOR_PLAYER + (8 * pnum) % 128;
306 
307 	if (plr[pnum]._pmode == PM_WALK3) {
308 		x = plr[pnum]._pfutx;
309 		y = plr[pnum]._pfuty;
310 		if (plr[pnum]._pdir == DIR_W)
311 			x++;
312 		else
313 			y++;
314 	} else {
315 		x = plr[pnum]._px;
316 		y = plr[pnum]._py;
317 	}
318 	px = x - 2 * AutoMapXOfs - ViewX;
319 	py = y - 2 * AutoMapYOfs - ViewY;
320 
321 	x = (plr[pnum]._pxoff * AutoMapScale / 100 >> 1) + (ScrollInfo._sxoff * AutoMapScale / 100 >> 1) + (px - py) * AmLine16 + gnScreenWidth / 2;
322 	y = (plr[pnum]._pyoff * AutoMapScale / 100 >> 1) + (ScrollInfo._syoff * AutoMapScale / 100 >> 1) + (px + py) * AmLine8 + (gnScreenHeight - PANEL_HEIGHT) / 2;
323 
324 	if (PANELS_COVER) {
325 		if (invflag || sbookflag)
326 			x -= gnScreenWidth / 4;
327 		if (chrflag || questlog)
328 			x += gnScreenWidth / 4;
329 	}
330 	y -= AmLine8;
331 
332 	switch (plr[pnum]._pdir) {
333 	case DIR_N:
334 		DrawLineTo(out, x, y, x, y - AmLine16, playerColor);
335 		DrawLineTo(out, x, y - AmLine16, x - AmLine4, y - AmLine8, playerColor);
336 		DrawLineTo(out, x, y - AmLine16, x + AmLine4, y - AmLine8, playerColor);
337 		break;
338 	case DIR_NE:
339 		DrawLineTo(out, x, y, x + AmLine16, y - AmLine8, playerColor);
340 		DrawLineTo(out, x + AmLine16, y - AmLine8, x + AmLine8, y - AmLine8, playerColor);
341 		DrawLineTo(out, x + AmLine16, y - AmLine8, x + AmLine8 + AmLine4, y, playerColor);
342 		break;
343 	case DIR_E:
344 		DrawLineTo(out, x, y, x + AmLine16, y, playerColor);
345 		DrawLineTo(out, x + AmLine16, y, x + AmLine8, y - AmLine4, playerColor);
346 		DrawLineTo(out, x + AmLine16, y, x + AmLine8, y + AmLine4, playerColor);
347 		break;
348 	case DIR_SE:
349 		DrawLineTo(out, x, y, x + AmLine16, y + AmLine8, playerColor);
350 		DrawLineTo(out, x + AmLine16, y + AmLine8, x + AmLine8 + AmLine4, y, playerColor);
351 		DrawLineTo(out, x + AmLine16, y + AmLine8, x + AmLine8, y + AmLine8, playerColor);
352 		break;
353 	case DIR_S:
354 	case DIR_OMNI:
355 		DrawLineTo(out, x, y, x, y + AmLine16, playerColor);
356 		DrawLineTo(out, x, y + AmLine16, x + AmLine4, y + AmLine8, playerColor);
357 		DrawLineTo(out, x, y + AmLine16, x - AmLine4, y + AmLine8, playerColor);
358 		break;
359 	case DIR_SW:
360 		DrawLineTo(out, x, y, x - AmLine16, y + AmLine8, playerColor);
361 		DrawLineTo(out, x - AmLine16, y + AmLine8, x - AmLine4 - AmLine8, y, playerColor);
362 		DrawLineTo(out, x - AmLine16, y + AmLine8, x - AmLine8, y + AmLine8, playerColor);
363 		break;
364 	case DIR_W:
365 		DrawLineTo(out, x, y, x - AmLine16, y, playerColor);
366 		DrawLineTo(out, x - AmLine16, y, x - AmLine8, y - AmLine4, playerColor);
367 		DrawLineTo(out, x - AmLine16, y, x - AmLine8, y + AmLine4, playerColor);
368 		break;
369 	case DIR_NW:
370 		DrawLineTo(out, x, y, x - AmLine16, y - AmLine8, playerColor);
371 		DrawLineTo(out, x - AmLine16, y - AmLine8, x - AmLine8, y - AmLine8, playerColor);
372 		DrawLineTo(out, x - AmLine16, y - AmLine8, x - AmLine4 - AmLine8, y, playerColor);
373 		break;
374 	}
375 }
376 
377 /**
378  * @brief Returns the automap shape at the given coordinate.
379  */
GetAutomapType(int x,int y,BOOL view)380 WORD GetAutomapType(int x, int y, BOOL view)
381 {
382 	WORD rv;
383 
384 	if (view && x == -1 && y >= 0 && y < DMAXY && automapview[0][y]) {
385 		if (GetAutomapType(0, y, FALSE) & (MAPFLAG_DIRT << 8)) {
386 			return 0;
387 		} else {
388 			return MAPFLAG_DIRT << 8;
389 		}
390 	}
391 
392 	if (view && y == -1 && x >= 0 && x < DMAXY && automapview[x][0]) {
393 		if (GetAutomapType(x, 0, FALSE) & (MAPFLAG_DIRT << 8)) {
394 			return 0;
395 		} else {
396 			return MAPFLAG_DIRT << 8;
397 		}
398 	}
399 
400 	if (x < 0 || x >= DMAXX) {
401 		return 0;
402 	}
403 	if (y < 0 || y >= DMAXX) {
404 		return 0;
405 	}
406 	if (!automapview[x][y] && view) {
407 		return 0;
408 	}
409 
410 	rv = automaptype[(BYTE)dungeon[x][y]];
411 	if (rv == 7) {
412 		if ((GetAutomapType(x - 1, y, FALSE) >> 8) & MAPFLAG_HORZARCH) {
413 			if ((GetAutomapType(x, y - 1, FALSE) >> 8) & MAPFLAG_VERTARCH) {
414 				rv = 1;
415 			}
416 		}
417 	}
418 	return rv;
419 }
420 
421 /**
422  * @brief Renders game info, such as the name of the current level, and in multi player the name of the game and the game password.
423  */
DrawAutomapText(CelOutputBuffer out)424 void DrawAutomapText(CelOutputBuffer out)
425 {
426 	// TODO: Use the `out` buffer instead of the global one.
427 
428 	char desc[256];
429 	int nextline = 20;
430 
431 	if (gbIsMultiplayer) {
432 		strcat(strcpy(desc, "game: "), szPlayerName);
433 		PrintGameStr(out, 8, 20, desc, COL_GOLD);
434 		nextline = 35;
435 		if (szPlayerDescript[0]) {
436 			strcat(strcpy(desc, "password: "), szPlayerDescript);
437 			PrintGameStr(out, 8, 35, desc, COL_GOLD);
438 			nextline = 50;
439 		}
440 	}
441 	if (setlevel) {
442 		PrintGameStr(out, 8, nextline, quest_level_names[(BYTE)setlvlnum], COL_GOLD);
443 	} else if (currlevel != 0) {
444 		if (currlevel < 17 || currlevel > 20) {
445 			if (currlevel < 21 || currlevel > 24)
446 				sprintf(desc, "Level: %i", currlevel);
447 			else
448 				sprintf(desc, "Level: Crypt %i", currlevel - 20);
449 		} else {
450 			sprintf(desc, "Level: Nest %i", currlevel - 16);
451 		}
452 		PrintGameStr(out, 8, nextline, desc, COL_GOLD);
453 	}
454 }
455 
456 }
457 
458 bool automapflag;
459 bool automapview[DMAXX][DMAXY];
460 Sint32 AutoMapScale;
461 Sint32 AutoMapXOfs;
462 Sint32 AutoMapYOfs;
463 Sint32 AmLine64;
464 Sint32 AmLine32;
465 Sint32 AmLine16;
466 Sint32 AmLine8;
467 Sint32 AmLine4;
468 
InitAutomapOnce()469 void InitAutomapOnce()
470 {
471 	automapflag = FALSE;
472 	AutoMapScale = 50;
473 	AmLine64 = 32;
474 	AmLine32 = 16;
475 	AmLine16 = 8;
476 	AmLine8 = 4;
477 	AmLine4 = 2;
478 }
479 
InitAutomap()480 void InitAutomap()
481 {
482 	BYTE b1, b2;
483 	DWORD dwTiles;
484 	int x, y;
485 	BYTE *pAFile, *pTmp;
486 	DWORD i;
487 
488 	memset(automaptype, 0, sizeof(automaptype));
489 
490 	switch (leveltype) {
491 	case DTYPE_CATHEDRAL:
492 		if (currlevel < 21)
493 			pAFile = LoadFileInMem("Levels\\L1Data\\L1.AMP", &dwTiles);
494 		else
495 			pAFile = LoadFileInMem("NLevels\\L5Data\\L5.AMP", &dwTiles);
496 		break;
497 	case DTYPE_CATACOMBS:
498 		pAFile = LoadFileInMem("Levels\\L2Data\\L2.AMP", &dwTiles);
499 		break;
500 	case DTYPE_CAVES:
501 		if (currlevel < 17)
502 			pAFile = LoadFileInMem("Levels\\L3Data\\L3.AMP", &dwTiles);
503 		else
504 			pAFile = LoadFileInMem("NLevels\\L6Data\\L6.AMP", &dwTiles);
505 		break;
506 	case DTYPE_HELL:
507 		pAFile = LoadFileInMem("Levels\\L4Data\\L4.AMP", &dwTiles);
508 		break;
509 	default:
510 		return;
511 	}
512 
513 	dwTiles /= 2;
514 	pTmp = pAFile;
515 
516 	for (i = 1; i <= dwTiles; i++) {
517 		b1 = *pTmp++;
518 		b2 = *pTmp++;
519 		automaptype[i] = b1 + (b2 << 8);
520 	}
521 
522 	mem_free_dbg(pAFile);
523 	memset(automapview, 0, sizeof(automapview));
524 
525 	for (y = 0; y < MAXDUNY; y++) {
526 		for (x = 0; x < MAXDUNX; x++)
527 			dFlags[x][y] &= ~BFLAG_EXPLORED;
528 	}
529 }
530 
StartAutomap()531 void StartAutomap()
532 {
533 	AutoMapXOfs = 0;
534 	AutoMapYOfs = 0;
535 	automapflag = TRUE;
536 }
537 
AutomapUp()538 void AutomapUp()
539 {
540 	AutoMapXOfs--;
541 	AutoMapYOfs--;
542 }
543 
AutomapDown()544 void AutomapDown()
545 {
546 	AutoMapXOfs++;
547 	AutoMapYOfs++;
548 }
549 
AutomapLeft()550 void AutomapLeft()
551 {
552 	AutoMapXOfs--;
553 	AutoMapYOfs++;
554 }
555 
AutomapRight()556 void AutomapRight()
557 {
558 	AutoMapXOfs++;
559 	AutoMapYOfs--;
560 }
561 
AutomapZoomIn()562 void AutomapZoomIn()
563 {
564 	if (AutoMapScale < 200) {
565 		AutoMapScale += 5;
566 		AmLine64 = (AutoMapScale << 6) / 100;
567 		AmLine32 = AmLine64 >> 1;
568 		AmLine16 = AmLine32 >> 1;
569 		AmLine8 = AmLine16 >> 1;
570 		AmLine4 = AmLine8 >> 1;
571 	}
572 }
573 
AutomapZoomOut()574 void AutomapZoomOut()
575 {
576 	if (AutoMapScale > 50) {
577 		AutoMapScale -= 5;
578 		AmLine64 = (AutoMapScale << 6) / 100;
579 		AmLine32 = AmLine64 >> 1;
580 		AmLine16 = AmLine32 >> 1;
581 		AmLine8 = AmLine16 >> 1;
582 		AmLine4 = AmLine8 >> 1;
583 	}
584 }
585 
DrawAutomap(CelOutputBuffer out)586 void DrawAutomap(CelOutputBuffer out)
587 {
588 	int cells;
589 	int sx, sy;
590 	int i, j, d;
591 	int mapx, mapy;
592 
593 	if (leveltype == DTYPE_TOWN) {
594 		DrawAutomapText(out);
595 		return;
596 	}
597 
598 	AutoMapX = (ViewX - 16) >> 1;
599 	while (AutoMapX + AutoMapXOfs < 0)
600 		AutoMapXOfs++;
601 	while (AutoMapX + AutoMapXOfs >= DMAXX)
602 		AutoMapXOfs--;
603 	AutoMapX += AutoMapXOfs;
604 
605 	AutoMapY = (ViewY - 16) >> 1;
606 	while (AutoMapY + AutoMapYOfs < 0)
607 		AutoMapYOfs++;
608 	while (AutoMapY + AutoMapYOfs >= DMAXY)
609 		AutoMapYOfs--;
610 	AutoMapY += AutoMapYOfs;
611 
612 	d = (AutoMapScale << 6) / 100;
613 	cells = 2 * (gnScreenWidth / 2 / d) + 1;
614 	if ((gnScreenWidth / 2) % d)
615 		cells++;
616 	if ((gnScreenWidth / 2) % d >= (AutoMapScale << 5) / 100)
617 		cells++;
618 
619 	if (ScrollInfo._sxoff + ScrollInfo._syoff)
620 		cells++;
621 	mapx = AutoMapX - cells;
622 	mapy = AutoMapY - 1;
623 
624 	if (cells & 1) {
625 		sx = gnScreenWidth / 2 - AmLine64 * ((cells - 1) >> 1);
626 		sy = (gnScreenHeight - PANEL_HEIGHT) / 2 - AmLine32 * ((cells + 1) >> 1);
627 	} else {
628 		sx = gnScreenWidth / 2 - AmLine64 * (cells >> 1) + AmLine32;
629 		sy = (gnScreenHeight - PANEL_HEIGHT) / 2 - AmLine32 * (cells >> 1) - AmLine16;
630 	}
631 	if (ViewX & 1) {
632 		sx -= AmLine16;
633 		sy -= AmLine8;
634 	}
635 	if (ViewY & 1) {
636 		sx += AmLine16;
637 		sy -= AmLine8;
638 	}
639 
640 	sx += AutoMapScale * ScrollInfo._sxoff / 100 >> 1;
641 	sy += AutoMapScale * ScrollInfo._syoff / 100 >> 1;
642 	if (PANELS_COVER) {
643 		if (invflag || sbookflag) {
644 			sx -= gnScreenWidth / 4;
645 		}
646 		if (chrflag || questlog) {
647 			sx += gnScreenWidth / 4;
648 		}
649 	}
650 
651 	for (i = 0; i <= cells + 1; i++) {
652 		int x = sx;
653 		int y;
654 
655 		for (j = 0; j < cells; j++) {
656 			WORD maptype = GetAutomapType(mapx + j, mapy - j, TRUE);
657 			if (maptype != 0)
658 				DrawAutomapTile(out, x, sy, maptype);
659 			x += AmLine64;
660 		}
661 		mapy++;
662 		x = sx - AmLine32;
663 		y = sy + AmLine16;
664 		for (j = 0; j <= cells; j++) {
665 			WORD maptype = GetAutomapType(mapx + j, mapy - j, TRUE);
666 			if (maptype != 0)
667 				DrawAutomapTile(out, x, y, maptype);
668 			x += AmLine64;
669 		}
670 		mapx++;
671 		sy += AmLine32;
672 	}
673 
674 	for (int pnum = 0; pnum < MAX_PLRS; pnum++) {
675 		if (plr[pnum].plrlevel == plr[myplr].plrlevel && plr[pnum].plractive && !plr[pnum]._pLvlChanging) {
676 			DrawAutomapPlr(out, pnum);
677 		}
678 	}
679 	if (AutoMapShowItems)
680 		SearchAutomapItem(out);
681 	DrawAutomapText(out);
682 }
683 
SetAutomapView(Sint32 x,Sint32 y)684 void SetAutomapView(Sint32 x, Sint32 y)
685 {
686 	WORD maptype, solid;
687 	int xx, yy;
688 
689 	xx = (x - 16) >> 1;
690 	yy = (y - 16) >> 1;
691 
692 	if (xx < 0 || xx >= DMAXX || yy < 0 || yy >= DMAXY) {
693 		return;
694 	}
695 
696 	automapview[xx][yy] = TRUE;
697 
698 	maptype = GetAutomapType(xx, yy, FALSE);
699 	solid = maptype & 0x4000;
700 
701 	switch (maptype & MAPFLAG_TYPE) {
702 	case 2:
703 		if (solid) {
704 			if (GetAutomapType(xx, yy + 1, FALSE) == 0x4007)
705 				automapview[xx][yy + 1] = TRUE;
706 		} else if (GetAutomapType(xx - 1, yy, FALSE) & 0x4000) {
707 			automapview[xx - 1][yy] = TRUE;
708 		}
709 		break;
710 	case 3:
711 		if (solid) {
712 			if (GetAutomapType(xx + 1, yy, FALSE) == 0x4007)
713 				automapview[xx + 1][yy] = TRUE;
714 		} else if (GetAutomapType(xx, yy - 1, FALSE) & 0x4000) {
715 			automapview[xx][yy - 1] = TRUE;
716 		}
717 		break;
718 	case 4:
719 		if (solid) {
720 			if (GetAutomapType(xx, yy + 1, FALSE) == 0x4007)
721 				automapview[xx][yy + 1] = TRUE;
722 			if (GetAutomapType(xx + 1, yy, FALSE) == 0x4007)
723 				automapview[xx + 1][yy] = TRUE;
724 		} else {
725 			if (GetAutomapType(xx - 1, yy, FALSE) & 0x4000)
726 				automapview[xx - 1][yy] = TRUE;
727 			if (GetAutomapType(xx, yy - 1, FALSE) & 0x4000)
728 				automapview[xx][yy - 1] = TRUE;
729 			if (GetAutomapType(xx - 1, yy - 1, FALSE) & 0x4000)
730 				automapview[xx - 1][yy - 1] = TRUE;
731 		}
732 		break;
733 	case 5:
734 		if (solid) {
735 			if (GetAutomapType(xx, yy - 1, FALSE) & 0x4000)
736 				automapview[xx][yy - 1] = TRUE;
737 			if (GetAutomapType(xx, yy + 1, FALSE) == 0x4007)
738 				automapview[xx][yy + 1] = TRUE;
739 		} else if (GetAutomapType(xx - 1, yy, FALSE) & 0x4000) {
740 			automapview[xx - 1][yy] = TRUE;
741 		}
742 		break;
743 	case 6:
744 		if (solid) {
745 			if (GetAutomapType(xx - 1, yy, FALSE) & 0x4000)
746 				automapview[xx - 1][yy] = TRUE;
747 			if (GetAutomapType(xx + 1, yy, FALSE) == 0x4007)
748 				automapview[xx + 1][yy] = TRUE;
749 		} else if (GetAutomapType(xx, yy - 1, FALSE) & 0x4000) {
750 			automapview[xx][yy - 1] = TRUE;
751 		}
752 		break;
753 	}
754 }
755 
AutomapZoomReset()756 void AutomapZoomReset()
757 {
758 	AutoMapXOfs = 0;
759 	AutoMapYOfs = 0;
760 	AmLine64 = (AutoMapScale << 6) / 100;
761 	AmLine32 = AmLine64 >> 1;
762 	AmLine16 = AmLine32 >> 1;
763 	AmLine8 = AmLine16 >> 1;
764 	AmLine4 = AmLine8 >> 1;
765 }
766 
767 DEVILUTION_END_NAMESPACE
768