osezer patch 008
[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     else /* avoid compiler warning */
775     {
776       tmp.x = 0;
777       tmp.y = 0;
778     }
779     if (outside == outcode1)
780     {
781       fl->a = tmp;
782       DOOUTCODE(outcode1, fl->a.x, fl->a.y);
783     } else {
784       fl->b = tmp;
785       DOOUTCODE(outcode2, fl->b.x, fl->b.y);
786     }
787     if (outcode1 & outcode2) return false; // trivially outside
788   }
789
790   return true;
791 }
792 #undef DOOUTCODE
793
794 // Classic Bresenham w/ whatever optimizations I need for speed
795
796 void AM_drawFline(fline_t *fl, int color)
797 {
798         register int x, y, dx, dy, sx, sy, ax, ay, d;
799         //static fuck = 0;
800
801         switch(color)
802         {
803                 case WALLCOLORS:
804                         DrawWuLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y,
805                                 &antialias[0][0], 8, 3);
806                         break;
807                 case FDWALLCOLORS:
808                         DrawWuLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y,
809                                 &antialias[1][0], 8, 3);
810                         break;
811                 case CDWALLCOLORS:
812                         DrawWuLine(fl->a.x, fl->a.y, fl->b.x, fl->b.y,
813                                 &antialias[2][0], 8, 3);
814                         break;
815                 default:
816                 {
817                                 // For debugging only
818                                 if (   fl->a.x < 0 || fl->a.x >= f_w
819                                 || fl->a.y < 0 || fl->a.y >= f_h
820                                 || fl->b.x < 0 || fl->b.x >= f_w
821                                 || fl->b.y < 0 || fl->b.y >= f_h)
822                                 {
823                                 //fprintf(stderr, "fuck %d \r", fuck++);
824                                 return;
825                                 }
826
827                                 #define DOT(xx,yy,cc) fb[(yy)*f_w+(xx)]=(cc) //the MACRO!
828
829                                 dx = fl->b.x - fl->a.x;
830                                 ax = 2 * (dx<0 ? -dx : dx);
831                                 sx = dx<0 ? -1 : 1;
832
833                                 dy = fl->b.y - fl->a.y;
834                                 ay = 2 * (dy<0 ? -dy : dy);
835                                 sy = dy<0 ? -1 : 1;
836
837                                 x = fl->a.x;
838                                 y = fl->a.y;
839
840                                 if (ax > ay)
841                                 {
842                                 d = ay - ax/2;
843                                 while (1)
844                                 {
845                                 DOT(x,y,color);
846                                 if (x == fl->b.x) return;
847                                 if (d>=0)
848                                 {
849                                         y += sy;
850                                         d -= ax;
851                                 }
852                                 x += sx;
853                                 d += ay;
854                                 }
855                                 } else {
856                                 d = ax - ay/2;
857                                 while (1)
858                                 {
859                                 DOT(x, y, color);
860                                 if (y == fl->b.y) return;
861                                 if (d >= 0)
862                                 {
863                                         x += sx;
864                                         d -= ay;
865                                 }
866                                 y += sy;
867                                 d += ax;
868                                 }
869                                 }
870                 }
871   }
872 }
873
874 /* Wu antialiased line drawer.
875  * (X0,Y0),(X1,Y1) = line to draw
876  * BaseColor = color # of first color in block used for antialiasing, the
877  *          100% intensity version of the drawing color
878  * NumLevels = size of color block, with BaseColor+NumLevels-1 being the
879  *          0% intensity version of the drawing color
880  * IntensityBits = log base 2 of NumLevels; the # of bits used to describe
881  *          the intensity of the drawing color. 2**IntensityBits==NumLevels
882  */
883 void PUTDOT(short xx,short yy,byte *cc, byte *cm)
884 {
885         static int oldyy;
886         static int oldyyshifted;
887         byte *oldcc=cc;
888
889         if(xx < 32)
890                 cc += 7-(xx>>2);
891         else if(xx > (finit_width - 32))
892                 cc += 7-((finit_width-xx) >> 2);
893 //      if(cc==oldcc) //make sure that we don't double fade the corners.
894 //      {
895                 if(yy < 32)
896                         cc += 7-(yy>>2);
897                 else if(yy > (finit_height - 32))
898                         cc += 7-((finit_height-yy) >> 2);
899 //      }
900         if(cc > cm && cm != NULL)
901         {
902                 cc = cm;
903         }
904         else if(cc > oldcc+6) // don't let the color escape from the fade table...
905         {
906                 cc=oldcc+6;
907         }
908         if(yy == oldyy+1)
909         {
910                 oldyy++;
911                 oldyyshifted += 320;
912         }
913         else if(yy == oldyy-1)
914         {
915                 oldyy--;
916                 oldyyshifted -= 320;
917         }
918         else if(yy != oldyy)
919         {
920                 oldyy = yy;
921                 oldyyshifted = yy*320;
922         }
923         fb[oldyyshifted+xx] = *(cc);
924 //      fb[(yy)*f_w+(xx)]=*(cc);
925 }
926
927 void DrawWuLine(int X0, int Y0, int X1, int Y1, byte *BaseColor,
928         int NumLevels, unsigned short IntensityBits)
929 {
930    unsigned short IntensityShift, ErrorAdj, ErrorAcc;
931    unsigned short ErrorAccTemp, Weighting, WeightingComplementMask;
932    short DeltaX, DeltaY, Temp, XDir;
933
934    /* Make sure the line runs top to bottom */
935    if (Y0 > Y1) {
936       Temp = Y0; Y0 = Y1; Y1 = Temp;
937       Temp = X0; X0 = X1; X1 = Temp;
938    }
939    /* Draw the initial pixel, which is always exactly intersected by
940       the line and so needs no weighting */
941    PUTDOT(X0, Y0, &BaseColor[0], NULL);
942
943    if ((DeltaX = X1 - X0) >= 0) {
944       XDir = 1;
945    } else {
946       XDir = -1;
947       DeltaX = -DeltaX; /* make DeltaX positive */
948    }
949    /* Special-case horizontal, vertical, and diagonal lines, which
950       require no weighting because they go right through the center of
951       every pixel */
952    if ((DeltaY = Y1 - Y0) == 0) {
953       /* Horizontal line */
954       while (DeltaX-- != 0) {
955          X0 += XDir;
956          PUTDOT(X0, Y0, &BaseColor[0], NULL);
957       }
958       return;
959    }
960    if (DeltaX == 0) {
961       /* Vertical line */
962       do {
963          Y0++;
964          PUTDOT(X0, Y0, &BaseColor[0], NULL);
965       } while (--DeltaY != 0);
966       return;
967    }
968         //diagonal line.
969         if (DeltaX == DeltaY) {
970       do {
971          X0 += XDir;
972          Y0++;
973          PUTDOT(X0, Y0, &BaseColor[0], NULL);
974       } while (--DeltaY != 0);
975       return;
976    }
977    /* Line is not horizontal, diagonal, or vertical */
978    ErrorAcc = 0;  /* initialize the line error accumulator to 0 */
979    /* # of bits by which to shift ErrorAcc to get intensity level */
980    IntensityShift = 16 - IntensityBits;
981    /* Mask used to flip all bits in an intensity weighting, producing the
982       result (1 - intensity weighting) */
983    WeightingComplementMask = NumLevels - 1;
984    /* Is this an X-major or Y-major line? */
985    if (DeltaY > DeltaX) {
986       /* Y-major line; calculate 16-bit fixed-point fractional part of a
987          pixel that X advances each time Y advances 1 pixel, truncating the
988          result so that we won't overrun the endpoint along the X axis */
989       ErrorAdj = ((unsigned long) DeltaX << 16) / (unsigned long) DeltaY;
990       /* Draw all pixels other than the first and last */
991       while (--DeltaY) {
992          ErrorAccTemp = ErrorAcc;   /* remember currrent accumulated error */
993          ErrorAcc += ErrorAdj;      /* calculate error for next pixel */
994          if (ErrorAcc <= ErrorAccTemp) {
995             /* The error accumulator turned over, so advance the X coord */
996             X0 += XDir;
997          }
998          Y0++; /* Y-major, so always advance Y */
999          /* The IntensityBits most significant bits of ErrorAcc give us the
1000             intensity weighting for this pixel, and the complement of the
1001             weighting for the paired pixel */
1002          Weighting = ErrorAcc >> IntensityShift;
1003                         PUTDOT(X0, Y0, &BaseColor[Weighting], &BaseColor[7]);
1004          PUTDOT(X0 + XDir, Y0,
1005                &BaseColor[(Weighting ^ WeightingComplementMask)], &BaseColor[7]);
1006       }
1007       /* Draw the final pixel, which is always exactly intersected by the line
1008          and so needs no weighting */
1009       PUTDOT(X1, Y1, &BaseColor[0], NULL);
1010       return;
1011    }
1012    /* It's an X-major line; calculate 16-bit fixed-point fractional part of a
1013       pixel that Y advances each time X advances 1 pixel, truncating the
1014       result to avoid overrunning the endpoint along the X axis */
1015    ErrorAdj = ((unsigned long) DeltaY << 16) / (unsigned long) DeltaX;
1016    /* Draw all pixels other than the first and last */
1017    while (--DeltaX) {
1018       ErrorAccTemp = ErrorAcc;   /* remember currrent accumulated error */
1019       ErrorAcc += ErrorAdj;      /* calculate error for next pixel */
1020       if (ErrorAcc <= ErrorAccTemp) {
1021          /* The error accumulator turned over, so advance the Y coord */
1022          Y0++;
1023       }
1024       X0 += XDir; /* X-major, so always advance X */
1025       /* The IntensityBits most significant bits of ErrorAcc give us the
1026          intensity weighting for this pixel, and the complement of the
1027          weighting for the paired pixel */
1028       Weighting = ErrorAcc >> IntensityShift;
1029       PUTDOT(X0, Y0, &BaseColor[Weighting], &BaseColor[7]);
1030       PUTDOT(X0, Y0 + 1,
1031                 &BaseColor[(Weighting ^ WeightingComplementMask)], &BaseColor[7]);
1032
1033    }
1034    /* Draw the final pixel, which is always exactly intersected by the line
1035       and so needs no weighting */
1036    PUTDOT(X1, Y1, &BaseColor[0], NULL);
1037 }
1038
1039 void AM_drawMline(mline_t *ml, int color)
1040 {
1041 #ifdef RENDER3D
1042     byte *palette = W_CacheLumpName("playpal", PU_CACHE);
1043     byte r = palette[color*3], g = palette[color*3+1], b = palette[color*3+2];
1044  
1045     OGL_DrawLine( FIX2FLT(CXMTOFX(ml->a.x)), FIX2FLT(CYMTOFX(ml->a.y))/1.2,
1046                   FIX2FLT(CXMTOFX(ml->b.x)), FIX2FLT(CYMTOFX(ml->b.y))/1.2,
1047                   r/255.0, g/255.0, b/255.0, 1 );
1048 #else
1049   static fline_t fl;
1050
1051   if (AM_clipMline(ml, &fl))
1052     AM_drawFline(&fl, color); // draws it on frame buffer using fb coords
1053 #endif
1054 }
1055
1056 void AM_drawGrid(int color)
1057 {
1058   fixed_t x, y;
1059   fixed_t start, end;
1060   mline_t ml;
1061
1062   // Figure out start of vertical gridlines
1063   start = m_x;
1064   if ((start-bmaporgx)%(MAPBLOCKUNITS<<FRACBITS))
1065     start += (MAPBLOCKUNITS<<FRACBITS)
1066       - ((start-bmaporgx)%(MAPBLOCKUNITS<<FRACBITS));
1067   end = m_x + m_w;
1068
1069   // draw vertical gridlines
1070   ml.a.y = m_y;
1071   ml.b.y = m_y+m_h;
1072   for (x=start; x<end; x+=(MAPBLOCKUNITS<<FRACBITS))
1073   {
1074     ml.a.x = x;
1075     ml.b.x = x;
1076     AM_drawMline(&ml, color);
1077   }
1078
1079   // Figure out start of horizontal gridlines
1080   start = m_y;
1081   if ((start-bmaporgy)%(MAPBLOCKUNITS<<FRACBITS))
1082     start += (MAPBLOCKUNITS<<FRACBITS)
1083       - ((start-bmaporgy)%(MAPBLOCKUNITS<<FRACBITS));
1084   end = m_y + m_h;
1085
1086   // draw horizontal gridlines
1087   ml.a.x = m_x;
1088   ml.b.x = m_x + m_w;
1089   for (y=start; y<end; y+=(MAPBLOCKUNITS<<FRACBITS))
1090   {
1091     ml.a.y = y;
1092     ml.b.y = y;
1093     AM_drawMline(&ml, color);
1094   }
1095 }
1096
1097 void AM_drawWalls(void)
1098 {
1099   int i;
1100
1101 #ifdef RENDER3D
1102     //OGL_SetNoTexture();
1103     glDisable( GL_TEXTURE_2D );
1104
1105     glLineWidth(2.5); 
1106     glBegin(GL_LINES);  // We'll draw pretty much all of them.
1107     for(i=0;i<numlines;i++)
1108     {
1109         if (cheating || (lines[i].flags & ML_MAPPED))
1110         {
1111             if ((lines[i].flags & LINE_NEVERSEE) && !cheating)
1112                 continue;
1113             if (!lines[i].backsector)
1114             {
1115                 OGL_SetColor(WALLCOLORS);
1116             }
1117             else
1118             {
1119                 if (lines[i].flags & ML_SECRET) // secret door
1120                 {
1121                     if (cheating) //AM_drawMline(&l, 0);
1122                         OGL_SetColor(0);
1123                     else
1124                         OGL_SetColor(WALLCOLORS);
1125                 }
1126                 else if(lines[i].special == 13 || lines[i].special == 83)
1127                 { // Locked door line -- all locked doors are greed
1128                     OGL_SetColor(GREENKEY);
1129                 }
1130                 else if(lines[i].special == 70 || lines[i].special == 71)
1131                 { // intra-level teleports are blue
1132                     OGL_SetColor(BLUEKEY);
1133                 }
1134                 else if(lines[i].special == 74 || lines[i].special == 75)
1135                 { // inter-level teleport/game-winning exit -- both are red
1136                     OGL_SetColor(BLOODRED);
1137                 }
1138                 else if (lines[i].backsector->floorheight
1139                     != lines[i].frontsector->floorheight)
1140                 {
1141                     // floor level change
1142                     OGL_SetColor(FDWALLCOLORS);
1143                 }
1144                 else if (lines[i].backsector->ceilingheight
1145                     != lines[i].frontsector->ceilingheight)
1146                 {
1147                     // ceiling level change
1148                     OGL_SetColor(CDWALLCOLORS);
1149                 }
1150                 else if (cheating)
1151                 {
1152                     OGL_SetColor(TSWALLCOLORS);
1153                 }
1154                 else continue;
1155             }
1156         }
1157         else if (plr->powers[pw_allmap])
1158         {
1159             if (!(lines[i].flags & LINE_NEVERSEE))
1160                 OGL_SetColor(GRAYS+3);
1161             else
1162                 continue;
1163         }
1164         else continue;
1165
1166         // Draw the line. 1.2 is the to-square aspect corrector.
1167         glVertex2f( FIX2FLT(CXMTOFX(lines[i].v1->x)),
1168                     FIX2FLT(CYMTOFX(lines[i].v1->y))/1.2);
1169         glVertex2f( FIX2FLT(CXMTOFX(lines[i].v2->x)),
1170                     FIX2FLT(CYMTOFX(lines[i].v2->y))/1.2);
1171     }
1172     glEnd();
1173     glLineWidth(1.0);
1174     glEnable( GL_TEXTURE_2D );
1175 #else
1176   static mline_t l;
1177
1178   for (i=0;i<numlines;i++)
1179   {
1180     l.a.x = lines[i].v1->x;
1181     l.a.y = lines[i].v1->y;
1182     l.b.x = lines[i].v2->x;
1183     l.b.y = lines[i].v2->y;
1184     if (cheating || (lines[i].flags & ML_MAPPED))
1185     {
1186       if ((lines[i].flags & LINE_NEVERSEE) && !cheating)
1187                         continue;
1188       if (!lines[i].backsector)
1189       {
1190         AM_drawMline(&l, WALLCOLORS+lightlev);
1191       } else {
1192         if (lines[i].flags & ML_SECRET) // secret door
1193         {
1194           if (cheating) AM_drawMline(&l, 0);
1195           else AM_drawMline(&l, WALLCOLORS+lightlev);
1196         }
1197         else if(lines[i].special == 13 || lines[i].special == 83)
1198         { // Locked door line -- all locked doors are greed
1199                 AM_drawMline(&l, GREENKEY);
1200         }
1201         else if(lines[i].special == 70 || lines[i].special == 71)
1202         { // intra-level teleports are blue
1203                 AM_drawMline(&l, BLUEKEY);
1204         }
1205         else if(lines[i].special == 74 || lines[i].special == 75)
1206         { // inter-level teleport/game-winning exit -- both are red
1207                 AM_drawMline(&l, BLOODRED);
1208         }
1209         else if (lines[i].backsector->floorheight
1210                    != lines[i].frontsector->floorheight) {
1211           AM_drawMline(&l, FDWALLCOLORS + lightlev); // floor level change
1212         } else if (lines[i].backsector->ceilingheight
1213                    != lines[i].frontsector->ceilingheight) {
1214           AM_drawMline(&l, CDWALLCOLORS+lightlev); // ceiling level change
1215         } else if (cheating) {
1216           AM_drawMline(&l, TSWALLCOLORS+lightlev);
1217         }
1218       }
1219     } else if (plr->powers[pw_allmap])
1220     {
1221       if (!(lines[i].flags & LINE_NEVERSEE)) AM_drawMline(&l, GRAYS+3);
1222     }
1223   }
1224 #endif
1225 }
1226
1227 void AM_rotate(fixed_t *x, fixed_t *y, angle_t a)
1228 {
1229   fixed_t tmpx;
1230
1231   tmpx = FixedMul(*x,finecosine[a>>ANGLETOFINESHIFT])
1232        - FixedMul(*y,finesine[a>>ANGLETOFINESHIFT]);
1233   *y   = FixedMul(*x,finesine[a>>ANGLETOFINESHIFT])
1234        + FixedMul(*y,finecosine[a>>ANGLETOFINESHIFT]);
1235   *x = tmpx;
1236 }
1237
1238 void AM_drawLineCharacter(mline_t *lineguy, int lineguylines, fixed_t scale,
1239   angle_t angle, int color, fixed_t x, fixed_t y)
1240 {
1241   int i;
1242   mline_t l;
1243
1244   for (i=0;i<lineguylines;i++)
1245   {
1246     l.a.x = lineguy[i].a.x;
1247     l.a.y = lineguy[i].a.y;
1248     if (scale)
1249     {
1250       l.a.x = FixedMul(scale, l.a.x);
1251       l.a.y = FixedMul(scale, l.a.y);
1252     }
1253     if (angle) AM_rotate(&l.a.x, &l.a.y, angle);
1254     l.a.x += x;
1255     l.a.y += y;
1256
1257     l.b.x = lineguy[i].b.x;
1258     l.b.y = lineguy[i].b.y;
1259     if (scale)
1260     {
1261       l.b.x = FixedMul(scale, l.b.x);
1262       l.b.y = FixedMul(scale, l.b.y);
1263     }
1264     if (angle) AM_rotate(&l.b.x, &l.b.y, angle);
1265     l.b.x += x;
1266     l.b.y += y;
1267
1268     AM_drawMline(&l, color);
1269   }
1270 }
1271
1272 void AM_drawPlayers(void)
1273 {
1274         int i;
1275         player_t *p;
1276         static int their_colors[] =
1277         {
1278                 AM_PLR1_COLOR,
1279                 AM_PLR2_COLOR,
1280                 AM_PLR3_COLOR,
1281                 AM_PLR4_COLOR,
1282                 AM_PLR5_COLOR,
1283                 AM_PLR6_COLOR,
1284                 AM_PLR7_COLOR,
1285                 AM_PLR8_COLOR
1286         };
1287         int their_color = -1;
1288         int color;
1289
1290         if(!netgame)
1291         {
1292                 AM_drawLineCharacter(player_arrow, NUMPLYRLINES, 0, plr->mo->angle,
1293                         WHITE, plr->mo->x, plr->mo->y);
1294                 return;
1295         }
1296
1297         for(i = 0; i < MAXPLAYERS; i++)
1298         {
1299                 their_color++;
1300                 p = &players[i];
1301                 if(deathmatch && !singledemo && p != plr)
1302                 {
1303                         continue;
1304                 }
1305                 if (!playeringame[i]) continue;
1306                 color = their_colors[their_color];
1307                 AM_drawLineCharacter(player_arrow, NUMPLYRLINES, 0, p->mo->angle,
1308                                                                 color, p->mo->x, p->mo->y);
1309         }
1310 }
1311
1312 void AM_drawThings(int colors, int colorrange)
1313 {
1314   int i;
1315   mobj_t *t;
1316
1317   for (i=0;i<numsectors;i++)
1318   {
1319     t = sectors[i].thinglist;
1320     while (t)
1321     {
1322       AM_drawLineCharacter(thintriangle_guy, NUMTHINTRIANGLEGUYLINES,
1323                                 16<<FRACBITS, t->angle, colors+lightlev, t->x, t->y);
1324       t = t->snext;
1325     }
1326   }
1327 }
1328
1329 /*
1330 void AM_drawMarks(void)
1331 {
1332   int i, fx, fy, w, h;
1333
1334   for (i=0;i<AM_NUMMARKPOINTS;i++)
1335   {
1336     if (markpoints[i].x != -1)
1337     {
1338       w = SHORT(marknums[i]->width);
1339       h = SHORT(marknums[i]->height);
1340       fx = CXMTOF(markpoints[i].x);
1341       fy = CYMTOF(markpoints[i].y);
1342       if (fx >= f_x && fx <= f_w - w && fy >= f_y && fy <= f_h - h)
1343                         V_DrawPatch(fx, fy, marknums[i]);
1344     }
1345   }
1346 }
1347 */
1348 /*
1349 void AM_drawkeys(void)
1350 {
1351         if(KeyPoints[0].x != 0 || KeyPoints[0].y != 0)
1352         {
1353                 AM_drawLineCharacter(keysquare, NUMKEYSQUARELINES, 0, 0, YELLOWKEY,
1354                         KeyPoints[0].x, KeyPoints[0].y);
1355         }
1356         if(KeyPoints[1].x != 0 || KeyPoints[1].y != 0)
1357         {
1358                 AM_drawLineCharacter(keysquare, NUMKEYSQUARELINES, 0, 0, GREENKEY,
1359                         KeyPoints[1].x, KeyPoints[1].y);
1360         }
1361         if(KeyPoints[2].x != 0 || KeyPoints[2].y != 0)
1362         {
1363                 AM_drawLineCharacter(keysquare, NUMKEYSQUARELINES, 0, 0, BLUEKEY,
1364                         KeyPoints[2].x, KeyPoints[2].y);
1365         }
1366 }
1367 */
1368
1369 /*
1370 void AM_drawCrosshair(int color)
1371 {
1372   fb[(f_w*(f_h+1))/2] = color; // single point for now
1373 }
1374 */
1375
1376
1377 #ifdef RENDER3D
1378 void AM_OGL_SetupState()
1379 {
1380     float ys = screenHeight/200.0;
1381  
1382     // Let's set up a scissor box to clip the map lines and stuff.
1383     glPushAttrib(GL_SCISSOR_BIT);
1384     glScissor(0, screenHeight-finit_height*ys, screenWidth, finit_height*ys);
1385     glEnable(GL_SCISSOR_TEST);
1386 }
1387  
1388 void AM_OGL_RestoreState()
1389 {
1390     glPopAttrib();
1391 }                                                                               
1392 #endif
1393
1394
1395 void AM_Drawer (void)
1396 {
1397     if (!automapactive) return;
1398
1399     UpdateState |= I_FULLSCRN;
1400
1401 #ifdef RENDER3D
1402     // Update the height (in case sbarscale has been changed).
1403     finit_height = SCREENHEIGHT-SBARHEIGHT*sbarscale/20/*-3*/;
1404 #endif
1405
1406     AM_clearFB(BACKGROUND);
1407
1408 #ifdef RENDER3D
1409     AM_OGL_SetupState();
1410 #endif
1411
1412     if (grid) AM_drawGrid(GRIDCOLORS);
1413     AM_drawWalls();
1414     AM_drawPlayers();
1415         DrawWorldTimer();
1416
1417     if (cheating==2) AM_drawThings(THINGCOLORS, THINGRANGE);
1418
1419 //  AM_drawCrosshair(XHAIRCOLORS);
1420 //  AM_drawMarks();
1421 //      if(gameskill == sk_baby) AM_drawkeys();
1422
1423 #ifdef RENDER3D
1424     AM_OGL_RestoreState();
1425 #endif
1426
1427         MN_DrTextA(P_GetMapName(gamemap), 38, 144);
1428         if(ShowKills && netgame && deathmatch)
1429         {
1430                 AM_DrawDeathmatchStats();
1431         }
1432 //  I_Update();
1433 //  V_MarkRect(f_x, f_y, f_w, f_h);
1434
1435 }
1436
1437 //===========================================================================
1438 //
1439 // AM_DrawDeathmatchStats
1440 //
1441 //===========================================================================
1442
1443 // 8-player note:  Proper player color names here, too
1444
1445 char *PlayerColorText[MAXPLAYERS] =
1446 {
1447         "BLUE:",
1448         "RED:",
1449         "YELLOW:",
1450         "GREEN:",
1451         "JADE:",
1452         "WHITE:",
1453         "HAZEL:",
1454         "PURPLE:"
1455 };
1456
1457 void AM_DrawDeathmatchStats(void)
1458 {
1459         int i, j, k, m;
1460         int fragCount[MAXPLAYERS];
1461         int order[MAXPLAYERS];
1462         char textBuffer[80];
1463         int yPosition;
1464
1465         for(i = 0; i < MAXPLAYERS; i++)
1466         {
1467                 fragCount[i] = 0;
1468                 order[i] = -1;
1469         }
1470         for(i = 0; i < MAXPLAYERS; i++)
1471         {
1472                 if(!playeringame[i])
1473                 {
1474                         continue;
1475                 }
1476                 else
1477                 {
1478                         for(j = 0; j < MAXPLAYERS; j++)
1479                         {
1480                                 if(playeringame[j])
1481                                 {
1482                                         fragCount[i] += players[i].frags[j];
1483                                 }
1484                         }
1485                         for(k = 0; k < MAXPLAYERS; k++)
1486                         {
1487                                 if(order[k] == -1)
1488                                 {
1489                                         order[k] = i;
1490                                         break;
1491                                 }
1492                                 else if(fragCount[i] > fragCount[order[k]])
1493                                 {
1494                                         for(m = MAXPLAYERS-1; m > k; m--)
1495                                         {
1496                                                  order[m] = order[m-1];
1497                                         }
1498                                         order[k] = i;
1499                                         break;
1500                                 }
1501                         }
1502                 }
1503         }
1504         yPosition = 15;
1505         for(i = 0; i < MAXPLAYERS; i++)
1506         {
1507                 if(!playeringame[order[i]])
1508                 {
1509                         continue;
1510                 }
1511                 else
1512                 {
1513                         MN_DrTextA(PlayerColorText[order[i]], 8, yPosition);
1514                         sprintf(textBuffer, "%d", fragCount[order[i]]);
1515                         MN_DrTextA(textBuffer, 80, yPosition);
1516                         yPosition += 10;
1517                 }
1518         }
1519 }
1520
1521 //===========================================================================
1522 //
1523 // DrawWorldTimer
1524 //
1525 //===========================================================================
1526
1527 static void DrawWorldTimer(void)
1528 {
1529         int days;
1530         int hours;
1531         int minutes;
1532         int seconds;
1533         int worldTimer;
1534         char timeBuffer[15];
1535         char dayBuffer[20];
1536
1537         worldTimer = players[consoleplayer].worldTimer;
1538
1539         worldTimer /= 35;
1540         days = worldTimer/86400;
1541         worldTimer -= days*86400;
1542         hours = worldTimer/3600;
1543         worldTimer -= hours*3600;
1544         minutes = worldTimer/60;
1545         worldTimer -= minutes*60;
1546         seconds = worldTimer;
1547
1548         sprintf(timeBuffer, "%.2d : %.2d : %.2d", hours, minutes,seconds);
1549         MN_DrTextA(timeBuffer, 240, 8);
1550
1551         if (days)
1552         {
1553                 if (days==1)
1554                 {
1555                         sprintf(dayBuffer, "%.2d DAY", days);
1556                 }
1557                 else
1558                 {
1559                         sprintf(dayBuffer, "%.2d DAYS", days);
1560                 }
1561                 MN_DrTextA(dayBuffer, 240, 20);
1562                 if (days >= 5)
1563                 {
1564                         MN_DrTextA("YOU FREAK!!!", 230, 35);
1565                 }
1566         }
1567 }
1568