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