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