1 // Emacs style mode select   -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: am_map.cpp 4542 2014-02-09 17:39:42Z dr_sean $
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 // Copyright (C) 2006-2014 by The Odamex Team.
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 // GNU General Public License for more details.
18 //
19 // DESCRIPTION:
20 //  AutoMap module.
21 //
22 //-----------------------------------------------------------------------------
23 
24 
25 #include <stdio.h>
26 
27 #include "doomdef.h"
28 #include "g_level.h"
29 #include "z_zone.h"
30 #include "doomdef.h"
31 #include "st_stuff.h"
32 #include "p_local.h"
33 #include "p_lnspec.h"
34 #include "w_wad.h"
35 #include "v_palette.h"
36 
37 #include "m_cheat.h"
38 #include "i_system.h"
39 #include "c_dispatch.h"
40 #include "p_ctf.h"
41 #include "cl_demo.h"
42 
43 // Needs access to LFB.
44 #include "v_video.h"
45 
46 #include "v_text.h"
47 
48 extern patch_t *hu_font[];
49 
50 // State.
51 #include "doomstat.h"
52 #include "r_state.h"
53 
54 // Data.
55 #include "gstrings.h"
56 
57 #include "am_map.h"
58 
59 int CL_GetPlayerColor(player_t*);
60 
61 // Group palette index and RGB value together:
62 typedef struct am_color_s {
63 	palindex_t  index;
64 	argb_t      rgb;
65 } am_color_t;
66 
67 static am_color_t
68 	Background, YourColor, WallColor, TSWallColor,
69 		   FDWallColor, CDWallColor, ThingColor,
70 		   SecretWallColor, GridColor, XHairColor,
71 		   NotSeenColor,
72 		   LockedColor,
73 		   AlmostBackground,
74 		   TeleportColor, ExitColor;
75 
76 static int lockglow = 0;
77 
78 EXTERN_CVAR (am_rotate)
EXTERN_CVAR(am_overlay)79 EXTERN_CVAR (am_overlay)
80 EXTERN_CVAR (am_showsecrets)
81 EXTERN_CVAR (am_showmonsters)
82 EXTERN_CVAR (am_showtime)
83 EXTERN_CVAR (am_classicmapstring)
84 EXTERN_CVAR (am_usecustomcolors)
85 EXTERN_CVAR (am_ovshare)
86 
87 EXTERN_CVAR (am_backcolor)
88 EXTERN_CVAR (am_yourcolor)
89 EXTERN_CVAR (am_wallcolor)
90 EXTERN_CVAR (am_tswallcolor)
91 EXTERN_CVAR (am_fdwallcolor)
92 EXTERN_CVAR (am_cdwallcolor)
93 EXTERN_CVAR (am_thingcolor)
94 EXTERN_CVAR (am_gridcolor)
95 EXTERN_CVAR (am_xhaircolor)
96 EXTERN_CVAR (am_notseencolor)
97 EXTERN_CVAR (am_lockedcolor)
98 EXTERN_CVAR (am_exitcolor)
99 EXTERN_CVAR (am_teleportcolor)
100 
101 EXTERN_CVAR (am_ovyourcolor)
102 EXTERN_CVAR (am_ovwallcolor)
103 EXTERN_CVAR (am_ovtswallcolor)
104 EXTERN_CVAR (am_ovfdwallcolor)
105 EXTERN_CVAR (am_ovcdwallcolor)
106 EXTERN_CVAR (am_ovthingcolor)
107 EXTERN_CVAR (am_ovgridcolor)
108 EXTERN_CVAR (am_ovxhaircolor)
109 EXTERN_CVAR (am_ovnotseencolor)
110 EXTERN_CVAR (am_ovlockedcolor)
111 EXTERN_CVAR (am_ovexitcolor)
112 EXTERN_CVAR (am_ovteleportcolor)
113 
114 BEGIN_COMMAND (resetcustomcolors)
115 {
116     am_backcolor = "00 00 3a";
117     am_yourcolor = "fc e8 d8";
118     am_wallcolor = "00 8b ff";
119     am_tswallcolor = "10 32 7e";
120     am_fdwallcolor = "1a 1a 8a";
121     am_cdwallcolor = "00 00 5a";
122     am_thingcolor = "9f d3 ff";
123     am_gridcolor = "44 44 88";
124     am_xhaircolor = "80 80 80";
125     am_notseencolor = "00 22 6e";
126     am_lockedcolor = "bb bb bb";
127     am_exitcolor = "ff ff 00";
128     am_teleportcolor = "ff a3 00";
129 
130     am_ovyourcolor = "fc e8 d8";
131     am_ovwallcolor = "00 8b ff";
132     am_ovtswallcolor = "10 32 7e";
133     am_ovfdwallcolor = "1a 1a 8a";
134     am_ovcdwallcolor = "00 00 5a";
135     am_ovthingcolor = "9f d3 ff";
136     am_ovgridcolor = "44 44 88";
137     am_ovxhaircolor = "80 80 80";
138     am_ovnotseencolor = "00 22 6e";
139     am_ovlockedcolor = "bb bb bb";
140     am_ovexitcolor = "ff ff 00";
141     am_ovteleportcolor = "ff a3 00";
142     Printf (PRINT_HIGH, "Custom automap colors reset to default.\n");
143 }
144 END_COMMAND (resetcustomcolors)
145 
146 EXTERN_CVAR		(screenblocks)
147 
148 // drawing stuff
149 #define	FB		(screen)
150 
151 #define AM_PANDOWNKEY	KEY_DOWNARROW
152 #define AM_PANUPKEY		KEY_UPARROW
153 #define AM_PANRIGHTKEY	KEY_RIGHTARROW
154 #define AM_PANLEFTKEY	KEY_LEFTARROW
155 #define AM_ZOOMINKEY	KEY_EQUALS
156 #define AM_ZOOMINKEY2	0x4e	// DIK_ADD
157 #define AM_ZOOMOUTKEY	KEY_MINUS
158 #define AM_ZOOMOUTKEY2	0x4a	// DIK_SUBTRACT
159 #define AM_GOBIGKEY		0x0b	// DIK_0
160 #define AM_FOLLOWKEY	'f'
161 #define AM_GRIDKEY		'g'
162 #define AM_MARKKEY		'm'
163 #define AM_CLEARMARKKEY	'c'
164 
165 #define AM_NUMMARKPOINTS 10
166 
167 // scale on entry
168 #define INITSCALEMTOF (.2*FRACUNIT)
169 // how much the automap moves window per tic in frame-buffer coordinates
170 // moves 140 pixels in 1 second
171 #define F_PANINC	(140/TICRATE)
172 // how much zoom-in per tic
173 // goes to 2x in 1 second
174 #define M_ZOOMIN        ((int) (1.02*FRACUNIT))
175 // how much zoom-out per tic
176 // pulls out to 0.5x in 1 second
177 #define M_ZOOMOUT       ((int) (FRACUNIT/1.02))
178 
179 // translates between frame-buffer and map distances
180 #define FTOM(x) FixedMul(((x)<<16),scale_ftom)
181 #define MTOF(x) (FixedMul((x),scale_mtof)>>16)
182 // translates between frame-buffer and map coordinates
183 #define CXMTOF(x)  (MTOF((x)-m_x)/* - f_x*/)
184 #define CYMTOF(y)  (f_h - MTOF((y)-m_y)/* + f_y*/)
185 
186 #define PUTDOTP(xx,yy,cc) fb[(yy)*f_p+(xx)]=(cc)
187 #define PUTDOTD(xx,yy,cc) *((argb_t *)(fb+(yy)*f_p+((xx)<<2)))=(cc)
188 
189 typedef struct {
190 	int x, y;
191 } fpoint_t;
192 
193 typedef struct {
194 	fpoint_t a, b;
195 } fline_t;
196 
197 typedef struct {
198 	fixed_t x,y;
199 } mpoint_t;
200 
201 typedef struct {
202 	mpoint_t a, b;
203 } mline_t;
204 
205 typedef struct {
206 	fixed_t slp, islp;
207 } islope_t;
208 
209 
210 
211 //
212 // The vector graphics for the automap.
213 //  A line drawing of the player pointing right,
214 //   starting from the middle.
215 //
216 #define R ((8*PLAYERRADIUS)/7)
217 mline_t player_arrow[] = {
218 	{ { -R+R/8, 0 }, { R, 0 } }, // -----
219 	{ { R, 0 }, { R-R/2, R/4 } },  // ----->
220 	{ { R, 0 }, { R-R/2, -R/4 } },
221 	{ { -R+R/8, 0 }, { -R-R/8, R/4 } }, // >---->
222 	{ { -R+R/8, 0 }, { -R-R/8, -R/4 } },
223 	{ { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>--->
224 	{ { -R+3*R/8, 0 }, { -R+R/8, -R/4 } }
225 };
226 #undef R
227 #define NUMPLYRLINES (sizeof(player_arrow)/sizeof(mline_t))
228 
229 #define R ((8*PLAYERRADIUS)/7)
230 mline_t cheat_player_arrow[] = {
231 	{ { -R+R/8, 0 }, { R, 0 } }, // -----
232 	{ { R, 0 }, { R-R/2, R/6 } },  // ----->
233 	{ { R, 0 }, { R-R/2, -R/6 } },
234 	{ { -R+R/8, 0 }, { -R-R/8, R/6 } }, // >----->
235 	{ { -R+R/8, 0 }, { -R-R/8, -R/6 } },
236 	{ { -R+3*R/8, 0 }, { -R+R/8, R/6 } }, // >>----->
237 	{ { -R+3*R/8, 0 }, { -R+R/8, -R/6 } },
238 	{ { -R/2, 0 }, { -R/2, -R/6 } }, // >>-d--->
239 	{ { -R/2, -R/6 }, { -R/2+R/6, -R/6 } },
240 	{ { -R/2+R/6, -R/6 }, { -R/2+R/6, R/4 } },
241 	{ { -R/6, 0 }, { -R/6, -R/6 } }, // >>-dd-->
242 	{ { -R/6, -R/6 }, { 0, -R/6 } },
243 	{ { 0, -R/6 }, { 0, R/4 } },
244 	{ { R/6, R/4 }, { R/6, -R/7 } }, // >>-ddt->
245 	{ { R/6, -R/7 }, { R/6+R/32, -R/7-R/32 } },
246 	{ { R/6+R/32, -R/7-R/32 }, { R/6+R/10, -R/7 } }
247 };
248 #undef R
249 #define NUMCHEATPLYRLINES (sizeof(cheat_player_arrow)/sizeof(mline_t))
250 
251 #define R (FRACUNIT)
252 // [RH] Avoid lots of warnings without compiler-specific #pragmas
253 #define L(a,b,c,d) { {(fixed_t)((a)*R),(fixed_t)((b)*R)}, {(fixed_t)((c)*R),(fixed_t)((d)*R)} }
254 mline_t triangle_guy[] = {
255 	L (-.867,-.5, .867,-.5),
256 	L (.867,-.5, 0,1),
257 	L (0,1, -.867,-.5)
258 };
259 #define NUMTRIANGLEGUYLINES (sizeof(triangle_guy)/sizeof(mline_t))
260 
261 mline_t thintriangle_guy[] = {
262 	L (-.5,-.7, 1,0),
263 	L (1,0, -.5,.7),
264 	L (-.5,.7, -.5,-.7)
265 };
266 #undef L
267 #undef R
268 #define NUMTHINTRIANGLEGUYLINES (sizeof(thintriangle_guy)/sizeof(mline_t))
269 
270 
271 
272 
273 static int 	cheating = 0;
274 static int 	grid = 0;
275 
276 static int 	leveljuststarted = 1; 	// kluge until AM_LevelInit() is called
277 
278 BOOL		automapactive = false;
279 
280 // location of window on screen
281 static int	f_x;
282 static int	f_y;
283 
284 // size of window on screen
285 static int	f_w;
286 static int	f_h;
287 static int	f_p;				// [RH] # of bytes from start of a line to start of next
288 
289 static byte *fb;				// pseudo-frame buffer
290 static int	amclock;
291 
292 static mpoint_t	m_paninc;		// how far the window pans each tic (map coords)
293 static fixed_t	mtof_zoommul;	// how far the window zooms in each tic (map coords)
294 static fixed_t	ftom_zoommul;	// how far the window zooms in each tic (fb coords)
295 
296 static fixed_t	m_x, m_y;		// LL x,y where the window is on the map (map coords)
297 static fixed_t	m_x2, m_y2;		// UR x,y where the window is on the map (map coords)
298 
299 //
300 // width/height of window on map (map coords)
301 //
302 static fixed_t	m_w;
303 static fixed_t	m_h;
304 
305 // based on level size
306 static fixed_t	min_x;
307 static fixed_t	min_y;
308 static fixed_t	max_x;
309 static fixed_t	max_y;
310 
311 static fixed_t	max_w; // max_x-min_x,
312 static fixed_t	max_h; // max_y-min_y
313 
314 // based on player size
315 static fixed_t	min_w;
316 static fixed_t	min_h;
317 
318 
319 static fixed_t	min_scale_mtof; // used to tell when to stop zooming out
320 static fixed_t	max_scale_mtof; // used to tell when to stop zooming in
321 
322 // old stuff for recovery later
323 static fixed_t old_m_w, old_m_h;
324 static fixed_t old_m_x, old_m_y;
325 
326 // old location used by the Follower routine
327 static mpoint_t f_oldloc;
328 
329 // used by MTOF to scale from map-to-frame-buffer coords
330 static fixed_t scale_mtof = (fixed_t)INITSCALEMTOF;
331 // used by FTOM to scale from frame-buffer-to-map coords (=1/scale_mtof)
332 static fixed_t scale_ftom;
333 
334 static patch_t *marknums[10]; // numbers used for marking by the automap
335 static mpoint_t markpoints[AM_NUMMARKPOINTS]; // where the points are
336 static int markpointnum = 0; // next point to be assigned
337 
338 static bool followplayer = true; // specifies whether to follow the player around
339 
340 // [RH] Not static so that the DeHackEd code can reach it.
341 extern byte cheat_amap_seq[5];
342 cheatseq_t cheat_amap = { cheat_amap_seq, 0 };
343 
344 static BOOL stopped = true;
345 
346 extern NetDemo netdemo;
347 
348 #define NUMALIASES		3
349 #define WALLCOLORS		-1
350 #define FDWALLCOLORS	-2
351 #define CDWALLCOLORS	-3
352 
353 #define WEIGHTBITS		6
354 #define WEIGHTSHIFT		(FRACBITS-WEIGHTBITS)
355 #define NUMWEIGHTS		(1<<WEIGHTBITS)
356 #define WEIGHTMASK		(NUMWEIGHTS-1)
357 
358 
359 void AM_rotatePoint (fixed_t *x, fixed_t *y);
360 
361 //
362 //
363 //
AM_activateNewScale(void)364 void AM_activateNewScale(void)
365 {
366 	m_x += m_w/2;
367 	m_y += m_h/2;
368 	m_w = FTOM(f_w);
369 	m_h = FTOM(f_h);
370 	m_x -= m_w/2;
371 	m_y -= m_h/2;
372 	m_x2 = m_x + m_w;
373 	m_y2 = m_y + m_h;
374 }
375 
376 //
377 //
378 //
AM_saveScaleAndLoc(void)379 void AM_saveScaleAndLoc(void)
380 {
381 	old_m_x = m_x;
382 	old_m_y = m_y;
383 	old_m_w = m_w;
384 	old_m_h = m_h;
385 }
386 
387 //
388 //
389 //
AM_restoreScaleAndLoc(void)390 void AM_restoreScaleAndLoc(void)
391 {
392 	m_w = old_m_w;
393 	m_h = old_m_h;
394 	if (!followplayer)
395 	{
396 		m_x = old_m_x;
397 		m_y = old_m_y;
398     }
399 	else
400 	{
401 		m_x = displayplayer().camera->x - m_w/2;
402 		m_y = displayplayer().camera->y - m_h/2;
403     }
404 	m_x2 = m_x + m_w;
405 	m_y2 = m_y + m_h;
406 
407 	// Change the scaling multipliers
408 	scale_mtof = FixedDiv(f_w<<FRACBITS, m_w);
409 	scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
410 }
411 
412 //
413 // adds a marker at the current location
414 //
AM_addMark(void)415 void AM_addMark(void)
416 {
417 	markpoints[markpointnum].x = m_x + m_w/2;
418 	markpoints[markpointnum].y = m_y + m_h/2;
419 	markpointnum = (markpointnum + 1) % AM_NUMMARKPOINTS;
420 }
421 
422 //
423 // Determines bounding box of all vertices,
424 // sets global variables controlling zoom range.
425 //
AM_findMinMaxBoundaries(void)426 void AM_findMinMaxBoundaries(void)
427 {
428 	int i;
429 	fixed_t a;
430 	fixed_t b;
431 
432 	min_x = min_y =  MAXINT;
433 	max_x = max_y = -MAXINT;
434 
435 	for (i=0;i<numvertexes;i++) {
436 		if (vertexes[i].x < min_x)
437 			min_x = vertexes[i].x;
438 		else if (vertexes[i].x > max_x)
439 			max_x = vertexes[i].x;
440 
441 		if (vertexes[i].y < min_y)
442 			min_y = vertexes[i].y;
443 		else if (vertexes[i].y > max_y)
444 			max_y = vertexes[i].y;
445 	}
446 
447 	max_w = max_x - min_x;
448 	max_h = max_y - min_y;
449 
450 	min_w = 2*PLAYERRADIUS; // const? never changed?
451 	min_h = 2*PLAYERRADIUS;
452 
453 	a = FixedDiv((screen->width)<<FRACBITS, max_w);
454 	b = FixedDiv((screen->height)<<FRACBITS, max_h);
455 
456 	min_scale_mtof = a < b ? a : b;
457 	max_scale_mtof = FixedDiv((screen->height)<<FRACBITS, 2*PLAYERRADIUS);
458 }
459 
460 
461 //
462 //
463 //
AM_changeWindowLoc(void)464 void AM_changeWindowLoc(void)
465 {
466 	if (m_paninc.x || m_paninc.y) {
467 		followplayer = 0;
468 		f_oldloc.x = MAXINT;
469 	}
470 
471 	m_x += m_paninc.x;
472 	m_y += m_paninc.y;
473 
474 	if (m_x + m_w/2 > max_x)
475 		m_x = max_x - m_w/2;
476 	else if (m_x + m_w/2 < min_x)
477 		m_x = min_x - m_w/2;
478 
479 	if (m_y + m_h/2 > max_y)
480 		m_y = max_y - m_h/2;
481 	else if (m_y + m_h/2 < min_y)
482 		m_y = min_y - m_h/2;
483 
484 	m_x2 = m_x + m_w;
485 	m_y2 = m_y + m_h;
486 }
487 
488 
489 //
490 //
491 //
AM_initVariables(void)492 void AM_initVariables(void)
493 {
494 	static event_t st_notify = { ev_keyup, AM_MSGENTERED, 0, 0 };
495 
496 	automapactive = true;
497 
498 	f_oldloc.x = MAXINT;
499 	amclock = 0;
500 
501 	m_paninc.x = m_paninc.y = 0;
502 	ftom_zoommul = FRACUNIT;
503 	mtof_zoommul = FRACUNIT;
504 
505 	m_w = FTOM(screen->width);
506 	m_h = FTOM(screen->height);
507 
508 	// find player to center on initially
509 	player_t *pl = &displayplayer();
510 	if (!pl->ingame())
511 	{
512 		for (Players::iterator it = players.begin();it != players.end();++it)
513 		{
514 			if (it->ingame())
515 			{
516 				pl = &*it;
517 				break;
518 			}
519 		}
520 	}
521 
522 	if(!pl->camera)
523 		return;
524 
525 	m_x = pl->camera->x - m_w/2;
526 	m_y = pl->camera->y - m_h/2;
527 	AM_changeWindowLoc();
528 
529 	// for saving & restoring
530 	old_m_x = m_x;
531 	old_m_y = m_y;
532 	old_m_w = m_w;
533 	old_m_h = m_h;
534 
535 	// inform the status bar of the change
536 	ST_Responder (&st_notify);
537 }
538 
539 
AM_GetColorFromString(argb_t * palette,const char * colorstring)540 am_color_t AM_GetColorFromString(argb_t *palette, const char *colorstring)
541 {
542 	am_color_t c;
543 	c.rgb = (argb_t) V_GetColorFromString(NULL, colorstring);
544 	c.index = BestColor2(palette, c.rgb, 256);
545 	return c;
546 }
547 
AM_BestColor(argb_t * palette,const int r,const int g,const int b,const int numcolors)548 am_color_t AM_BestColor(argb_t *palette, const int r, const int g, const int b, const int numcolors)
549 {
550 	am_color_t c;
551 	c.rgb = MAKERGB(r,g,b);
552 	c.index = BestColor2(palette, c.rgb, 256);
553 	return c;
554 }
555 
AM_initColors(BOOL overlayed)556 void AM_initColors (BOOL overlayed)
557 {
558 	// Look up the colors in the current palette:
559 	argb_t *palette = GetDefaultPalette()->colors;
560 
561 	if (overlayed && !am_ovshare)
562 	{
563 		YourColor = AM_GetColorFromString (palette, am_ovyourcolor.cstring());
564 		SecretWallColor =
565 			WallColor= AM_GetColorFromString (palette, am_ovwallcolor.cstring());
566 		TSWallColor = AM_GetColorFromString (palette, am_ovtswallcolor.cstring());
567 		FDWallColor = AM_GetColorFromString (palette, am_ovfdwallcolor.cstring());
568 		CDWallColor = AM_GetColorFromString (palette, am_ovcdwallcolor.cstring());
569 		ThingColor = AM_GetColorFromString (palette, am_ovthingcolor.cstring());
570 		GridColor = AM_GetColorFromString (palette, am_ovgridcolor.cstring());
571 		XHairColor = AM_GetColorFromString (palette, am_ovxhaircolor.cstring());
572 		NotSeenColor = AM_GetColorFromString (palette, am_ovnotseencolor.cstring());
573 		LockedColor = AM_GetColorFromString (palette, am_ovlockedcolor.cstring());
574 		ExitColor = AM_GetColorFromString (palette, am_ovexitcolor.cstring());
575 		TeleportColor = AM_GetColorFromString (palette, am_ovteleportcolor.cstring());
576 	}
577 	else if (am_usecustomcolors || (overlayed && am_ovshare))
578 	{
579 		/* Use the custom colors in the am_* cvars */
580 		Background = AM_GetColorFromString(palette, am_backcolor.cstring());
581 		YourColor = AM_GetColorFromString(palette, am_yourcolor.cstring());
582 		SecretWallColor =
583 			WallColor = AM_GetColorFromString(palette, am_wallcolor.cstring());
584 		TSWallColor = AM_GetColorFromString(palette, am_tswallcolor.cstring());
585 		FDWallColor = AM_GetColorFromString(palette, am_fdwallcolor.cstring());
586 		CDWallColor = AM_GetColorFromString(palette, am_cdwallcolor.cstring());
587 		ThingColor = AM_GetColorFromString(palette, am_thingcolor.cstring());
588 		GridColor = AM_GetColorFromString(palette, am_gridcolor.cstring());
589 		XHairColor = AM_GetColorFromString(palette, am_xhaircolor.cstring());
590 		NotSeenColor = AM_GetColorFromString(palette, am_notseencolor.cstring());
591 		LockedColor = AM_GetColorFromString(palette, am_lockedcolor.cstring());
592 		ExitColor = AM_GetColorFromString(palette, am_exitcolor.cstring());
593 		TeleportColor = AM_GetColorFromString(palette, am_teleportcolor.cstring());
594 		{
595 			argb_t ba = AM_GetColorFromString(palette, am_backcolor.cstring()).rgb;
596 			int r = RPART(ba) - 16;
597 			int g = GPART(ba) - 16;
598 			int b = BPART(ba) - 16;
599 			if (r < 0) r += 32;
600 			if (g < 0) g += 32;
601 			if (b < 0) b += 32;
602 			AlmostBackground.rgb = MAKERGB(r,g,b);
603 			AlmostBackground.index = BestColor2(palette, AlmostBackground.rgb, 256);
604 		}
605 	}
606 	else
607 	{
608 		/* Use colors corresponding to the original Doom's */
609 		Background = AM_GetColorFromString(palette, "00 00 00");
610 		YourColor = AM_GetColorFromString(palette, "FF FF FF");
611 		AlmostBackground = AM_GetColorFromString(palette, "10 10 10");
612 		SecretWallColor =
613 			WallColor = AM_GetColorFromString(palette, "fc 00 00");
614 		TSWallColor = AM_GetColorFromString(palette, "80 80 80");
615 		FDWallColor = AM_GetColorFromString(palette, "bc 78 48");
616 		LockedColor = AM_GetColorFromString(palette, "fc fc 00");
617 		CDWallColor = AM_GetColorFromString(palette, "fc fc 00");
618 		ThingColor = AM_GetColorFromString(palette, "74 fc 6c");
619 		GridColor = AM_GetColorFromString(palette, "4c 4c 4c");
620 		XHairColor = AM_GetColorFromString(palette, "80 80 80");
621 		NotSeenColor = AM_GetColorFromString(palette, "6c 6c 6c");
622 	}
623 }
624 
625 //
626 //
627 //
AM_loadPics(void)628 void AM_loadPics(void)
629 {
630 	int i;
631 	char namebuf[9];
632 
633 	for (i = 0; i < 10; i++)
634 	{
635 		sprintf(namebuf, "AMMNUM%d", i);
636 		marknums[i] = W_CachePatch (namebuf, PU_STATIC);
637 	}
638 }
639 
AM_unloadPics(void)640 void AM_unloadPics(void)
641 {
642 	int i;
643 
644 	for (i = 0; i < 10; i++)
645 	{
646 		if (marknums[i])
647 		{
648 			Z_ChangeTag (marknums[i], PU_CACHE);
649 			marknums[i] = NULL;
650 		}
651 	}
652 }
653 
AM_clearMarks(void)654 void AM_clearMarks(void)
655 {
656 	int i;
657 
658 	for (i = AM_NUMMARKPOINTS-1; i >= 0; i--)
659 		markpoints[i].x = -1; // means empty
660 	markpointnum = 0;
661 }
662 
663 //
664 // should be called at the start of every level
665 // right now, i figure it out myself
666 //
AM_LevelInit(void)667 void AM_LevelInit(void)
668 {
669 	leveljuststarted = 0;
670 
671 	AM_clearMarks();
672 
673 	AM_findMinMaxBoundaries();
674 	scale_mtof = FixedDiv(min_scale_mtof, (int) (0.7*FRACUNIT));
675 	if (scale_mtof > max_scale_mtof)
676 		scale_mtof = min_scale_mtof;
677 	scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
678 }
679 
680 
681 
682 
683 //
684 //
685 //
AM_Stop(void)686 void AM_Stop (void)
687 {
688 	static event_t st_notify = { ev_keyup, AM_MSGEXITED, 0, 0 };
689 
690     if (!automapactive)
691     {
692         return;
693     }
694 
695 	AM_unloadPics ();
696 	automapactive = false;
697 	ST_Responder (&st_notify);
698 	stopped = true;
699 	viewactive = true;
700 }
701 
702 //
703 //
704 //
AM_Start(void)705 void AM_Start (void)
706 {
707 	static char lastmap[8] = "";
708 
709 	if (!stopped) AM_Stop();
710 	stopped = false;
711 	if (strncmp (lastmap, level.mapname, 8))
712 	{
713 		AM_LevelInit();
714 		strncpy (lastmap, level.mapname, 8);
715 	}
716 	AM_initVariables();
717 	AM_loadPics();
718 }
719 
720 //
721 // set the window scale to the maximum size
722 //
AM_minOutWindowScale(void)723 void AM_minOutWindowScale(void)
724 {
725 	scale_mtof = min_scale_mtof;
726 	scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
727 }
728 
729 //
730 // set the window scale to the minimum size
731 //
AM_maxOutWindowScale(void)732 void AM_maxOutWindowScale(void)
733 {
734 	scale_mtof = max_scale_mtof;
735 	scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
736 }
737 
738 
BEGIN_COMMAND(togglemap)739 BEGIN_COMMAND (togglemap)
740 {
741 	if (gamestate != GS_LEVEL)
742 		return;
743 
744 	if (!automapactive)
745 	{
746 		AM_Start ();
747 		if (am_overlay)
748 			viewactive = true;
749 		else
750 			viewactive = false;
751 	}
752 	else
753 	{
754 		if (am_overlay > 0 && am_overlay < 3 && viewactive)
755 		{
756 			viewactive = false;
757 		}
758 		else
759 		{
760 			AM_Stop ();
761 		}
762 	}
763 
764 	if (automapactive)
765 		AM_initColors (viewactive);
766 }
END_COMMAND(togglemap)767 END_COMMAND (togglemap)
768 
769 //
770 // Handle events (user inputs) in automap mode
771 //
772 BOOL AM_Responder (event_t *ev)
773 {
774 	int rc;
775 	static int bigstate = 0;
776 
777 	rc = false;
778 
779 	if (automapactive && ev->type == ev_keydown)
780 	{
781 		rc = true;
782 		switch(ev->data1)
783 		{
784 		case AM_PANRIGHTKEY: // pan right
785 			if (!followplayer)
786 				m_paninc.x = FTOM(F_PANINC);
787 			else
788 				rc = false;
789 			break;
790 		case AM_PANLEFTKEY: // pan left
791 			if (!followplayer)
792 				m_paninc.x = -FTOM(F_PANINC);
793 			else
794 				rc = false;
795 			break;
796 		case AM_PANUPKEY: // pan up
797 			if (!followplayer)
798 				m_paninc.y = FTOM(F_PANINC);
799 			else
800 				rc = false;
801 			break;
802 		case AM_PANDOWNKEY: // pan down
803 			if (!followplayer)
804 				m_paninc.y = -FTOM(F_PANINC);
805 			else
806 				rc = false;
807 			break;
808 		case AM_ZOOMOUTKEY: // zoom out
809 		case AM_ZOOMOUTKEY2:
810 			mtof_zoommul = M_ZOOMOUT;
811 			ftom_zoommul = M_ZOOMIN;
812 			break;
813 		case AM_ZOOMINKEY: // zoom in
814 		case AM_ZOOMINKEY2:
815 			mtof_zoommul = M_ZOOMIN;
816 			ftom_zoommul = M_ZOOMOUT;
817 			break;
818 		case AM_GOBIGKEY:
819 			bigstate = !bigstate;
820 			if (bigstate)
821 			{
822 				AM_saveScaleAndLoc();
823 				AM_minOutWindowScale();
824 			}
825 			else
826 				AM_restoreScaleAndLoc();
827 			break;
828 		default:
829 			switch (ev->data2)
830 			{
831 			case AM_FOLLOWKEY:
832 				followplayer = !followplayer;
833 				f_oldloc.x = MAXINT;
834 				Printf (PRINT_HIGH, "%s\n", followplayer ? GStrings(AMSTR_FOLLOWON) : GStrings(AMSTR_FOLLOWOFF));
835 				break;
836 			case AM_GRIDKEY:
837 				grid = !grid;
838 				Printf (PRINT_HIGH, "%s\n", grid ? GStrings(AMSTR_GRIDON) : GStrings(AMSTR_GRIDOFF));
839 				break;
840 			case AM_MARKKEY:
841 				Printf (PRINT_HIGH, "%s %d\n",  GStrings(AMSTR_MARKEDSPOT), markpointnum);
842 				AM_addMark();
843 				break;
844 			case AM_CLEARMARKKEY:
845 				AM_clearMarks();
846 				Printf (PRINT_HIGH, "%s\n", GStrings(AMSTR_MARKSCLEARED));
847 				break;
848 			default:
849 				rc = false;
850 			}
851 		}
852 		if (sv_gametype == GM_COOP && cht_CheckCheat(&cheat_amap, (char)ev->data2))
853 		{
854 			rc = true;	// [RH] Eat last keypress of cheat sequence
855 			cheating = (cheating+1) % 3;
856 		}
857 	}
858 	else if (ev->type == ev_keyup)
859 	{
860 		rc = false;
861 		switch (ev->data1)
862 		{
863 		case AM_PANRIGHTKEY:
864 			if (!followplayer) m_paninc.x = 0;
865 			break;
866 		case AM_PANLEFTKEY:
867 			if (!followplayer) m_paninc.x = 0;
868 			break;
869 		case AM_PANUPKEY:
870 			if (!followplayer) m_paninc.y = 0;
871 			break;
872 		case AM_PANDOWNKEY:
873 			if (!followplayer) m_paninc.y = 0;
874 			break;
875 		case AM_ZOOMOUTKEY:
876 		case AM_ZOOMOUTKEY2:
877 		case AM_ZOOMINKEY:
878 		case AM_ZOOMINKEY2:
879 			mtof_zoommul = FRACUNIT;
880 			ftom_zoommul = FRACUNIT;
881 			break;
882 		}
883 	}
884 
885 	return rc;
886 }
887 
888 
889 //
890 // Zooming
891 //
AM_changeWindowScale(void)892 void AM_changeWindowScale (void)
893 {
894 	// Change the scaling multipliers
895 	scale_mtof = FixedMul(scale_mtof, mtof_zoommul);
896 	scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
897 
898 	if (scale_mtof < min_scale_mtof)
899 		AM_minOutWindowScale();
900 	else if (scale_mtof > max_scale_mtof)
901 		AM_maxOutWindowScale();
902 }
903 
904 
905 //
906 //
907 //
AM_doFollowPlayer(void)908 void AM_doFollowPlayer(void)
909 {
910 	player_t &p = displayplayer();
911 
912     if (f_oldloc.x != p.camera->x ||
913 		f_oldloc.y != p.camera->y)
914 	{
915 		m_x = FTOM(MTOF(p.camera->x)) - m_w/2;
916 		m_y = FTOM(MTOF(p.camera->y)) - m_h/2;
917 		m_x2 = m_x + m_w;
918 		m_y2 = m_y + m_h;
919 		f_oldloc.x = p.camera->x;
920 		f_oldloc.y = p.camera->y;
921 	}
922 }
923 
924 //
925 // Updates on Game Tick
926 //
AM_Ticker(void)927 void AM_Ticker (void)
928 {
929 	if (!automapactive)
930 		return;
931 
932 	amclock++;
933 
934 	if (followplayer)
935 		AM_doFollowPlayer();
936 
937 	// Change the zoom if necessary
938 	if (ftom_zoommul != FRACUNIT)
939 		AM_changeWindowScale();
940 
941 	// Change x,y location
942 	if (m_paninc.x || m_paninc.y)
943 		AM_changeWindowLoc();
944 
945     // NES - Glowing effect on locked doors.
946     if (lockglow < 90)
947         lockglow++;
948     else
949         lockglow = 0;
950 
951 }
952 
953 
954 //
955 // Clear automap frame buffer.
956 //
AM_clearFB(am_color_t color)957 void AM_clearFB (am_color_t color)
958 {
959 	int y;
960 
961 	if (screen->is8bit()) {
962 		if (f_w == f_p)
963 			memset (fb, color.index, f_w*f_h);
964 		else
965 			for (y = 0; y < f_h; y++)
966 				memset (fb + y * f_p, color.index, f_w);
967 	} else {
968 		int x;
969 		argb_t *line;
970 
971 		line = (argb_t *)(fb);
972 		for (y = 0; y < f_h; y++) {
973 			for (x = 0; x < f_w; x++) {
974 				line[x] = color.rgb;
975 			}
976 			line += f_p >> 2;
977 		}
978 	}
979 }
980 
981 
982 //
983 // Automap clipping of lines.
984 //
985 // Based on Cohen-Sutherland clipping algorithm but with a slightly
986 // faster reject and precalculated slopes.  If the speed is needed,
987 // use a hash algorithm to handle  the common cases.
988 //
AM_clipMline(mline_t * ml,fline_t * fl)989 BOOL AM_clipMline (mline_t *ml, fline_t *fl)
990 {
991 	enum {
992 		LEFT	=1,
993 		RIGHT	=2,
994 		BOTTOM	=4,
995 		TOP	=8
996 	};
997 
998 	register int outcode1 = 0;
999 	register int outcode2 = 0;
1000 	register int outside;
1001 
1002 	fpoint_t tmp = {0, 0};
1003 	int dx;
1004 	int dy;
1005 
1006 
1007 #define DOOUTCODE(oc, mx, my) \
1008 	(oc) = 0; \
1009 	if ((my) < 0) (oc) |= TOP; \
1010 	else if ((my) >= f_h) (oc) |= BOTTOM; \
1011 	if ((mx) < 0) (oc) |= LEFT; \
1012 	else if ((mx) >= f_w) (oc) |= RIGHT;
1013 
1014 	// do trivial rejects and outcodes
1015 	if (ml->a.y > m_y2)
1016 		outcode1 = TOP;
1017 	else if (ml->a.y < m_y)
1018 		outcode1 = BOTTOM;
1019 
1020 	if (ml->b.y > m_y2)
1021 		outcode2 = TOP;
1022 	else if (ml->b.y < m_y)
1023 		outcode2 = BOTTOM;
1024 
1025 	if (outcode1 & outcode2)
1026 		return false; // trivially outside
1027 
1028 	if (ml->a.x < m_x)
1029 		outcode1 |= LEFT;
1030 	else if (ml->a.x > m_x2)
1031 		outcode1 |= RIGHT;
1032 
1033 	if (ml->b.x < m_x)
1034 		outcode2 |= LEFT;
1035 	else if (ml->b.x > m_x2)
1036 		outcode2 |= RIGHT;
1037 
1038 	if (outcode1 & outcode2)
1039 		return false; // trivially outside
1040 
1041 	// transform to frame-buffer coordinates.
1042 	fl->a.x = CXMTOF(ml->a.x);
1043 	fl->a.y = CYMTOF(ml->a.y);
1044 	fl->b.x = CXMTOF(ml->b.x);
1045 	fl->b.y = CYMTOF(ml->b.y);
1046 
1047 	DOOUTCODE(outcode1, fl->a.x, fl->a.y);
1048 	DOOUTCODE(outcode2, fl->b.x, fl->b.y);
1049 
1050 	if (outcode1 & outcode2)
1051 		return false;
1052 
1053 	while (outcode1 | outcode2) {
1054 		// may be partially inside box
1055 		// find an outside point
1056 		if (outcode1)
1057 			outside = outcode1;
1058 		else
1059 			outside = outcode2;
1060 
1061 		// clip to each side
1062 		if (outside & TOP) {
1063 			dy = fl->a.y - fl->b.y;
1064 			dx = fl->b.x - fl->a.x;
1065 			tmp.x = fl->a.x + (dx*(fl->a.y))/dy;
1066 			tmp.y = 0;
1067 		} else if (outside & BOTTOM) {
1068 			dy = fl->a.y - fl->b.y;
1069 			dx = fl->b.x - fl->a.x;
1070 			tmp.x = fl->a.x + (dx*(fl->a.y-f_h))/dy;
1071 			tmp.y = f_h-1;
1072 		} else if (outside & RIGHT) {
1073 			dy = fl->b.y - fl->a.y;
1074 			dx = fl->b.x - fl->a.x;
1075 			tmp.y = fl->a.y + (dy*(f_w-1 - fl->a.x))/dx;
1076 			tmp.x = f_w-1;
1077 		} else if (outside & LEFT) {
1078 			dy = fl->b.y - fl->a.y;
1079 			dx = fl->b.x - fl->a.x;
1080 			tmp.y = fl->a.y + (dy*(-fl->a.x))/dx;
1081 			tmp.x = 0;
1082 		}
1083 
1084 		if (outside == outcode1) {
1085 			fl->a = tmp;
1086 			DOOUTCODE(outcode1, fl->a.x, fl->a.y);
1087 		} else {
1088 			fl->b = tmp;
1089 			DOOUTCODE(outcode2, fl->b.x, fl->b.y);
1090 		}
1091 
1092 		if (outcode1 & outcode2)
1093 			return false; // trivially outside
1094 	}
1095 
1096 	return true;
1097 }
1098 #undef DOOUTCODE
1099 
1100 
1101 //
1102 // Classic Bresenham w/ whatever optimizations needed for speed
1103 //
1104 
1105 // Palettized (8bpp) version:
1106 
AM_drawFlineP(fline_t * fl,byte color)1107 void AM_drawFlineP (fline_t* fl, byte color)
1108 {
1109 			register int x;
1110 			register int y;
1111 			register int dx;
1112 			register int dy;
1113 			register int sx;
1114 			register int sy;
1115 			register int ax;
1116 			register int ay;
1117 			register int d;
1118 
1119 
1120 			fl->a.x += f_x;
1121 			fl->b.x += f_x;
1122 			fl->a.y += f_y;
1123 			fl->b.y += f_y;
1124 
1125 			dx = fl->b.x - fl->a.x;
1126 			ax = 2 * (dx<0 ? -dx : dx);
1127 			sx = dx<0 ? -1 : 1;
1128 
1129 			dy = fl->b.y - fl->a.y;
1130 			ay = 2 * (dy<0 ? -dy : dy);
1131 			sy = dy<0 ? -1 : 1;
1132 
1133 			x = fl->a.x;
1134 			y = fl->a.y;
1135 
1136 			if (ax > ay) {
1137 				d = ay - ax/2;
1138 
1139 					while (1) {
1140 						PUTDOTP(x,y,(byte)color);
1141 						if (x == fl->b.x)
1142 							return;
1143 			if (d >= 0)
1144 			{
1145 							y += sy;
1146 							d -= ax;
1147 						}
1148 						x += sx;
1149 						d += ay;
1150 					}
1151 			}
1152 	else
1153 	{
1154 				d = ax - ay/2;
1155 					while (1) {
1156 						PUTDOTP(x, y, (byte)color);
1157 						if (y == fl->b.y)
1158 							return;
1159 			if (d >= 0)
1160 			{
1161 							x += sx;
1162 							d -= ay;
1163 						}
1164 						y += sy;
1165 						d += ax;
1166 					}
1167 	}
1168 }
1169 
1170 // Direct (32bpp) version:
1171 
AM_drawFlineD(fline_t * fl,argb_t color)1172 void AM_drawFlineD(fline_t* fl, argb_t color)
1173 {
1174 	register int x;
1175 	register int y;
1176 	register int dx;
1177 	register int dy;
1178 	register int sx;
1179 	register int sy;
1180 	register int ax;
1181 	register int ay;
1182 	register int d;
1183 
1184 	fl->a.x += f_x;
1185 	fl->b.x += f_x;
1186 	fl->a.y += f_y;
1187 	fl->b.y += f_y;
1188 
1189 	dx = fl->b.x - fl->a.x;
1190 	ax = 2 * (dx<0 ? -dx : dx);
1191 	sx = dx<0 ? -1 : 1;
1192 
1193 	dy = fl->b.y - fl->a.y;
1194 	ay = 2 * (dy<0 ? -dy : dy);
1195 	sy = dy<0 ? -1 : 1;
1196 
1197 	x = fl->a.x;
1198 	y = fl->a.y;
1199 
1200 	if (ax > ay) {
1201 		d = ay - ax/2;
1202 
1203 		while (1) {
1204 			PUTDOTD(x, y, color);
1205 			if (x == fl->b.x)
1206 				return;
1207 			if (d >= 0)
1208 			{
1209 				y += sy;
1210 				d -= ax;
1211 			}
1212 			x += sx;
1213 			d += ay;
1214 		}
1215 	}
1216 	else
1217 	{
1218 		d = ax - ay/2;
1219 		while (1) {
1220 			PUTDOTD(x, y, color);
1221 			if (y == fl->b.y)
1222 				return;
1223 			if (d >= 0)
1224 			{
1225 				x += sx;
1226 				d -= ay;
1227 			}
1228 			y += sy;
1229 			d += ax;
1230 		}
1231 				}
1232 }
1233 
1234 
1235 //
1236 // Clip lines, draw visible part sof lines.
1237 //
AM_drawMline(mline_t * ml,am_color_t color)1238 void AM_drawMline (mline_t* ml, am_color_t color)
1239 {
1240 	static fline_t fl;
1241 
1242 	if (AM_clipMline(ml, &fl))
1243 	{
1244 		// draws it on frame buffer using fb coords
1245 		if (screen->is8bit())
1246 			AM_drawFlineP(&fl, color.index);
1247 		else
1248 			AM_drawFlineD(&fl, color.rgb);
1249 	}
1250 }
1251 
1252 
1253 
1254 //
1255 // Draws flat (floor/ceiling tile) aligned grid lines.
1256 //
AM_drawGrid(am_color_t color)1257 void AM_drawGrid(am_color_t color)
1258 {
1259 	fixed_t x, y;
1260 	fixed_t start, end;
1261 	mline_t ml;
1262 
1263 	// Figure out start of vertical gridlines
1264 	start = m_x;
1265 	if ((start-bmaporgx)%(MAPBLOCKUNITS<<FRACBITS))
1266 		start += (MAPBLOCKUNITS<<FRACBITS)
1267 			- ((start-bmaporgx)%(MAPBLOCKUNITS<<FRACBITS));
1268 	end = m_x + m_w;
1269 
1270 	// draw vertical gridlines
1271 	ml.a.y = m_y;
1272 	ml.b.y = m_y+m_h;
1273 	for (x=start; x<end; x+=(MAPBLOCKUNITS<<FRACBITS)) {
1274 		ml.a.x = x;
1275 		ml.b.x = x;
1276 		if (am_rotate) {
1277 			AM_rotatePoint (&ml.a.x, &ml.a.y);
1278 			AM_rotatePoint (&ml.b.x, &ml.b.y);
1279 		}
1280 		AM_drawMline(&ml, color);
1281 	}
1282 
1283 	// Figure out start of horizontal gridlines
1284 	start = m_y;
1285 	if ((start-bmaporgy)%(MAPBLOCKUNITS<<FRACBITS))
1286 		start += (MAPBLOCKUNITS<<FRACBITS)
1287 			- ((start-bmaporgy)%(MAPBLOCKUNITS<<FRACBITS));
1288 	end = m_y + m_h;
1289 
1290 	// draw horizontal gridlines
1291 	ml.a.x = m_x;
1292 	ml.b.x = m_x + m_w;
1293 	for (y=start; y<end; y+=(MAPBLOCKUNITS<<FRACBITS)) {
1294 		ml.a.y = y;
1295 		ml.b.y = y;
1296 		if (am_rotate) {
1297 			AM_rotatePoint (&ml.a.x, &ml.a.y);
1298 			AM_rotatePoint (&ml.b.x, &ml.b.y);
1299 		}
1300 		AM_drawMline(&ml, color);
1301 	}
1302 }
1303 
1304 //
1305 // Determines visible lines, draws them.
1306 // This is LineDef based, not LineSeg based.
1307 //
AM_drawWalls(void)1308 void AM_drawWalls(void)
1309 {
1310 	int i, r, g, b;
1311 	static mline_t l;
1312 	float rdif, gdif, bdif;
1313 	palette_t *pal = GetDefaultPalette();
1314 
1315 
1316 	for (i=0;i<numlines;i++) {
1317 		l.a.x = lines[i].v1->x;
1318 		l.a.y = lines[i].v1->y;
1319 		l.b.x = lines[i].v2->x;
1320 		l.b.y = lines[i].v2->y;
1321 
1322 		if (am_rotate) {
1323 			AM_rotatePoint (&l.a.x, &l.a.y);
1324 			AM_rotatePoint (&l.b.x, &l.b.y);
1325 		}
1326 
1327 		if (cheating || (lines[i].flags & ML_MAPPED))
1328 		{
1329 			if ((lines[i].flags & ML_DONTDRAW) && !cheating)
1330 				continue;
1331             if (!lines[i].backsector &&
1332                 (((am_usecustomcolors || viewactive) &&
1333                 lines[i].special != Exit_Normal &&
1334                 lines[i].special != Exit_Secret) ||
1335                 (!am_usecustomcolors && !viewactive)))
1336             {
1337 				AM_drawMline(&l, WallColor);
1338 			}
1339 			else
1340 			{
1341 				if ((lines[i].special == Teleport ||
1342 					lines[i].special == Teleport_NoFog ||
1343 					lines[i].special == Teleport_Line) &&
1344 					(am_usecustomcolors || viewactive))
1345 				{ // teleporters
1346 					AM_drawMline(&l, TeleportColor);
1347 				}
1348 				else if ((lines[i].special == Teleport_NewMap ||
1349 						 lines[i].special == Teleport_EndGame ||
1350 						 lines[i].special == Exit_Normal ||
1351 						 lines[i].special == Exit_Secret) &&
1352 						 (am_usecustomcolors || viewactive))
1353 				{ // exit
1354 					AM_drawMline(&l, ExitColor);
1355 				}
1356 				else if (lines[i].flags & ML_SECRET)
1357 				{ // secret door
1358 					if (cheating)
1359 						AM_drawMline(&l, SecretWallColor);
1360 				    else
1361 						AM_drawMline(&l, WallColor);
1362 				}
1363 				else if (lines[i].special == Door_LockedRaise)
1364 				{
1365 				    // NES - Locked doors glow from a predefined color to either blue, yellow, or red.
1366                     r = RPART(LockedColor.rgb), g = GPART(LockedColor.rgb), b = BPART(LockedColor.rgb);
1367 
1368                     if (am_usecustomcolors) {
1369                         if (lines[i].args[3] == (BCard | CardIsSkull)) {
1370                             rdif = (0 - r)/30;
1371                             gdif = (0 - g)/30;
1372                             bdif = (255 - b)/30;
1373                         } else if (lines[i].args[3] == (YCard | CardIsSkull)) {
1374                             rdif = (255 - r)/30;
1375                             gdif = (255 - g)/30;
1376                             bdif = (0 - b)/30;
1377                         } else {
1378                             rdif = (255 - r)/30;
1379                             gdif = (0 - g)/30;
1380                             bdif = (0 - b)/30;
1381                         }
1382 
1383                         if (lockglow < 30) {
1384                             AM_drawMline (&l, AM_BestColor (pal->basecolors, r + ((int)rdif*lockglow),
1385                                           g + ((int)gdif*lockglow), b + ((int)bdif*lockglow),
1386                                           pal->numcolors));
1387                         } else if (lockglow < 60) {
1388                             AM_drawMline (&l, AM_BestColor (pal->basecolors, r + ((int)rdif*(60-lockglow)),
1389                                           g + ((int)gdif*(60-lockglow)), b + ((int)bdif*(60-lockglow)),
1390                                           pal->numcolors));
1391                         } else {
1392                             AM_drawMline (&l, AM_BestColor (pal->basecolors, r, g, b,
1393                                           pal->numcolors));
1394                         }
1395 				    } else {
1396                         AM_drawMline (&l, AM_BestColor (pal->basecolors, r, g, b,
1397                                       pal->numcolors));
1398                     }
1399                 }
1400 				else if (lines[i].backsector->floorheight
1401 					  != lines[i].frontsector->floorheight)
1402 				{
1403 					AM_drawMline(&l, FDWallColor); // floor level change
1404 				}
1405 				else if (lines[i].backsector->ceilingheight
1406 					  != lines[i].frontsector->ceilingheight)
1407 				{
1408 					AM_drawMline(&l, CDWallColor); // ceiling level change
1409 				}
1410 				else if (cheating)
1411 				{
1412 					AM_drawMline(&l, TSWallColor);
1413 				}
1414 			}
1415 		}
1416 		else if (consoleplayer().powers[pw_allmap])
1417 		{
1418 			if (!(lines[i].flags & ML_DONTDRAW))
1419 				AM_drawMline(&l, NotSeenColor);
1420 		}
1421     }
1422 }
1423 
1424 
1425 //
1426 // Rotation in 2D.
1427 // Used to rotate player arrow line character.
1428 //
1429 void
AM_rotate(fixed_t * x,fixed_t * y,angle_t a)1430 AM_rotate
1431 ( fixed_t*	x,
1432   fixed_t*	y,
1433   angle_t	a )
1434 {
1435     fixed_t tmpx;
1436 
1437     tmpx =
1438 	FixedMul(*x,finecosine[a>>ANGLETOFINESHIFT])
1439 	- FixedMul(*y,finesine[a>>ANGLETOFINESHIFT]);
1440 
1441     *y   =
1442 	FixedMul(*x,finesine[a>>ANGLETOFINESHIFT])
1443 	+ FixedMul(*y,finecosine[a>>ANGLETOFINESHIFT]);
1444 
1445     *x = tmpx;
1446 }
1447 
AM_rotatePoint(fixed_t * x,fixed_t * y)1448 void AM_rotatePoint (fixed_t *x, fixed_t *y)
1449 {
1450 	player_t &p = displayplayer();
1451 
1452 	*x -= p.camera->x;
1453 	*y -= p.camera->y;
1454 	AM_rotate (x, y, ANG90 - p.camera->angle);
1455 	*x += p.camera->x;
1456 	*y += p.camera->y;
1457 }
1458 
1459 void
AM_drawLineCharacter(mline_t * lineguy,int lineguylines,fixed_t scale,angle_t angle,am_color_t color,fixed_t x,fixed_t y)1460 AM_drawLineCharacter
1461 ( mline_t*	lineguy,
1462   int		lineguylines,
1463   fixed_t	scale,
1464   angle_t	angle,
1465   am_color_t	color,
1466   fixed_t	x,
1467   fixed_t	y )
1468 {
1469 	int		i;
1470 	mline_t	l;
1471 
1472 	for (i=0;i<lineguylines;i++) {
1473 		l.a.x = lineguy[i].a.x;
1474 		l.a.y = lineguy[i].a.y;
1475 
1476 		if (scale) {
1477 			l.a.x = FixedMul(scale, l.a.x);
1478 			l.a.y = FixedMul(scale, l.a.y);
1479 		}
1480 
1481 		if (angle)
1482 			AM_rotate(&l.a.x, &l.a.y, angle);
1483 
1484 		l.a.x += x;
1485 		l.a.y += y;
1486 
1487 		l.b.x = lineguy[i].b.x;
1488 		l.b.y = lineguy[i].b.y;
1489 
1490 		if (scale) {
1491 			l.b.x = FixedMul(scale, l.b.x);
1492 			l.b.y = FixedMul(scale, l.b.y);
1493 		}
1494 
1495 		if (angle)
1496 			AM_rotate(&l.b.x, &l.b.y, angle);
1497 
1498 		l.b.x += x;
1499 		l.b.y += y;
1500 
1501 		AM_drawMline(&l, color);
1502 	}
1503 }
1504 
AM_drawPlayers(void)1505 void AM_drawPlayers(void)
1506 {
1507 	angle_t angle;
1508 	player_t &conplayer = displayplayer();
1509 	argb_t *palette;
1510 	palette = GetDefaultPalette()->colors;
1511 
1512 	if (!multiplayer)
1513 	{
1514 		if (am_rotate)
1515 			angle = ANG90;
1516 		else
1517 			angle = conplayer.camera->angle;
1518 
1519 		if (cheating)
1520 			AM_drawLineCharacter
1521 			(cheat_player_arrow, NUMCHEATPLYRLINES, 0,
1522 			 angle, YourColor, conplayer.camera->x, conplayer.camera->y);
1523 		else
1524 			AM_drawLineCharacter
1525 			(player_arrow, NUMPLYRLINES, 0, angle,
1526 			 YourColor, conplayer.camera->x, conplayer.camera->y);
1527 		return;
1528 	}
1529 
1530 	for (Players::iterator it = players.begin();it != players.end();++it)
1531 	{
1532 		player_t *p = &*it;
1533 		am_color_t color;
1534 		mpoint_t pt;
1535 
1536 		if (!(it->ingame()) || !p->mo ||
1537 			(((sv_gametype == GM_DM && p != &conplayer) ||
1538 			((sv_gametype == GM_TEAMDM || sv_gametype == GM_CTF) && p->userinfo.team != conplayer.userinfo.team))
1539 			&& !(netdemo.isPlaying() || netdemo.isPaused())
1540 			&& !demoplayback && !(conplayer.spectator)) || p->spectator)
1541 		{
1542 			continue;
1543 		}
1544 
1545 		if (p->powers[pw_invisibility])
1546 			color = AlmostBackground;
1547 		else if (demoplayback && democlassic) {
1548 			switch (it->id) {
1549 				case 1: color = AM_GetColorFromString (palette, "00 FF 00"); break;
1550 				case 2: color = AM_GetColorFromString (palette, "60 60 B0"); break;
1551 				case 3: color = AM_GetColorFromString (palette, "B0 B0 30"); break;
1552 				case 4: color = AM_GetColorFromString (palette, "C0 00 00"); break;
1553 				default: break;
1554 			}
1555 		} else {
1556 			int playercolor = CL_GetPlayerColor(p);
1557 			color.rgb = (argb_t)playercolor;
1558 			color.index = BestColor (GetDefaultPalette()->basecolors,
1559 							   RPART(playercolor),
1560 							   GPART(playercolor),
1561 							   BPART(playercolor),
1562 							   GetDefaultPalette()->numcolors);
1563 		}
1564 
1565 		pt.x = p->mo->x;
1566 		pt.y = p->mo->y;
1567 		angle = p->mo->angle;
1568 
1569 		if (am_rotate)
1570 		{
1571 			AM_rotatePoint (&pt.x, &pt.y);
1572 			angle -= conplayer.camera->angle - ANG90;
1573 		}
1574 
1575 		AM_drawLineCharacter
1576 			(player_arrow, NUMPLYRLINES, 0, angle,
1577 			 color, pt.x, pt.y);
1578     }
1579 }
1580 
AM_drawThings(am_color_t color)1581 void AM_drawThings (am_color_t color)
1582 {
1583 	int		 i;
1584 	AActor*	 t;
1585 	mpoint_t p;
1586 	angle_t	 angle;
1587 
1588 	for (i=0;i<numsectors;i++)
1589 	{
1590 		t = sectors[i].thinglist;
1591 		while (t)
1592 		{
1593 			p.x = t->x;
1594 			p.y = t->y;
1595 			angle = t->angle;
1596 
1597 			if (am_rotate)
1598 			{
1599 				AM_rotatePoint (&p.x, &p.y);
1600 				angle += ANG90 - displayplayer().camera->angle;
1601 			}
1602 
1603 			AM_drawLineCharacter(thintriangle_guy, NUMTHINTRIANGLEGUYLINES, 16<<FRACBITS, angle, color, p.x, p.y);
1604 			t = t->snext;
1605 		}
1606 	}
1607 }
1608 
AM_drawMarks(void)1609 void AM_drawMarks (void)
1610 {
1611 	int i, fx, fy, w, h;
1612 	mpoint_t pt;
1613 
1614 	for (i = 0; i < AM_NUMMARKPOINTS; i++)
1615 	{
1616 		if (markpoints[i].x != -1)
1617 		{
1618 			//      w = LESHORT(marknums[i]->width);
1619 			//      h = LESHORT(marknums[i]->height);
1620 			w = 5; // because something's wrong with the wad, i guess
1621 			h = 6; // because something's wrong with the wad, i guess
1622 
1623 			pt.x = markpoints[i].x;
1624 			pt.y = markpoints[i].y;
1625 
1626 			if (am_rotate)
1627 				AM_rotatePoint (&pt.x, &pt.y);
1628 
1629 			fx = CXMTOF(pt.x);
1630 			fy = CYMTOF(pt.y) - 3;
1631 
1632 			if (fx >= f_x && fx <= f_w - w && fy >= f_y && fy <= f_h - h)
1633 				FB->DrawPatchCleanNoMove (marknums[i], fx, fy);
1634 		}
1635 	}
1636 }
1637 
AM_drawCrosshair(am_color_t color)1638 void AM_drawCrosshair (am_color_t color)
1639 {
1640 	// single point for now
1641 	if (screen->is8bit())
1642 	{
1643 		PUTDOTP(f_w/2, (f_h+1)/2, (byte)color.index);
1644 	}
1645 	else
1646 	{
1647 		PUTDOTD(f_w/2, (f_h+1)/2, color.rgb);
1648 	}
1649 }
1650 
AM_Drawer(void)1651 void AM_Drawer (void)
1652 {
1653 	if (!automapactive)
1654 		return;
1655 
1656 	fb = screen->buffer;
1657 	if (!viewactive)
1658 	{
1659 		// [RH] Set f_? here now to handle automap overlaying
1660 		// and view size adjustments.
1661 		f_x = f_y = 0;
1662 		f_w = screen->width;
1663 		f_h = ST_Y;
1664 		f_p = screen->pitch;
1665 
1666 		AM_clearFB(Background);
1667 	}
1668 	else
1669 	{
1670 		f_x = viewwindowx;
1671 		f_y = viewwindowy;
1672 		f_w = realviewwidth;
1673 		f_h = realviewheight;
1674 		f_p = screen->pitch;
1675 	}
1676 	AM_activateNewScale();
1677 
1678 	if (grid)
1679 		AM_drawGrid(GridColor);
1680 
1681 	AM_drawWalls();
1682 	AM_drawPlayers();
1683 	if (cheating==2)
1684 		AM_drawThings(ThingColor);
1685 
1686 	if (!(viewactive && am_overlay < 2))
1687 		AM_drawCrosshair(XHairColor);
1688 
1689 	AM_drawMarks();
1690 
1691 	if (!(viewactive && am_overlay < 2)) {
1692 
1693 		char line[64+10];
1694 		int OV_Y, i, time = level.time / TICRATE, height;
1695 
1696 		height = (hu_font[0]->height() + 1) * CleanYfac;
1697 		OV_Y = screen->height - ((32 * screen->height) / 200);
1698 
1699 		if (sv_gametype == GM_COOP)
1700 		{
1701 			if (am_showmonsters)
1702 			{
1703 				sprintf (line, TEXTCOLOR_RED "MONSTERS:"
1704 							   TEXTCOLOR_NORMAL " %d / %d",
1705 							   level.killed_monsters, level.total_monsters);
1706                 if (viewactive && screenblocks == 11)
1707                     FB->DrawTextClean (CR_GREY, screen->width - V_StringWidth (line) * CleanXfac, OV_Y - (height * 4) + 1, line);
1708                 else if (viewactive && screenblocks == 12)
1709                     FB->DrawTextClean (CR_GREY, 0, screen->height - (height * 2) + 1, line);
1710                 else
1711                     FB->DrawTextClean (CR_GREY, 0, ST_Y - (height * 2) + 1, line);
1712 			}
1713 
1714 			if (am_showsecrets)
1715 			{
1716 				sprintf (line, TEXTCOLOR_RED "SECRETS:"
1717 							   TEXTCOLOR_NORMAL " %d / %d",
1718 							   level.found_secrets, level.total_secrets);
1719                 if (viewactive && screenblocks == 11)
1720                     FB->DrawTextClean (CR_GREY, screen->width - V_StringWidth (line) * CleanXfac, OV_Y - (height * 3) + 1, line);
1721                 else if (viewactive && screenblocks == 12)
1722                     FB->DrawTextClean (CR_GREY, screen->width - V_StringWidth (line) * CleanXfac, screen->height - (height * 2) + 1, line);
1723                 else
1724                     FB->DrawTextClean (CR_GREY, screen->width - V_StringWidth (line) * CleanXfac, ST_Y - (height * 2) + 1, line);
1725 			}
1726 		}
1727 
1728 		if (am_classicmapstring)
1729 		{
1730 			int firstmap;
1731 			int mapoffset = 1;
1732 			switch (gamemission)
1733 			{
1734 				case doom2:
1735 				firstmap = HUSTR_1;
1736 				break;
1737 				case pack_plut:
1738 				firstmap = PHUSTR_1;
1739 				break;
1740 				case pack_tnt:
1741 				firstmap = THUSTR_1;
1742 				break;
1743 				default:
1744 				firstmap = HUSTR_E1M1;
1745 				mapoffset = level.cluster; // Episodes skip map numbers.
1746 				break;
1747 			}
1748 			strcpy(line, GStrings(firstmap + level.levelnum - mapoffset));
1749 
1750 			if (viewactive && screenblocks == 11)
1751 				FB->DrawTextClean(CR_RED, screen->width - V_StringWidth (line) * CleanXfac, OV_Y - (height * 1) + 1, line);
1752 			else if (viewactive && screenblocks == 12)
1753 				FB->DrawTextClean (CR_RED, 0, screen->height - (height * 1) + 1, line);
1754 			else
1755 				FB->DrawTextClean (CR_RED, 0, ST_Y - (height * 1) + 1, line);
1756 		}
1757 		else
1758 		{
1759             line[0] = '\x8a';
1760             line[1] = CR_RED + 'A';
1761             i = 0;
1762             while (i < 8 && level.mapname[i]) {
1763                 line[2 + i] = level.mapname[i];
1764                 i++;
1765             }
1766             i += 2;
1767             line[i++] = ':';
1768             line[i++] = ' ';
1769             line[i++] = '\x8a';
1770             line[i++] = '-';
1771             strcpy (&line[i], level.level_name);
1772             if (viewactive && screenblocks == 11)
1773                 FB->DrawTextClean (CR_GREY, screen->width - V_StringWidth (line) * CleanXfac, OV_Y - (height * 1) + 1, line);
1774             else if (viewactive && screenblocks == 12)
1775                 FB->DrawTextClean (CR_GREY, 0, screen->height - (height * 1) + 1, line);
1776             else
1777                 FB->DrawTextClean (CR_GREY, 0, ST_Y - (height * 1) + 1, line);
1778 		}
1779 
1780 		if (am_showtime) {
1781 			sprintf (line, " %02d:%02d:%02d", time/3600, (time%3600)/60, time%60);	// Time
1782             if (viewactive && screenblocks == 11)
1783                 FB->DrawTextClean (CR_RED, screen->width - V_StringWidth (line) * CleanXfac, OV_Y - (height * 2) + 1, line);
1784             else if (viewactive && screenblocks == 12)
1785                 FB->DrawTextClean (CR_RED, screen->width - V_StringWidth (line) * CleanXfac, screen->height - (height * 1) + 1, line);
1786             else
1787                 FB->DrawTextClean (CR_RED, screen->width - V_StringWidth (line) * CleanXfac, ST_Y - (height * 1) + 1, line);
1788 		}
1789 
1790 	}
1791 }
1792 
1793 VERSION_CONTROL (am_map_cpp, "$Id: am_map.cpp 4542 2014-02-09 17:39:42Z dr_sean $")
1794 
1795 
1796