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