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