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