1 //
2 // Copyright(C) 1993-1996 Id Software, Inc.
3 // Copyright(C) 1993-2008 Raven Software
4 // Copyright(C) 2005-2014 Simon Howard
5 //
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 //
16 
17 // AM_map.c
18 
19 #include <stdio.h>
20 
21 #include "doomdef.h"
22 #include "deh_str.h"
23 #include "i_timer.h"
24 #include "i_video.h"
25 #include "m_controls.h"
26 #include "p_local.h"
27 #include "am_map.h"
28 #include "am_data.h"
29 
30 #include "doomkeys.h"
31 #include "v_video.h"
32 
33 vertex_t KeyPoints[NUMKEYS];
34 
35 #define NUMALIAS 3              // Number of antialiased lines.
36 
37 const char *LevelNames[] = {
38     // EPISODE 1 - THE CITY OF THE DAMNED
39     "E1M1:  THE DOCKS",
40     "E1M2:  THE DUNGEONS",
41     "E1M3:  THE GATEHOUSE",
42     "E1M4:  THE GUARD TOWER",
43     "E1M5:  THE CITADEL",
44     "E1M6:  THE CATHEDRAL",
45     "E1M7:  THE CRYPTS",
46     "E1M8:  HELL'S MAW",
47     "E1M9:  THE GRAVEYARD",
48     // EPISODE 2 - HELL'S MAW
49     "E2M1:  THE CRATER",
50     "E2M2:  THE LAVA PITS",
51     "E2M3:  THE RIVER OF FIRE",
52     "E2M4:  THE ICE GROTTO",
53     "E2M5:  THE CATACOMBS",
54     "E2M6:  THE LABYRINTH",
55     "E2M7:  THE GREAT HALL",
56     "E2M8:  THE PORTALS OF CHAOS",
57     "E2M9:  THE GLACIER",
58     // EPISODE 3 - THE DOME OF D'SPARIL
59     "E3M1:  THE STOREHOUSE",
60     "E3M2:  THE CESSPOOL",
61     "E3M3:  THE CONFLUENCE",
62     "E3M4:  THE AZURE FORTRESS",
63     "E3M5:  THE OPHIDIAN LAIR",
64     "E3M6:  THE HALLS OF FEAR",
65     "E3M7:  THE CHASM",
66     "E3M8:  D'SPARIL'S KEEP",
67     "E3M9:  THE AQUIFER",
68     // EPISODE 4: THE OSSUARY
69     "E4M1:  CATAFALQUE",
70     "E4M2:  BLOCKHOUSE",
71     "E4M3:  AMBULATORY",
72     "E4M4:  SEPULCHER",
73     "E4M5:  GREAT STAIR",
74     "E4M6:  HALLS OF THE APOSTATE",
75     "E4M7:  RAMPARTS OF PERDITION",
76     "E4M8:  SHATTERED BRIDGE",
77     "E4M9:  MAUSOLEUM",
78     // EPISODE 5: THE STAGNANT DEMESNE
79     "E5M1:  OCHRE CLIFFS",
80     "E5M2:  RAPIDS",
81     "E5M3:  QUAY",
82     "E5M4:  COURTYARD",
83     "E5M5:  HYDRATYR",
84     "E5M6:  COLONNADE",
85     "E5M7:  FOETID MANSE",
86     "E5M8:  FIELD OF JUDGEMENT",
87     "E5M9:  SKEIN OF D'SPARIL",
88     // EPISODE 6: unnamed
89     "E6M1:  ",
90     "E6M2:  ",
91     "E6M3:  ",
92 };
93 
94 static int cheating = 0;
95 static int grid = 0;
96 
97 static int leveljuststarted = 1;        // kluge until AM_LevelInit() is called
98 
99 boolean automapactive = false;
100 static int finit_width;// = SCREENWIDTH;
101 static int finit_height;// = SCREENHEIGHT - (42 << crispy->hires);
102 static int f_x, f_y;            // location of window on screen
103 static int f_w, f_h;            // size of window on screen
104 static int lightlev;            // used for funky strobing effect
105 static byte *fb;                // pseudo-frame buffer
106 static int amclock;
107 
108 static mpoint_t m_paninc;       // how far the window pans each tic (map coords)
109 static fixed_t mtof_zoommul;    // how far the window zooms in each tic (map coords)
110 static fixed_t ftom_zoommul;    // how far the window zooms in each tic (fb coords)
111 
112 static fixed_t m_x, m_y;        // LL x,y where the window is on the map (map coords)
113 static fixed_t m_x2, m_y2;      // UR x,y where the window is on the map (map coords)
114 
115 // width/height of window on map (map coords)
116 static fixed_t m_w, m_h;
117 static fixed_t min_x, min_y;    // based on level size
118 static fixed_t max_x, max_y;    // based on level size
119 static fixed_t max_w, max_h;    // max_x-min_x, max_y-min_y
120 static fixed_t min_w, min_h;    // based on player size
121 static fixed_t min_scale_mtof;  // used to tell when to stop zooming out
122 static fixed_t max_scale_mtof;  // used to tell when to stop zooming in
123 
124 // old stuff for recovery later
125 static fixed_t old_m_w, old_m_h;
126 static fixed_t old_m_x, old_m_y;
127 
128 // old location used by the Follower routine
129 static mpoint_t f_oldloc;
130 
131 // used by MTOF to scale from map-to-frame-buffer coords
132 static fixed_t scale_mtof = (fixed_t)INITSCALEMTOF;
133 // used by FTOM to scale from frame-buffer-to-map coords (=1/scale_mtof)
134 static fixed_t scale_ftom;
135 
136 static player_t *plr;           // the player represented by an arrow
137 static vertex_t oldplr;
138 
139 //static patch_t *marknums[10]; // numbers used for marking by the automap
140 //static mpoint_t markpoints[AM_NUMMARKPOINTS]; // where the points are
141 //static int markpointnum = 0; // next point to be assigned
142 
143 static int followplayer = 1;    // specifies whether to follow the player around
144 
145 static char cheat_amap[] = { 'r', 'a', 'v', 'm', 'a', 'p' };
146 
147 static byte cheatcount = 0;
148 
149 extern boolean viewactive;
150 
151 static byte antialias[NUMALIAS][8] = {
152     {96, 97, 98, 99, 100, 101, 102, 103},
153     {110, 109, 108, 107, 106, 105, 104, 103},
154     {75, 76, 77, 78, 79, 80, 81, 103}
155 };
156 
157 /*
158 static byte *aliasmax[NUMALIAS] = {
159 	&antialias[0][7], &antialias[1][7], &antialias[2][7]
160 };*/
161 
162 static byte *maplump;           // pointer to the raw data for the automap background.
163 static short mapystart = 0;     // y-value for the start of the map bitmap...used in the paralax stuff.
164 static short mapxstart = 0;     //x-value for the bitmap.
165 
166 //byte screens[][SCREENWIDTH*SCREENHEIGHT];
167 //void V_MarkRect (int x, int y, int width, int height);
168 
169 // Functions
170 
171 void DrawWuLine(int X0, int Y0, int X1, int Y1, byte * BaseColor,
172                 int NumLevels, unsigned short IntensityBits);
173 
174 // Calculates the slope and slope according to the x-axis of a line
175 // segment in map coordinates (with the upright y-axis n' all) so
176 // that it can be used with the brain-dead drawing stuff.
177 
178 // Ripped out for Heretic
179 /*
180 void AM_getIslope(mline_t *ml, islope_t *is)
181 {
182   int dx, dy;
183 
184   dy = ml->a.y - ml->b.y;
185   dx = ml->b.x - ml->a.x;
186   if (!dy) is->islp = (dx<0?-INT_MAX:INT_MAX);
187   else is->islp = FixedDiv(dx, dy);
188   if (!dx) is->slp = (dy<0?-INT_MAX:INT_MAX);
189   else is->slp = FixedDiv(dy, dx);
190 }
191 */
192 
AM_activateNewScale(void)193 void AM_activateNewScale(void)
194 {
195     m_x += m_w / 2;
196     m_y += m_h / 2;
197     m_w = FTOM(f_w);
198     m_h = FTOM(f_h);
199     m_x -= m_w / 2;
200     m_y -= m_h / 2;
201     m_x2 = m_x + m_w;
202     m_y2 = m_y + m_h;
203 }
204 
AM_saveScaleAndLoc(void)205 void AM_saveScaleAndLoc(void)
206 {
207     old_m_x = m_x;
208     old_m_y = m_y;
209     old_m_w = m_w;
210     old_m_h = m_h;
211 }
212 
AM_restoreScaleAndLoc(void)213 void AM_restoreScaleAndLoc(void)
214 {
215 
216     m_w = old_m_w;
217     m_h = old_m_h;
218     if (!followplayer)
219     {
220         m_x = old_m_x;
221         m_y = old_m_y;
222     }
223     else
224     {
225         m_x = plr->mo->x - m_w / 2;
226         m_y = plr->mo->y - m_h / 2;
227     }
228     m_x2 = m_x + m_w;
229     m_y2 = m_y + m_h;
230 
231     // Change the scaling multipliers
232     scale_mtof = FixedDiv(f_w << FRACBITS, m_w);
233     scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
234 }
235 
236 // adds a marker at the current location
237 
238 /*
239 void AM_addMark(void)
240 {
241   markpoints[markpointnum].x = m_x + m_w/2;
242   markpoints[markpointnum].y = m_y + m_h/2;
243   markpointnum = (markpointnum + 1) % AM_NUMMARKPOINTS;
244 
245 }
246 */
AM_findMinMaxBoundaries(void)247 void AM_findMinMaxBoundaries(void)
248 {
249     int i;
250     fixed_t a, b;
251 
252     min_x = min_y = INT_MAX;
253     max_x = max_y = -INT_MAX;
254     for (i = 0; i < numvertexes; i++)
255     {
256         if (vertexes[i].x < min_x)
257             min_x = vertexes[i].x;
258         else if (vertexes[i].x > max_x)
259             max_x = vertexes[i].x;
260         if (vertexes[i].y < min_y)
261             min_y = vertexes[i].y;
262         else if (vertexes[i].y > max_y)
263             max_y = vertexes[i].y;
264     }
265     max_w = max_x - min_x;
266     max_h = max_y - min_y;
267     min_w = 2 * PLAYERRADIUS;
268     min_h = 2 * PLAYERRADIUS;
269 
270     a = FixedDiv(f_w << FRACBITS, max_w);
271     b = FixedDiv(f_h << FRACBITS, max_h);
272     min_scale_mtof = a < b ? a : b;
273 
274     max_scale_mtof = FixedDiv(f_h << FRACBITS, 2 * PLAYERRADIUS);
275 
276 }
277 
AM_changeWindowLoc(void)278 void AM_changeWindowLoc(void)
279 {
280     if (m_paninc.x || m_paninc.y)
281     {
282         followplayer = 0;
283         f_oldloc.x = INT_MAX;
284     }
285 
286     m_x += m_paninc.x;
287     m_y += m_paninc.y;
288 
289     if (m_x + m_w / 2 > max_x)
290     {
291         m_x = max_x - m_w / 2;
292         m_paninc.x = 0;
293     }
294     else if (m_x + m_w / 2 < min_x)
295     {
296         m_x = min_x - m_w / 2;
297         m_paninc.x = 0;
298     }
299     if (m_y + m_h / 2 > max_y)
300     {
301         m_y = max_y - m_h / 2;
302         m_paninc.y = 0;
303     }
304     else if (m_y + m_h / 2 < min_y)
305     {
306         m_y = min_y - m_h / 2;
307         m_paninc.y = 0;
308     }
309 
310     // The following code was commented out in the released Heretic source,
311     // but I believe we need to do this here to stop the background moving
312     // when we reach the map boundaries. (In the released source it's done
313     // in AM_clearFB).
314     mapxstart += MTOF(m_paninc.x+FRACUNIT/2);
315     mapystart -= MTOF(m_paninc.y+FRACUNIT/2);
316     if(mapxstart >= (finit_width >> crispy->hires))
317         mapxstart -= (finit_width >> crispy->hires);
318     if(mapxstart < 0)
319         mapxstart += (finit_width >> crispy->hires);
320     if(mapystart >= (finit_height >> crispy->hires))
321         mapystart -= (finit_height >> crispy->hires);
322     if(mapystart < 0)
323         mapystart += (finit_height >> crispy->hires);
324     // - end of code that was commented-out
325 
326     m_x2 = m_x + m_w;
327     m_y2 = m_y + m_h;
328 }
329 
AM_initVariables(void)330 void AM_initVariables(void)
331 {
332     int pnum;
333     thinker_t *think;
334     mobj_t *mo;
335 
336     //static event_t st_notify = { ev_keyup, AM_MSGENTERED };
337 
338     automapactive = true;
339     fb = I_VideoBuffer;
340 
341     f_oldloc.x = INT_MAX;
342     amclock = 0;
343     lightlev = 0;
344 
345     m_paninc.x = m_paninc.y = 0;
346     ftom_zoommul = FRACUNIT;
347     mtof_zoommul = FRACUNIT;
348 
349     m_w = FTOM(f_w);
350     m_h = FTOM(f_h);
351 
352     // find player to center on initially
353     if (!playeringame[pnum = consoleplayer])
354         for (pnum = 0; pnum < MAXPLAYERS; pnum++)
355             if (playeringame[pnum])
356                 break;
357     plr = &players[pnum];
358     oldplr.x = plr->mo->x;
359     oldplr.y = plr->mo->y;
360     m_x = plr->mo->x - m_w / 2;
361     m_y = plr->mo->y - m_h / 2;
362     AM_changeWindowLoc();
363 
364     // for saving & restoring
365     old_m_x = m_x;
366     old_m_y = m_y;
367     old_m_w = m_w;
368     old_m_h = m_h;
369 
370     // load in the location of keys, if in baby mode
371 
372     memset(KeyPoints, 0, sizeof(vertex_t) * 3);
373     if (gameskill == sk_baby)
374     {
375         for (think = thinkercap.next; think != &thinkercap;
376              think = think->next)
377         {
378             if (think->function != P_MobjThinker)
379             {                   //not a mobj
380                 continue;
381             }
382             mo = (mobj_t *) think;
383             if (mo->type == MT_CKEY)
384             {
385                 KeyPoints[0].x = mo->x;
386                 KeyPoints[0].y = mo->y;
387             }
388             else if (mo->type == MT_AKYY)
389             {
390                 KeyPoints[1].x = mo->x;
391                 KeyPoints[1].y = mo->y;
392             }
393             else if (mo->type == MT_BKYY)
394             {
395                 KeyPoints[2].x = mo->x;
396                 KeyPoints[2].y = mo->y;
397             }
398         }
399     }
400 
401     // inform the status bar of the change
402 //c  ST_Responder(&st_notify);
403 }
404 
AM_loadPics(void)405 void AM_loadPics(void)
406 {
407     //int i;
408     //char namebuf[9];
409 /*  for (i=0;i<10;i++)
410   {
411     M_snprintf(namebuf, sizeof(namebuf), "AMMNUM%d", i);
412     marknums[i] = W_CacheLumpName(namebuf, PU_STATIC);
413   }*/
414     maplump = W_CacheLumpName(DEH_String("AUTOPAGE"), PU_STATIC);
415 }
416 
417 /*void AM_unloadPics(void)
418 {
419   int i;
420   for (i=0;i<10;i++) Z_ChangeTag(marknums[i], PU_CACHE);
421 
422 }*/
423 
424 /*
425 void AM_clearMarks(void)
426 {
427   int i;
428   for (i=0;i<AM_NUMMARKPOINTS;i++) markpoints[i].x = -1; // means empty
429   markpointnum = 0;
430 }
431 */
432 
433 // should be called at the start of every level
434 // right now, i figure it out myself
435 
AM_LevelInit(void)436 void AM_LevelInit(void)
437 {
438     leveljuststarted = 0;
439 
440     finit_width = SCREENWIDTH;
441     finit_height = SCREENHEIGHT - (42 << crispy->hires);
442     f_x = f_y = 0;
443     f_w = finit_width;
444     f_h = finit_height;
445     mapxstart = mapystart = 0;
446 
447 
448 //  AM_clearMarks();
449 
450     AM_findMinMaxBoundaries();
451     scale_mtof = FixedDiv(min_scale_mtof, (int) (0.7 * FRACUNIT));
452     if (scale_mtof > max_scale_mtof)
453         scale_mtof = min_scale_mtof;
454     scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
455 }
456 
457 static boolean stopped = true;
458 
AM_Stop(void)459 void AM_Stop(void)
460 {
461     //static event_t st_notify = { 0, ev_keyup, AM_MSGEXITED };
462 
463 //  AM_unloadPics();
464     automapactive = false;
465 //  ST_Responder(&st_notify);
466     stopped = true;
467     BorderNeedRefresh = true;
468 }
469 
AM_Start(void)470 void AM_Start(void)
471 {
472     static int lastlevel = -1, lastepisode = -1;
473 
474     if (!stopped)
475         AM_Stop();
476     stopped = false;
477     if (gamestate != GS_LEVEL)
478     {
479         return;                 // don't show automap if we aren't in a game!
480     }
481     if (lastlevel != gamemap || lastepisode != gameepisode)
482     {
483         AM_LevelInit();
484         lastlevel = gamemap;
485         lastepisode = gameepisode;
486     }
487     AM_initVariables();
488     AM_loadPics();
489 }
490 
491 // set the window scale to the maximum size
492 
AM_minOutWindowScale(void)493 void AM_minOutWindowScale(void)
494 {
495     scale_mtof = min_scale_mtof;
496     scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
497     AM_activateNewScale();
498 }
499 
500 // set the window scale to the minimum size
501 
AM_maxOutWindowScale(void)502 void AM_maxOutWindowScale(void)
503 {
504     scale_mtof = max_scale_mtof;
505     scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
506     AM_activateNewScale();
507 }
508 
AM_Responder(event_t * ev)509 boolean AM_Responder(event_t * ev)
510 {
511     int rc;
512     int key;
513     static int bigstate = 0;
514     static int joywait = 0;
515 
516     key = ev->data1;
517     rc = false;
518 
519     if (ev->type == ev_joystick && joybautomap >= 0
520         && (ev->data1 & (1 << joybautomap)) != 0 && joywait < I_GetTime())
521     {
522         joywait = I_GetTime() + 5;
523 
524         if (!automapactive)
525         {
526             AM_Start ();
527             viewactive = false;
528         }
529         else
530         {
531             bigstate = 0;
532             viewactive = true;
533             AM_Stop ();
534         }
535     }
536 
537     if (!automapactive)
538     {
539 
540         if (ev->type == ev_keydown && key == key_map_toggle
541          && gamestate == GS_LEVEL)
542         {
543             AM_Start();
544             viewactive = false;
545             // viewactive = true;
546             rc = true;
547         }
548     }
549     else if (ev->type == ev_keydown)
550     {
551         rc = true;
552 
553         if (key == key_map_east)                 // pan right
554         {
555             if (!followplayer && !crispy->automapoverlay)
556                 m_paninc.x = FTOM(F_PANINC);
557             else
558                 rc = false;
559         }
560         else if (key == key_map_west)            // pan left
561         {
562             if (!followplayer && !crispy->automapoverlay)
563                 m_paninc.x = -FTOM(F_PANINC);
564             else
565                 rc = false;
566         }
567         else if (key == key_map_north)           // pan up
568         {
569             if (!followplayer && !crispy->automapoverlay)
570                 m_paninc.y = FTOM(F_PANINC);
571             else
572                 rc = false;
573         }
574         else if (key == key_map_south)           // pan down
575         {
576             if (!followplayer && !crispy->automapoverlay)
577                 m_paninc.y = -FTOM(F_PANINC);
578             else
579                 rc = false;
580         }
581         else if (key == key_map_zoomout)         // zoom out
582         {
583             mtof_zoommul = M_ZOOMOUT;
584             ftom_zoommul = M_ZOOMIN;
585         }
586         else if (key == key_map_zoomin)          // zoom in
587         {
588             mtof_zoommul = M_ZOOMIN;
589             ftom_zoommul = M_ZOOMOUT;
590         }
591         else if (key == key_map_toggle)          // toggle map (tab)
592         {
593             bigstate = 0;
594             viewactive = true;
595             AM_Stop();
596         }
597         else if (key == key_map_maxzoom)
598         {
599             bigstate = !bigstate;
600             if (bigstate)
601             {
602                 AM_saveScaleAndLoc();
603                 AM_minOutWindowScale();
604             }
605             else
606                 AM_restoreScaleAndLoc();
607         }
608         else if (key == key_map_follow)
609         {
610             followplayer = !followplayer;
611             f_oldloc.x = INT_MAX;
612             P_SetMessage(plr,
613                          followplayer ? AMSTR_FOLLOWON : AMSTR_FOLLOWOFF,
614                          true);
615         }
616         /*
617         else if (key == key_map_grid)
618         {
619             grid = !grid;
620             plr->message = grid ? AMSTR_GRIDON : AMSTR_GRIDOFF;
621         }
622         else if (key == key_map_mark)
623         {
624             M_snprintf(buffer, sizeof(buffer), "%s %d",
625                        AMSTR_MARKEDSPOT, markpointnum);
626             plr->message = buffer;
627             AM_addMark();
628         }
629         else if (key == key_map_clearmark)
630         {
631             AM_clearMarks();
632             plr->message = AMSTR_MARKSCLEARED;
633         }
634         */
635         else if (key == key_map_overlay)
636         {
637             // [crispy] force redraw status bar
638             UpdateState |= I_FULLSCRN;
639             SB_state = -1;
640 
641             crispy->automapoverlay = !crispy->automapoverlay;
642             if (crispy->automapoverlay)
643                 plr->message = DEH_String(AMSTR_OVERLAYON);
644             else
645                 plr->message = DEH_String(AMSTR_OVERLAYOFF);
646         }
647         else
648         {
649             rc = false;
650         }
651 
652         if (cheat_amap[cheatcount] == ev->data1 && !netgame)
653             cheatcount++;
654         else
655             cheatcount = 0;
656         if (cheatcount == 6)
657         {
658             cheatcount = 0;
659             rc = false;
660             cheating = (cheating + 1) % 3;
661         }
662     }
663 
664     else if (ev->type == ev_keyup)
665     {
666         rc = false;
667 
668         if (key == key_map_east)
669         {
670             if (!followplayer)
671                 m_paninc.x = 0;
672         }
673         else if (key == key_map_west)
674         {
675             if (!followplayer)
676                 m_paninc.x = 0;
677         }
678         else if (key == key_map_north)
679         {
680             if (!followplayer)
681                 m_paninc.y = 0;
682         }
683         else if (key == key_map_south)
684         {
685             if (!followplayer)
686                 m_paninc.y = 0;
687         }
688         else if (key == key_map_zoomout || key == key_map_zoomin)
689         {
690             mtof_zoommul = FRACUNIT;
691             ftom_zoommul = FRACUNIT;
692         }
693     }
694 
695     return rc;
696 
697 }
698 
AM_changeWindowScale(void)699 void AM_changeWindowScale(void)
700 {
701 
702     // Change the scaling multipliers
703     scale_mtof = FixedMul(scale_mtof, mtof_zoommul);
704     scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
705 
706     if (scale_mtof < min_scale_mtof)
707         AM_minOutWindowScale();
708     else if (scale_mtof > max_scale_mtof)
709         AM_maxOutWindowScale();
710     else
711         AM_activateNewScale();
712 }
713 
AM_doFollowPlayer(void)714 void AM_doFollowPlayer(void)
715 {
716     if (f_oldloc.x != plr->mo->x || f_oldloc.y != plr->mo->y)
717     {
718 //  m_x = FTOM(MTOF(plr->mo->x - m_w/2));
719 //  m_y = FTOM(MTOF(plr->mo->y - m_h/2));
720 //  m_x = plr->mo->x - m_w/2;
721 //  m_y = plr->mo->y - m_h/2;
722         m_x = FTOM(MTOF(plr->mo->x)) - m_w / 2;
723         m_y = FTOM(MTOF(plr->mo->y)) - m_h / 2;
724         m_x2 = m_x + m_w;
725         m_y2 = m_y + m_h;
726 
727         // do the parallax parchment scrolling.
728 /*
729 	 dmapx = (MTOF(plr->mo->x)-MTOF(f_oldloc.x)); //fixed point
730 	 dmapy = (MTOF(f_oldloc.y)-MTOF(plr->mo->y));
731 
732 	 if(f_oldloc.x == INT_MAX) //to eliminate an error when the user first
733 		dmapx=0;  //goes into the automap.
734 	 mapxstart += dmapx;
735 	 mapystart += dmapy;
736 
737   	 while(mapxstart >= finit_width)
738 			mapxstart -= finit_width;
739     while(mapxstart < 0)
740 			mapxstart += finit_width;
741     while(mapystart >= finit_height)
742 			mapystart -= finit_height;
743     while(mapystart < 0)
744 			mapystart += finit_height;
745 */
746         f_oldloc.x = plr->mo->x;
747         f_oldloc.y = plr->mo->y;
748     }
749 }
750 
751 // Ripped out for Heretic
752 /*
753 void AM_updateLightLev(void)
754 {
755   static nexttic = 0;
756 //static int litelevels[] = { 0, 3, 5, 6, 6, 7, 7, 7 };
757   static int litelevels[] = { 0, 4, 7, 10, 12, 14, 15, 15 };
758   static int litelevelscnt = 0;
759 
760   // Change light level
761   if (amclock>nexttic)
762   {
763     lightlev = litelevels[litelevelscnt++];
764     if (litelevelscnt == sizeof(litelevels)/sizeof(int)) litelevelscnt = 0;
765     nexttic = amclock + 6 - (amclock % 6);
766   }
767 }
768 */
769 
AM_Ticker(void)770 void AM_Ticker(void)
771 {
772 
773     if (!automapactive)
774         return;
775 
776     amclock++;
777 
778     if (followplayer)
779         AM_doFollowPlayer();
780 
781     // Change the zoom if necessary
782     if (ftom_zoommul != FRACUNIT)
783         AM_changeWindowScale();
784 
785     // Change x,y location
786     if (m_paninc.x || m_paninc.y)
787         AM_changeWindowLoc();
788     // Update light level
789 // AM_updateLightLev();
790 
791 }
792 
AM_clearFB(int color)793 void AM_clearFB(int color)
794 {
795     int i, j;
796     int dmapx;
797     int dmapy;
798 
799     if (followplayer)
800     {
801         dmapx = (MTOF(plr->mo->x) - MTOF(oldplr.x));    //fixed point
802         dmapy = (MTOF(oldplr.y) - MTOF(plr->mo->y));
803 
804         oldplr.x = plr->mo->x;
805         oldplr.y = plr->mo->y;
806 //              if(f_oldloc.x == INT_MAX) //to eliminate an error when the user first
807 //                      dmapx=0;  //goes into the automap.
808         mapxstart += dmapx >> 1;
809         mapystart += dmapy >> 1;
810 
811         while (mapxstart >= (finit_width >> crispy->hires))
812             mapxstart -= (finit_width >> crispy->hires);
813         while (mapxstart < 0)
814             mapxstart += (finit_width >> crispy->hires);
815         while (mapystart >= (finit_height >> crispy->hires))
816             mapystart -= (finit_height >> crispy->hires);
817         while (mapystart < 0)
818             mapystart += (finit_height >> crispy->hires);
819     }
820     else
821     {
822         // The released Heretic source does this here, but this causes a bug
823         // where the map background keeps moving when we reach the map
824         // boundaries. This is instead done in AM_changeWindowLoc.
825         /*
826         mapxstart += (MTOF(m_paninc.x) >> 1);
827         mapystart -= (MTOF(m_paninc.y) >> 1);
828 
829         if (mapxstart >= (finit_width >> crispy->hires))
830             mapxstart -= (finit_width >> crispy->hires);
831         if (mapxstart < 0)
832             mapxstart += (finit_width >> crispy->hires);
833         if (mapystart >= (finit_height >> crispy->hires))
834             mapystart -= (finit_height >> crispy->hires);
835         if (mapystart < 0)
836             mapystart += (finit_height >> crispy->hires);
837         */
838     }
839 
840     //blit the automap background to the screen.
841     j = (mapystart & ~crispy->hires) * (finit_width >> crispy->hires);
842     for (i = 0; i < finit_height; i++)
843     {
844         memcpy(I_VideoBuffer + i * finit_width, maplump + j + mapxstart,
845                finit_width - mapxstart);
846         memcpy(I_VideoBuffer + i * finit_width + finit_width - mapxstart,
847                maplump + j, mapxstart);
848         j += finit_width;
849         if (j >= (finit_height >> crispy->hires) * (finit_width >> crispy->hires))
850             j = 0;
851     }
852 
853 //       memcpy(I_VideoBuffer, maplump, finit_width*finit_height);
854 //  memset(fb, color, f_w*f_h);
855 }
856 
857 // Based on Cohen-Sutherland clipping algorithm but with a slightly
858 // faster reject and precalculated slopes.  If I need the speed, will
859 // hash algorithm to the common cases.
860 
AM_clipMline(mline_t * ml,fline_t * fl)861 boolean AM_clipMline(mline_t * ml, fline_t * fl)
862 {
863     enum
864     { LEFT = 1, RIGHT = 2, BOTTOM = 4, TOP = 8 };
865     int outcode1 = 0, outcode2 = 0, outside;
866     fpoint_t tmp = { 0, 0 };
867     int dx, dy;
868 
869 #define DOOUTCODE(oc, mx, my) \
870   (oc) = 0; \
871   if ((my) < 0) (oc) |= TOP; \
872   else if ((my) >= f_h) (oc) |= BOTTOM; \
873   if ((mx) < 0) (oc) |= LEFT; \
874   else if ((mx) >= f_w) (oc) |= RIGHT
875 
876     // do trivial rejects and outcodes
877     if (ml->a.y > m_y2)
878         outcode1 = TOP;
879     else if (ml->a.y < m_y)
880         outcode1 = BOTTOM;
881     if (ml->b.y > m_y2)
882         outcode2 = TOP;
883     else if (ml->b.y < m_y)
884         outcode2 = BOTTOM;
885     if (outcode1 & outcode2)
886         return false;           // trivially outside
887 
888     if (ml->a.x < m_x)
889         outcode1 |= LEFT;
890     else if (ml->a.x > m_x2)
891         outcode1 |= RIGHT;
892     if (ml->b.x < m_x)
893         outcode2 |= LEFT;
894     else if (ml->b.x > m_x2)
895         outcode2 |= RIGHT;
896     if (outcode1 & outcode2)
897         return false;           // trivially outside
898 
899     // transform to frame-buffer coordinates.
900     fl->a.x = CXMTOF(ml->a.x);
901     fl->a.y = CYMTOF(ml->a.y);
902     fl->b.x = CXMTOF(ml->b.x);
903     fl->b.y = CYMTOF(ml->b.y);
904     DOOUTCODE(outcode1, fl->a.x, fl->a.y);
905     DOOUTCODE(outcode2, fl->b.x, fl->b.y);
906     if (outcode1 & outcode2)
907         return false;
908 
909     while (outcode1 | outcode2)
910     {
911         // may be partially inside box
912         // find an outside point
913         if (outcode1)
914             outside = outcode1;
915         else
916             outside = outcode2;
917         // clip to each side
918         if (outside & TOP)
919         {
920             dy = fl->a.y - fl->b.y;
921             dx = fl->b.x - fl->a.x;
922             tmp.x = fl->a.x + (dx * (fl->a.y)) / dy;
923             tmp.y = 0;
924         }
925         else if (outside & BOTTOM)
926         {
927             dy = fl->a.y - fl->b.y;
928             dx = fl->b.x - fl->a.x;
929             tmp.x = fl->a.x + (dx * (fl->a.y - f_h)) / dy;
930             tmp.y = f_h - 1;
931         }
932         else if (outside & RIGHT)
933         {
934             dy = fl->b.y - fl->a.y;
935             dx = fl->b.x - fl->a.x;
936             tmp.y = fl->a.y + (dy * (f_w - 1 - fl->a.x)) / dx;
937             tmp.x = f_w - 1;
938         }
939         else if (outside & LEFT)
940         {
941             dy = fl->b.y - fl->a.y;
942             dx = fl->b.x - fl->a.x;
943             tmp.y = fl->a.y + (dy * (-fl->a.x)) / dx;
944             tmp.x = 0;
945         }
946         if (outside == outcode1)
947         {
948             fl->a = tmp;
949             DOOUTCODE(outcode1, fl->a.x, fl->a.y);
950         }
951         else
952         {
953             fl->b = tmp;
954             DOOUTCODE(outcode2, fl->b.x, fl->b.y);
955         }
956         if (outcode1 & outcode2)
957             return false;       // trivially outside
958     }
959 
960     return true;
961 }
962 
963 #undef DOOUTCODE
964 
965 // Classic Bresenham w/ whatever optimizations I need for speed
966 
AM_drawFline(fline_t * fl,int color)967 void AM_drawFline(fline_t * fl, int color)
968 {
969 
970     register int x, y, dx, dy, sx, sy, ax, ay, d;
971     static int fuck = 0;
972 
973     switch (color)
974     {
975         case WALLCOLORS:
976             DrawWuLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y, &antialias[0][0],
977                        8, 3);
978             break;
979         case FDWALLCOLORS:
980             DrawWuLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y, &antialias[1][0],
981                        8, 3);
982             break;
983         case CDWALLCOLORS:
984             DrawWuLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y, &antialias[2][0],
985                        8, 3);
986             break;
987         default:
988             {
989                 // For debugging only
990                 if (fl->a.x < 0 || fl->a.x >= f_w
991                     || fl->a.y < 0 || fl->a.y >= f_h
992                     || fl->b.x < 0 || fl->b.x >= f_w
993                     || fl->b.y < 0 || fl->b.y >= f_h)
994                 {
995                     fprintf(stderr, "fuck %d \r", fuck++);
996                     return;
997                 }
998 
999 #define DOT(xx,yy,cc) fb[(yy)*f_w+(xx)]=(cc)    //the MACRO!
1000 
1001                 dx = fl->b.x - fl->a.x;
1002                 ax = 2 * (dx < 0 ? -dx : dx);
1003                 sx = dx < 0 ? -1 : 1;
1004 
1005                 dy = fl->b.y - fl->a.y;
1006                 ay = 2 * (dy < 0 ? -dy : dy);
1007                 sy = dy < 0 ? -1 : 1;
1008 
1009                 x = fl->a.x;
1010                 y = fl->a.y;
1011 
1012                 if (ax > ay)
1013                 {
1014                     d = ay - ax / 2;
1015                     while (1)
1016                     {
1017                         DOT(x, y, color);
1018                         if (x == fl->b.x)
1019                             return;
1020                         if (d >= 0)
1021                         {
1022                             y += sy;
1023                             d -= ax;
1024                         }
1025                         x += sx;
1026                         d += ay;
1027                     }
1028                 }
1029                 else
1030                 {
1031                     d = ax - ay / 2;
1032                     while (1)
1033                     {
1034                         DOT(x, y, color);
1035                         if (y == fl->b.y)
1036                             return;
1037                         if (d >= 0)
1038                         {
1039                             x += sx;
1040                             d -= ay;
1041                         }
1042                         y += sy;
1043                         d += ax;
1044                     }
1045                 }
1046             }
1047     }
1048 }
1049 
1050 /* Wu antialiased line drawer.
1051  * (X0,Y0),(X1,Y1) = line to draw
1052  * BaseColor = color # of first color in block used for antialiasing, the
1053  *          100% intensity version of the drawing color
1054  * NumLevels = size of color block, with BaseColor+NumLevels-1 being the
1055  *          0% intensity version of the drawing color
1056  * IntensityBits = log base 2 of NumLevels; the # of bits used to describe
1057  *          the intensity of the drawing color. 2**IntensityBits==NumLevels
1058  */
PUTDOT(short xx,short yy,byte * cc,byte * cm)1059 void PUTDOT(short xx, short yy, byte * cc, byte * cm)
1060 {
1061     static int oldyy;
1062     static int oldyyshifted;
1063     byte *oldcc = cc;
1064 
1065     if (xx < 32)
1066         cc += 7 - (xx >> 2);
1067     else if (xx > (finit_width - 32))
1068         cc += 7 - ((finit_width - xx) >> 2);
1069 //      if(cc==oldcc) //make sure that we don't double fade the corners.
1070 //      {
1071     if (yy < 32)
1072         cc += 7 - (yy >> 2);
1073     else if (yy > (finit_height - 32))
1074         cc += 7 - ((finit_height - yy) >> 2);
1075 //      }
1076     if (cc > cm && cm != NULL)
1077     {
1078         cc = cm;
1079     }
1080     else if (cc > oldcc + 6)    // don't let the color escape from the fade table...
1081     {
1082         cc = oldcc + 6;
1083     }
1084     if (yy == oldyy + 1)
1085     {
1086         oldyy++;
1087         oldyyshifted += (320 << crispy->hires);
1088     }
1089     else if (yy == oldyy - 1)
1090     {
1091         oldyy--;
1092         oldyyshifted -= (320 << crispy->hires);
1093     }
1094     else if (yy != oldyy)
1095     {
1096         oldyy = yy;
1097         oldyyshifted = yy * (320 << crispy->hires);
1098     }
1099     fb[oldyyshifted + xx] = *(cc);
1100 //      fb[(yy)*f_w+(xx)]=*(cc);
1101 }
1102 
DrawWuLine(int X0,int Y0,int X1,int Y1,byte * BaseColor,int NumLevels,unsigned short IntensityBits)1103 void DrawWuLine(int X0, int Y0, int X1, int Y1, byte * BaseColor,
1104                 int NumLevels, unsigned short IntensityBits)
1105 {
1106     unsigned short IntensityShift, ErrorAdj, ErrorAcc;
1107     unsigned short ErrorAccTemp, Weighting, WeightingComplementMask;
1108     short DeltaX, DeltaY, Temp, XDir;
1109 
1110     /* Make sure the line runs top to bottom */
1111     if (Y0 > Y1)
1112     {
1113         Temp = Y0;
1114         Y0 = Y1;
1115         Y1 = Temp;
1116         Temp = X0;
1117         X0 = X1;
1118         X1 = Temp;
1119     }
1120     /* Draw the initial pixel, which is always exactly intersected by
1121        the line and so needs no weighting */
1122     PUTDOT(X0, Y0, &BaseColor[0], NULL);
1123 
1124     if ((DeltaX = X1 - X0) >= 0)
1125     {
1126         XDir = 1;
1127     }
1128     else
1129     {
1130         XDir = -1;
1131         DeltaX = -DeltaX;       /* make DeltaX positive */
1132     }
1133     /* Special-case horizontal, vertical, and diagonal lines, which
1134        require no weighting because they go right through the center of
1135        every pixel */
1136     if ((DeltaY = Y1 - Y0) == 0)
1137     {
1138         /* Horizontal line */
1139         while (DeltaX-- != 0)
1140         {
1141             X0 += XDir;
1142             PUTDOT(X0, Y0, &BaseColor[0], NULL);
1143         }
1144         return;
1145     }
1146     if (DeltaX == 0)
1147     {
1148         /* Vertical line */
1149         do
1150         {
1151             Y0++;
1152             PUTDOT(X0, Y0, &BaseColor[0], NULL);
1153         }
1154         while (--DeltaY != 0);
1155         return;
1156     }
1157     //diagonal line.
1158     if (DeltaX == DeltaY)
1159     {
1160         do
1161         {
1162             X0 += XDir;
1163             Y0++;
1164             PUTDOT(X0, Y0, &BaseColor[0], NULL);
1165         }
1166         while (--DeltaY != 0);
1167         return;
1168     }
1169     /* Line is not horizontal, diagonal, or vertical */
1170     ErrorAcc = 0;               /* initialize the line error accumulator to 0 */
1171     /* # of bits by which to shift ErrorAcc to get intensity level */
1172     IntensityShift = 16 - IntensityBits;
1173     /* Mask used to flip all bits in an intensity weighting, producing the
1174        result (1 - intensity weighting) */
1175     WeightingComplementMask = NumLevels - 1;
1176     /* Is this an X-major or Y-major line? */
1177     if (DeltaY > DeltaX)
1178     {
1179         /* Y-major line; calculate 16-bit fixed-point fractional part of a
1180            pixel that X advances each time Y advances 1 pixel, truncating the
1181            result so that we won't overrun the endpoint along the X axis */
1182         ErrorAdj = ((unsigned int) DeltaX << 16) / (unsigned int) DeltaY;
1183         /* Draw all pixels other than the first and last */
1184         while (--DeltaY)
1185         {
1186             ErrorAccTemp = ErrorAcc;    /* remember currrent accumulated error */
1187             ErrorAcc += ErrorAdj;       /* calculate error for next pixel */
1188             if (ErrorAcc <= ErrorAccTemp)
1189             {
1190                 /* The error accumulator turned over, so advance the X coord */
1191                 X0 += XDir;
1192             }
1193             Y0++;               /* Y-major, so always advance Y */
1194             /* The IntensityBits most significant bits of ErrorAcc give us the
1195                intensity weighting for this pixel, and the complement of the
1196                weighting for the paired pixel */
1197             Weighting = ErrorAcc >> IntensityShift;
1198             PUTDOT(X0, Y0, &BaseColor[Weighting], &BaseColor[7]);
1199             PUTDOT(X0 + XDir, Y0,
1200                    &BaseColor[(Weighting ^ WeightingComplementMask)],
1201                    &BaseColor[7]);
1202         }
1203         /* Draw the final pixel, which is always exactly intersected by the line
1204            and so needs no weighting */
1205         PUTDOT(X1, Y1, &BaseColor[0], NULL);
1206         return;
1207     }
1208     /* It's an X-major line; calculate 16-bit fixed-point fractional part of a
1209        pixel that Y advances each time X advances 1 pixel, truncating the
1210        result to avoid overrunning the endpoint along the X axis */
1211     ErrorAdj = ((unsigned int) DeltaY << 16) / (unsigned int) DeltaX;
1212     /* Draw all pixels other than the first and last */
1213     while (--DeltaX)
1214     {
1215         ErrorAccTemp = ErrorAcc;        /* remember currrent accumulated error */
1216         ErrorAcc += ErrorAdj;   /* calculate error for next pixel */
1217         if (ErrorAcc <= ErrorAccTemp)
1218         {
1219             /* The error accumulator turned over, so advance the Y coord */
1220             Y0++;
1221         }
1222         X0 += XDir;             /* X-major, so always advance X */
1223         /* The IntensityBits most significant bits of ErrorAcc give us the
1224            intensity weighting for this pixel, and the complement of the
1225            weighting for the paired pixel */
1226         Weighting = ErrorAcc >> IntensityShift;
1227         PUTDOT(X0, Y0, &BaseColor[Weighting], &BaseColor[7]);
1228         PUTDOT(X0, Y0 + 1,
1229                &BaseColor[(Weighting ^ WeightingComplementMask)],
1230                &BaseColor[7]);
1231 
1232     }
1233     /* Draw the final pixel, which is always exactly intersected by the line
1234        and so needs no weighting */
1235     PUTDOT(X1, Y1, &BaseColor[0], NULL);
1236 }
1237 
AM_drawMline(mline_t * ml,int color)1238 void AM_drawMline(mline_t * ml, int color)
1239 {
1240     static fline_t fl;
1241 
1242     if (AM_clipMline(ml, &fl))
1243         AM_drawFline(&fl, color);       // draws it on frame buffer using fb coords
1244 
1245 }
1246 
AM_drawGrid(int color)1247 void AM_drawGrid(int color)
1248 {
1249     fixed_t x, y;
1250     fixed_t start, end;
1251     mline_t ml;
1252 
1253     // Figure out start of vertical gridlines
1254     start = m_x;
1255     if ((start - bmaporgx) % (MAPBLOCKUNITS << FRACBITS))
1256         start += (MAPBLOCKUNITS << FRACBITS)
1257             - ((start - bmaporgx) % (MAPBLOCKUNITS << FRACBITS));
1258     end = m_x + m_w;
1259 
1260     // draw vertical gridlines
1261     ml.a.y = m_y;
1262     ml.b.y = m_y + m_h;
1263     for (x = start; x < end; x += (MAPBLOCKUNITS << FRACBITS))
1264     {
1265         ml.a.x = x;
1266         ml.b.x = x;
1267         AM_drawMline(&ml, color);
1268     }
1269 
1270     // Figure out start of horizontal gridlines
1271     start = m_y;
1272     if ((start - bmaporgy) % (MAPBLOCKUNITS << FRACBITS))
1273         start += (MAPBLOCKUNITS << FRACBITS)
1274             - ((start - bmaporgy) % (MAPBLOCKUNITS << FRACBITS));
1275     end = m_y + m_h;
1276 
1277     // draw horizontal gridlines
1278     ml.a.x = m_x;
1279     ml.b.x = m_x + m_w;
1280     for (y = start; y < end; y += (MAPBLOCKUNITS << FRACBITS))
1281     {
1282         ml.a.y = y;
1283         ml.b.y = y;
1284         AM_drawMline(&ml, color);
1285     }
1286 }
1287 
AM_drawWalls(void)1288 void AM_drawWalls(void)
1289 {
1290     int i;
1291     static mline_t l;
1292 
1293     for (i = 0; i < numlines; i++)
1294     {
1295         l.a.x = lines[i].v1->x;
1296         l.a.y = lines[i].v1->y;
1297         l.b.x = lines[i].v2->x;
1298         l.b.y = lines[i].v2->y;
1299         if (cheating || (lines[i].flags & ML_MAPPED))
1300         {
1301             if ((lines[i].flags & LINE_NEVERSEE) && !cheating)
1302                 continue;
1303             if (!lines[i].backsector)
1304             {
1305                 AM_drawMline(&l, WALLCOLORS + lightlev);
1306             }
1307             else
1308             {
1309                 if (lines[i].special == 39)
1310                 {               // teleporters
1311                     AM_drawMline(&l, WALLCOLORS + WALLRANGE / 2);
1312                 }
1313                 else if (lines[i].flags & ML_SECRET)    // secret door
1314                 {
1315                     if (cheating)
1316                         AM_drawMline(&l, 0);
1317                     else
1318                         AM_drawMline(&l, WALLCOLORS + lightlev);
1319                 }
1320                 else if (lines[i].special > 25 && lines[i].special < 35)
1321                 {
1322                     switch (lines[i].special)
1323                     {
1324                         case 26:
1325                         case 32:
1326                             AM_drawMline(&l, BLUEKEY);
1327                             break;
1328                         case 27:
1329                         case 34:
1330                             AM_drawMline(&l, YELLOWKEY);
1331                             break;
1332                         case 28:
1333                         case 33:
1334                             AM_drawMline(&l, GREENKEY);
1335                             break;
1336                         default:
1337                             break;
1338                     }
1339                 }
1340                 else if (lines[i].backsector->floorheight
1341                          != lines[i].frontsector->floorheight)
1342                 {
1343                     AM_drawMline(&l, FDWALLCOLORS + lightlev);  // floor level change
1344                 }
1345                 else if (lines[i].backsector->ceilingheight
1346                          != lines[i].frontsector->ceilingheight)
1347                 {
1348                     AM_drawMline(&l, CDWALLCOLORS + lightlev);  // ceiling level change
1349                 }
1350                 else if (cheating)
1351                 {
1352                     AM_drawMline(&l, TSWALLCOLORS + lightlev);
1353                 }
1354             }
1355         }
1356         else if (plr->powers[pw_allmap])
1357         {
1358             if (!(lines[i].flags & LINE_NEVERSEE))
1359                 AM_drawMline(&l, GRAYS + 3);
1360         }
1361     }
1362 
1363 }
1364 
AM_rotate(fixed_t * x,fixed_t * y,angle_t a)1365 void AM_rotate(fixed_t * x, fixed_t * y, angle_t a)
1366 {
1367     fixed_t tmpx;
1368 
1369     tmpx = FixedMul(*x, finecosine[a >> ANGLETOFINESHIFT])
1370         - FixedMul(*y, finesine[a >> ANGLETOFINESHIFT]);
1371     *y = FixedMul(*x, finesine[a >> ANGLETOFINESHIFT])
1372         + FixedMul(*y, finecosine[a >> ANGLETOFINESHIFT]);
1373     *x = tmpx;
1374 }
1375 
AM_drawLineCharacter(mline_t * lineguy,int lineguylines,fixed_t scale,angle_t angle,int color,fixed_t x,fixed_t y)1376 void AM_drawLineCharacter(mline_t * lineguy, int lineguylines, fixed_t scale,
1377                           angle_t angle, int color, fixed_t x, fixed_t y)
1378 {
1379     int i;
1380     mline_t l;
1381 
1382     for (i = 0; i < lineguylines; i++)
1383     {
1384         l.a.x = lineguy[i].a.x;
1385         l.a.y = lineguy[i].a.y;
1386         if (scale)
1387         {
1388             l.a.x = FixedMul(scale, l.a.x);
1389             l.a.y = FixedMul(scale, l.a.y);
1390         }
1391         if (angle)
1392             AM_rotate(&l.a.x, &l.a.y, angle);
1393         l.a.x += x;
1394         l.a.y += y;
1395 
1396         l.b.x = lineguy[i].b.x;
1397         l.b.y = lineguy[i].b.y;
1398         if (scale)
1399         {
1400             l.b.x = FixedMul(scale, l.b.x);
1401             l.b.y = FixedMul(scale, l.b.y);
1402         }
1403         if (angle)
1404             AM_rotate(&l.b.x, &l.b.y, angle);
1405         l.b.x += x;
1406         l.b.y += y;
1407 
1408         AM_drawMline(&l, color);
1409     }
1410 
1411 }
1412 
AM_drawPlayers(void)1413 void AM_drawPlayers(void)
1414 {
1415 
1416     int i;
1417     player_t *p;
1418     static int their_colors[] = { GREENKEY, YELLOWKEY, BLOODRED, BLUEKEY };
1419     int their_color = -1;
1420     int color;
1421 
1422     if (!netgame)
1423     {
1424         /*
1425            if (cheating) AM_drawLineCharacter(cheat_player_arrow, NUMCHEATPLYRLINES, 0,
1426            plr->mo->angle, WHITE, plr->mo->x, plr->mo->y);
1427          *///cheat key player pointer is the same as non-cheat pointer..
1428 
1429         AM_drawLineCharacter(player_arrow, NUMPLYRLINES, 0, plr->mo->angle,
1430                              WHITE, plr->mo->x, plr->mo->y);
1431         return;
1432     }
1433 
1434     for (i = 0; i < MAXPLAYERS; i++)
1435     {
1436         their_color++;
1437         p = &players[i];
1438         if (deathmatch && !singledemo && p != plr)
1439         {
1440             continue;
1441         }
1442         if (!playeringame[i])
1443             continue;
1444         if (p->powers[pw_invisibility])
1445             color = 102;        // *close* to the automap color
1446         else
1447             color = their_colors[their_color];
1448         AM_drawLineCharacter(player_arrow, NUMPLYRLINES, 0, p->mo->angle,
1449                              color, p->mo->x, p->mo->y);
1450     }
1451 }
1452 
AM_drawThings(int colors,int colorrange)1453 void AM_drawThings(int colors, int colorrange)
1454 {
1455     int i;
1456     mobj_t *t;
1457 
1458     for (i = 0; i < numsectors; i++)
1459     {
1460         t = sectors[i].thinglist;
1461         while (t)
1462         {
1463             AM_drawLineCharacter(thintriangle_guy, NUMTHINTRIANGLEGUYLINES,
1464                                  16 << FRACBITS, t->angle, colors + lightlev,
1465                                  t->x, t->y);
1466             t = t->snext;
1467         }
1468     }
1469 }
1470 
1471 /*
1472 void AM_drawMarks(void)
1473 {
1474   int i, fx, fy, w, h;
1475 
1476   for (i=0;i<AM_NUMMARKPOINTS;i++)
1477   {
1478     if (markpoints[i].x != -1)
1479     {
1480       w = SHORT(marknums[i]->width);
1481       h = SHORT(marknums[i]->height);
1482       fx = CXMTOF(markpoints[i].x);
1483       fy = CYMTOF(markpoints[i].y);
1484       if (fx >= f_x && fx <= f_w - w && fy >= f_y && fy <= f_h - h)
1485   			V_DrawPatch(fx, fy, marknums[i]);
1486     }
1487   }
1488 }
1489 */
1490 
AM_drawkeys(void)1491 void AM_drawkeys(void)
1492 {
1493     if (KeyPoints[0].x != 0 || KeyPoints[0].y != 0)
1494     {
1495         AM_drawLineCharacter(keysquare, NUMKEYSQUARELINES, 0, 0, YELLOWKEY,
1496                              KeyPoints[0].x, KeyPoints[0].y);
1497     }
1498     if (KeyPoints[1].x != 0 || KeyPoints[1].y != 0)
1499     {
1500         AM_drawLineCharacter(keysquare, NUMKEYSQUARELINES, 0, 0, GREENKEY,
1501                              KeyPoints[1].x, KeyPoints[1].y);
1502     }
1503     if (KeyPoints[2].x != 0 || KeyPoints[2].y != 0)
1504     {
1505         AM_drawLineCharacter(keysquare, NUMKEYSQUARELINES, 0, 0, BLUEKEY,
1506                              KeyPoints[2].x, KeyPoints[2].y);
1507     }
1508 }
1509 
AM_drawCrosshair(int color)1510 void AM_drawCrosshair(int color)
1511 {
1512     fb[(f_w * (f_h + 1)) / 2] = color;  // single point for now
1513 }
1514 
AM_Drawer(void)1515 void AM_Drawer(void)
1516 {
1517     const char *level_name;
1518     int numepisodes;
1519 
1520     if (!automapactive)
1521         return;
1522 
1523     UpdateState |= I_FULLSCRN;
1524     if (!crispy->automapoverlay)
1525     {
1526     AM_clearFB(BACKGROUND);
1527     }
1528     if (grid)
1529         AM_drawGrid(GRIDCOLORS);
1530     AM_drawWalls();
1531     AM_drawPlayers();
1532     if (cheating == 2)
1533         AM_drawThings(THINGCOLORS, THINGRANGE);
1534 //  AM_drawCrosshair(XHAIRCOLORS);
1535 
1536 //  AM_drawMarks();
1537     if (gameskill == sk_baby)
1538     {
1539         AM_drawkeys();
1540     }
1541 
1542     if (gamemode == retail)
1543     {
1544         numepisodes = 5;
1545     }
1546     else
1547     {
1548         numepisodes = 3;
1549     }
1550 
1551     if (gameepisode <= numepisodes && gamemap < 10)
1552     {
1553         level_name = LevelNames[(gameepisode - 1) * 9 + gamemap - 1];
1554         MN_DrTextA(DEH_String(level_name), 20, 145);
1555     }
1556 //  I_Update();
1557 //  V_MarkRect(f_x, f_y, f_w, f_h);
1558 }
1559