fix remapping behavior. Remapping is only necessary if we are rendering on the workbe...
[AROS-Contrib.git] / Games / Doom / am_map.c
blob93a4379c112086b3200c9f9fbd2b630b3be093f6
1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id$
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 //
8 // This source is available for distribution and/or modification
9 // only under the terms of the DOOM Source Code License as
10 // published by id Software. All rights reserved.
12 // The source is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
15 // for more details.
18 // $Log$
19 // Revision 1.1 2000/02/29 18:21:03 stegerg
20 // Doom port based on ADoomPPC. Read README.AROS!
23 // DESCRIPTION: the automap code
25 //-----------------------------------------------------------------------------
27 static const char rcsid[] = "$Id$";
29 #include <stdio.h>
32 #include "z_zone.h"
33 #include "doomdef.h"
34 #include "st_stuff.h"
35 #include "p_local.h"
36 #include "w_wad.h"
38 #include "m_cheat.h"
39 #include "i_system.h"
41 // Needs access to LFB.
42 #include "v_video.h"
44 // State.
45 #include "doomstat.h"
46 #include "r_state.h"
48 // Data.
49 #include "dstrings.h"
51 #include "am_map.h"
54 // For use if I do walls with outsides/insides
55 #define REDS (256-5*16)
56 #define REDRANGE 16
57 #define BLUES (256-4*16+8)
58 #define BLUERANGE 8
59 #define GREENS (7*16)
60 #define GREENRANGE 16
61 #define GRAYS (6*16)
62 #define GRAYSRANGE 16
63 #define BROWNS (4*16)
64 #define BROWNRANGE 16
65 #define YELLOWS (256-32+7)
66 #define YELLOWRANGE 1
67 #define BLACK 0
68 #define WHITE (256-47)
70 // Automap colors
71 #define BACKGROUND BLACK
72 #define YOURCOLORS WHITE
73 #define YOURRANGE 0
74 #define WALLCOLORS REDS
75 #define WALLRANGE REDRANGE
76 #define TSWALLCOLORS GRAYS
77 #define TSWALLRANGE GRAYSRANGE
78 #define FDWALLCOLORS BROWNS
79 #define FDWALLRANGE BROWNRANGE
80 #define CDWALLCOLORS YELLOWS
81 #define CDWALLRANGE YELLOWRANGE
82 #define THINGCOLORS GREENS
83 #define THINGRANGE GREENRANGE
84 #define SECRETWALLCOLORS WALLCOLORS
85 #define SECRETWALLRANGE WALLRANGE
86 #define GRIDCOLORS (GRAYS + GRAYSRANGE/2)
87 #define GRIDRANGE 0
88 #define XHAIRCOLORS GRAYS
90 // drawing stuff
91 #define FB 0
93 #define AM_PANDOWNKEY KEY_DOWNARROW
94 #define AM_PANUPKEY KEY_UPARROW
95 #define AM_PANRIGHTKEY KEY_RIGHTARROW
96 #define AM_PANLEFTKEY KEY_LEFTARROW
97 #define AM_ZOOMINKEY '='
98 #define AM_ZOOMOUTKEY '-'
99 #define AM_STARTKEY KEY_TAB
100 #define AM_ENDKEY KEY_TAB
101 #define AM_GOBIGKEY '0'
102 #define AM_FOLLOWKEY 'f'
103 #define AM_GRIDKEY 'g'
104 #define AM_MARKKEY 'm'
105 #define AM_CLEARMARKKEY 'c'
106 #define AM_CHANGETYPE 'z' /* 't' conflicts with HU_INPUTTOGGLE, hu_stuff.c */
108 #define AM_NUMMARKPOINTS 10
110 // scale on entry
111 #define INITSCALEMTOF (.2*FRACUNIT)
112 // how much the automap moves window per tic in frame-buffer coordinates
113 // moves 140 pixels in 1 second
114 #define F_PANINC 4
115 // how much zoom-in per tic
116 // goes to 2x in 1 second
117 #define M_ZOOMIN ((int) (1.02*FRACUNIT))
118 // how much zoom-out per tic
119 // pulls out to 0.5x in 1 second
120 #define M_ZOOMOUT ((int) (FRACUNIT/1.02))
122 // translates between frame-buffer and map distances
123 #define FTOM(x) FixedMul(((x)<<16),scale_ftom)
124 #define MTOF(x) (FixedMul((x),scale_mtof)>>16)
125 // translates between frame-buffer and map coordinates
126 #define CXMTOF(x) (f_x + MTOF((x)-m_x))
127 #define CYMTOF(y) (f_y + (f_h - MTOF((y)-m_y)))
129 // the following is crap
130 #define LINE_NEVERSEE ML_DONTDRAW
132 typedef struct
134 int x, y;
135 } fpoint_t;
137 typedef struct
139 fpoint_t a, b;
140 } fline_t;
142 typedef struct
144 fixed_t x,y;
145 } mpoint_t;
147 typedef struct
149 mpoint_t a, b;
150 } mline_t;
152 typedef struct
154 fixed_t slp, islp;
155 } islope_t;
160 // The vector graphics for the automap.
161 // A line drawing of the player pointing right,
162 // starting from the middle.
164 #define R ((8*PLAYERRADIUS)/7)
165 mline_t player_arrow[] = {
166 { { -R+R/8, 0 }, { R, 0 } }, // -----
167 { { R, 0 }, { R-R/2, R/4 } }, // ----->
168 { { R, 0 }, { R-R/2, -R/4 } },
169 { { -R+R/8, 0 }, { -R-R/8, R/4 } }, // >---->
170 { { -R+R/8, 0 }, { -R-R/8, -R/4 } },
171 { { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>--->
172 { { -R+3*R/8, 0 }, { -R+R/8, -R/4 } }
174 #undef R
175 #define NUMPLYRLINES (sizeof(player_arrow)/sizeof(mline_t))
177 #define R ((8*PLAYERRADIUS)/7)
178 mline_t cheat_player_arrow[] = {
179 { { -R+R/8, 0 }, { R, 0 } }, // -----
180 { { R, 0 }, { R-R/2, R/6 } }, // ----->
181 { { R, 0 }, { R-R/2, -R/6 } },
182 { { -R+R/8, 0 }, { -R-R/8, R/6 } }, // >----->
183 { { -R+R/8, 0 }, { -R-R/8, -R/6 } },
184 { { -R+3*R/8, 0 }, { -R+R/8, R/6 } }, // >>----->
185 { { -R+3*R/8, 0 }, { -R+R/8, -R/6 } },
186 { { -R/2, 0 }, { -R/2, -R/6 } }, // >>-d--->
187 { { -R/2, -R/6 }, { -R/2+R/6, -R/6 } },
188 { { -R/2+R/6, -R/6 }, { -R/2+R/6, R/4 } },
189 { { -R/6, 0 }, { -R/6, -R/6 } }, // >>-dd-->
190 { { -R/6, -R/6 }, { 0, -R/6 } },
191 { { 0, -R/6 }, { 0, R/4 } },
192 { { R/6, R/4 }, { R/6, -R/7 } }, // >>-ddt->
193 { { R/6, -R/7 }, { R/6+R/32, -R/7-R/32 } },
194 { { R/6+R/32, -R/7-R/32 }, { R/6+R/10, -R/7 } }
196 #undef R
197 #define NUMCHEATPLYRLINES (sizeof(cheat_player_arrow)/sizeof(mline_t))
199 #define R (FRACUNIT)
200 mline_t triangle_guy[] = {
201 { { -.867*R, -.5*R }, { .867*R, -.5*R } },
202 { { .867*R, -.5*R } , { 0, R } },
203 { { 0, R }, { -.867*R, -.5*R } }
205 #undef R
206 #define NUMTRIANGLEGUYLINES (sizeof(triangle_guy)/sizeof(mline_t))
208 #define R (FRACUNIT)
209 mline_t thintriangle_guy[] = {
210 { { -.5*R, -.7*R }, { R, 0 } },
211 { { R, 0 }, { -.5*R, .7*R } },
212 { { -.5*R, .7*R }, { -.5*R, -.7*R } }
214 #undef R
215 #define NUMTHINTRIANGLEGUYLINES (sizeof(thintriangle_guy)/sizeof(mline_t))
220 static int cheating = 0;
221 static int grid = 0;
223 static int leveljuststarted = 1; // kluge until AM_LevelInit() is called
225 boolean automapactive = false;
227 static int finit_width;
228 static int finit_height;
230 extern int viewwidth; /* CDE'98 - Need this for maponhu */
231 extern int viewheight; /* CDE'98 - Need this for maponhu */
232 extern int viewwindowx; /* CDE'98 - Need this for maponhu */
233 extern int viewwindowy; /* CDE'98 - Need this for maponhu */
235 int wx; /* CDE'98 - x offset from view */
236 int wy; /* CDE'98 - y offset from view */
238 // location of window on screen
239 static int f_x;
240 static int f_y;
242 // size of window on screen
243 static int f_w;
244 static int f_h;
246 static int lightlev; // used for funky strobing effect
247 static byte* fb; // pseudo-frame buffer
248 static int amclock;
250 static mpoint_t m_paninc; // how far the window pans each tic (map coords)
251 static fixed_t mtof_zoommul; // how far the window zooms in each tic (map coords)
252 static fixed_t ftom_zoommul; // how far the window zooms in each tic (fb coords)
254 static fixed_t m_x, m_y; // LL x,y where the window is on the map (map coords)
255 static fixed_t m_x2, m_y2; // UR x,y where the window is on the map (map coords)
258 // width/height of window on map (map coords)
260 static fixed_t m_w;
261 static fixed_t m_h;
263 // based on level size
264 static fixed_t min_x;
265 static fixed_t min_y;
266 static fixed_t max_x;
267 static fixed_t max_y;
269 static fixed_t max_w; // max_x-min_x,
270 static fixed_t max_h; // max_y-min_y
272 // based on player size
273 static fixed_t min_w;
274 static fixed_t min_h;
277 static fixed_t min_scale_mtof; // used to tell when to stop zooming out
278 static fixed_t max_scale_mtof; // used to tell when to stop zooming in
280 // old stuff for recovery later
281 static fixed_t old_m_w, old_m_h;
282 static fixed_t old_m_x, old_m_y;
284 // old location used by the Follower routine
285 static mpoint_t f_oldloc;
287 // used by MTOF to scale from map-to-frame-buffer coords
288 static fixed_t scale_mtof = INITSCALEMTOF;
289 // used by FTOM to scale from frame-buffer-to-map coords (=1/scale_mtof)
290 static fixed_t scale_ftom;
292 static player_t *plr; // the player represented by an arrow
294 static patch_t *marknums[10]; // numbers used for marking by the automap
295 static mpoint_t markpoints[AM_NUMMARKPOINTS]; // where the points are
296 static int markpointnum = 0; // next point to be assigned
298 static int followplayer = 1; // specifies whether to follow the player around
300 // Dehacked
301 unsigned char cheat_amap_seq[] = { 0xb2, 0x26, 0x26, 0x2e, 0xff };
302 static cheatseq_t cheat_amap = { cheat_amap_seq, 0 };
304 static boolean stopped = true;
306 extern boolean viewactive;
307 extern boolean rotatemap;
308 extern int maponhu;
311 //extern byte screens[][SCREENWIDTH*SCREENHEIGHT];
315 void
316 I_MarkRect
317 ( int x,
318 int y,
319 int width,
320 int height );
323 // Rotation in 2D.
324 // Used to rotate player arrow line character.
326 void
327 AM_rotate
328 ( fixed_t* x,
329 fixed_t* y,
330 angle_t a )
332 fixed_t tmpx;
334 tmpx =
335 FixedMul(*x,finecosine[a>>ANGLETOFINESHIFT])
336 - FixedMul(*y,finesine[a>>ANGLETOFINESHIFT]);
338 *y =
339 FixedMul(*x,finesine[a>>ANGLETOFINESHIFT])
340 + FixedMul(*y,finecosine[a>>ANGLETOFINESHIFT]);
342 *x = tmpx;
345 // Calculates the slope and slope according to the x-axis of a line
346 // segment in map coordinates (with the upright y-axis n' all) so
347 // that it can be used with the brain-dead drawing stuff.
349 void
350 AM_getIslope
351 ( mline_t* ml,
352 islope_t* is )
354 int dx, dy;
356 dy = ml->a.y - ml->b.y;
357 dx = ml->b.x - ml->a.x;
358 if (!dy) is->islp = (dx<0?-MAXINT:MAXINT);
359 else is->islp = FixedDiv(dx, dy);
360 if (!dx) is->slp = (dy<0?-MAXINT:MAXINT);
361 else is->slp = FixedDiv(dy, dx);
368 void AM_activateNewScale(void)
370 if (followplayer)
372 m_x = plr->mo->x - m_w/2;
373 m_y = plr->mo->y - m_h/2;
376 m_x += m_w/2;
377 m_y += m_h/2;
378 m_w = FTOM(f_w);
379 m_h = FTOM(f_h);
380 m_x -= m_w/2;
381 m_y -= m_h/2;
382 m_x2 = m_x + m_w;
383 m_y2 = m_y + m_h;
386 /* ici */
392 void AM_saveScaleAndLoc(void)
394 old_m_x = m_x;
395 old_m_y = m_y;
396 old_m_w = m_w;
397 old_m_h = m_h;
403 void AM_restoreScaleAndLoc(void)
406 m_w = old_m_w;
407 m_h = old_m_h;
408 if (!followplayer)
410 m_x = old_m_x;
411 m_y = old_m_y;
412 } else {
413 m_x = plr->mo->x - m_w/2;
414 m_y = plr->mo->y - m_h/2;
416 m_x2 = m_x + m_w;
417 m_y2 = m_y + m_h;
419 // Change the scaling multipliers
420 scale_mtof = FixedDiv(f_w<<FRACBITS, m_w);
421 scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
425 // adds a marker at the current location
427 void AM_addMark(void)
429 markpoints[markpointnum].x = m_x + m_w/2;
430 markpoints[markpointnum].y = m_y + m_h/2;
431 markpointnum = (markpointnum + 1) % AM_NUMMARKPOINTS;
436 // Determines bounding box of all vertices,
437 // sets global variables controlling zoom range.
439 void AM_findMinMaxBoundaries(void)
441 int i;
442 fixed_t a;
443 fixed_t b;
445 min_x = min_y = MAXINT;
446 max_x = max_y = -MAXINT;
448 for (i=0;i<numvertexes;i++)
450 if (vertexes[i].x < min_x)
451 min_x = vertexes[i].x;
452 else if (vertexes[i].x > max_x)
453 max_x = vertexes[i].x;
455 if (vertexes[i].y < min_y)
456 min_y = vertexes[i].y;
457 else if (vertexes[i].y > max_y)
458 max_y = vertexes[i].y;
461 max_w = max_x - min_x;
462 max_h = max_y - min_y;
464 min_w = 2*PLAYERRADIUS; // const? never changed?
465 min_h = 2*PLAYERRADIUS;
467 a = FixedDiv(f_w<<FRACBITS, max_w);
468 b = FixedDiv(f_h<<FRACBITS, max_h);
470 min_scale_mtof = a < b ? a : b;
471 max_scale_mtof = FixedDiv(f_h<<FRACBITS, 2*PLAYERRADIUS);
479 void AM_changeWindowLoc(void)
481 if (m_paninc.x || m_paninc.y)
483 followplayer = 0;
484 f_oldloc.x = MAXINT;
487 /* CDE'98 Rotate Map Patch - Rotate paninc or not ?? make your choice ... */
489 if(rotatemap)
491 fixed_t x,y;
492 x=m_paninc.x;
493 y=m_paninc.y;
494 AM_rotate(&x, &y, ANG90-plr->mo->angle);
495 m_x += x;
496 m_y += y;
497 } else {
499 m_x += m_paninc.x;
500 m_y += m_paninc.y;
505 /* CDE'98 - checking for limit is disabled while in rotate mode */
506 /* should not cause any problem */
507 if(!rotatemap)
509 if (m_x + m_w/2 > max_x)
510 m_x = max_x - m_w/2;
511 else if (m_x + m_w/2 < min_x)
512 m_x = min_x - m_w/2;
514 if (m_y + m_h/2 > max_y)
515 m_y = max_y - m_h/2;
516 else if (m_y + m_h/2 < min_y)
517 m_y = min_y - m_h/2;
520 m_x2 = m_x + m_w;
521 m_y2 = m_y + m_h;
528 #define MAX_HUTYPE 5
530 void AM_initMapSize(void)
532 /* CDE'98 - Calculate view position and size */
533 switch(maponhu)
535 case 0:
536 wx = 0;
537 wy = 0;
538 f_w = finit_width;
539 f_h = finit_height;
540 break;
541 case 1:
542 wx = viewwindowx;
543 wy = viewwindowy;
544 f_w = viewwidth;
545 f_h = viewheight;
546 break;
547 case 2:
548 wx = viewwindowx+viewwidth/14;
549 wy = viewwindowy+viewheight/14;
550 f_w = viewwidth/4;
551 f_h = viewheight/4;
552 break;
553 case 3:
554 wx = viewwindowx+viewwidth/14;
555 wy = viewwindowy+viewheight/14;
556 f_w = viewwidth/4;
557 f_h = viewwidth/4;
558 break;
559 case 4:
560 wx = viewwindowx+viewwidth/14;
561 wy = viewwindowy+viewheight/14;
562 f_w = viewwidth/3;
563 f_h = viewheight/3;
564 break;
566 default:
567 wx = viewwindowx;
568 wy = viewwindowy;
569 f_w = viewwidth;
570 f_h = viewheight;
574 void resinit_am_map (void)
576 finit_width = SCREENWIDTH;
577 finit_height = SCREENHEIGHT - 32;
583 void AM_initVariables(void)
585 int pnum;
586 static event_t st_notify = { ev_keyup, AM_MSGENTERED };
587 fixed_t a;
588 fixed_t b;
589 fixed_t m_w_old;
591 automapactive = true;
592 fb = screens[0];
594 f_oldloc.x = MAXINT;
595 amclock = 0;
596 lightlev = 0;
598 m_paninc.x = m_paninc.y = 0;
599 ftom_zoommul = FRACUNIT;
600 mtof_zoommul = FRACUNIT;
602 // CDE'98 Should make this first to avoid plr=NULL :)
603 // Find player to center on initially
604 if (!playeringame[pnum = consoleplayer])
605 for (pnum=0;pnum<MAXPLAYERS;pnum++)
606 if (playeringame[pnum])
607 break;
609 plr = &players[pnum];
611 // CDE'98 - Calculate view position and size/scale
612 m_w_old = m_w;
613 AM_initMapSize();
614 m_w = FTOM(f_w);
615 m_h = FTOM(f_h);
617 // CDE'98 Change the scaling multipliers
618 if(m_w_old != 0)
620 a = FixedDiv(f_w<<FRACBITS, max_w);
621 b = FixedDiv(f_h<<FRACBITS, max_h);
623 min_scale_mtof = a < b ? a : b;
624 max_scale_mtof = FixedDiv(f_h<<FRACBITS, 2*PLAYERRADIUS);
626 scale_mtof = FixedDiv(f_w<<FRACBITS, m_w_old);
627 scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
628 AM_activateNewScale();
631 // CDE'98 Center on our player
632 m_x = plr->mo->x - m_w/2;
633 m_y = plr->mo->y - m_h/2;
634 AM_changeWindowLoc();
636 // for saving & restoring
637 old_m_x = m_x;
638 old_m_y = m_y;
639 old_m_w = m_w;
640 old_m_h = m_h;
642 // inform the status bar of the change
643 ST_Responder(&st_notify);
649 void AM_loadPics(void)
651 int i;
652 char namebuf[9];
654 for (i=0;i<10;i++)
656 sprintf(namebuf, "AMMNUM%d", i);
657 marknums[i] = W_CacheLumpName(namebuf, PU_STATIC);
662 void AM_unloadPics(void)
664 int i;
666 for (i=0;i<10;i++)
667 Z_ChangeTag(marknums[i], PU_CACHE);
671 void AM_clearMarks(void)
673 int i;
675 for (i=0;i<AM_NUMMARKPOINTS;i++)
676 markpoints[i].x = -1; // means empty
677 markpointnum = 0;
683 // should be called at the start of every level
684 // right now, i figure it out myself
686 void AM_LevelInit(void)
688 leveljuststarted = 0;
690 f_x = f_y = 0;
692 AM_initMapSize();
694 AM_clearMarks();
696 AM_findMinMaxBoundaries();
697 scale_mtof = FixedDiv(min_scale_mtof, (int) (0.7*FRACUNIT));
698 if (scale_mtof > max_scale_mtof)
699 scale_mtof = min_scale_mtof;
700 scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
709 void AM_Stop (void)
711 static event_t st_notify = { 0, ev_keyup, AM_MSGEXITED };
713 AM_unloadPics();
714 automapactive = false;
715 ST_Responder(&st_notify);
716 stopped = true;
722 void AM_Start (void)
724 static int lastlevel = -1, lastepisode = -1;
726 if (!stopped) AM_Stop();
727 stopped = false;
728 if (lastlevel != gamemap || lastepisode != gameepisode)
730 AM_LevelInit();
731 lastlevel = gamemap;
732 lastepisode = gameepisode;
734 AM_initVariables();
735 AM_loadPics();
739 // set the window scale to the maximum size
741 void AM_minOutWindowScale(void)
743 scale_mtof = min_scale_mtof;
744 scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
745 AM_activateNewScale();
749 // set the window scale to the minimum size
751 void AM_maxOutWindowScale(void)
753 scale_mtof = max_scale_mtof;
754 scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
755 AM_activateNewScale();
760 // Handle events (user inputs) in automap mode
762 boolean
763 AM_Responder
764 ( event_t* ev )
767 int rc;
768 static int cheatstate=0;
769 static int bigstate=0;
770 static char buffer[20];
772 rc = false;
774 if (!automapactive)
776 if (ev->type == ev_keydown && ev->data1 == AM_STARTKEY)
778 AM_Start ();
779 /* CDE'98 Map on Headup Patch */
780 viewactive = (maponhu != 0);
781 rc = true;
785 else if (ev->type == ev_keydown)
788 rc = true;
789 switch(ev->data1)
791 case AM_PANRIGHTKEY: // pan right
792 if (!followplayer) m_paninc.x = FTOM(F_PANINC);
793 else rc = false;
794 break;
795 case AM_PANLEFTKEY: // pan left
796 if (!followplayer) m_paninc.x = -FTOM(F_PANINC);
797 else rc = false;
798 break;
799 case AM_PANUPKEY: // pan up
800 if (!followplayer) m_paninc.y = FTOM(F_PANINC);
801 else rc = false;
802 break;
803 case AM_PANDOWNKEY: // pan down
804 if (!followplayer) m_paninc.y = -FTOM(F_PANINC);
805 else rc = false;
806 break;
807 case AM_ZOOMOUTKEY: // zoom out
808 mtof_zoommul = M_ZOOMOUT;
809 ftom_zoommul = M_ZOOMIN;
810 break;
811 case AM_ZOOMINKEY: // zoom in
812 mtof_zoommul = M_ZOOMIN;
813 ftom_zoommul = M_ZOOMOUT;
814 break;
815 case AM_GOBIGKEY:
816 bigstate = !bigstate;
817 if (bigstate)
819 AM_saveScaleAndLoc();
820 AM_minOutWindowScale();
822 else AM_restoreScaleAndLoc();
823 break;
824 case AM_FOLLOWKEY:
825 followplayer = !followplayer;
826 f_oldloc.x = MAXINT;
827 plr->message = followplayer ? AMSTR_FOLLOWON : AMSTR_FOLLOWOFF;
828 break;
829 case AM_GRIDKEY:
830 grid = !grid;
831 plr->message = grid ? AMSTR_GRIDON : AMSTR_GRIDOFF;
832 break;
833 case AM_MARKKEY:
834 sprintf(buffer, "%s %d", AMSTR_MARKEDSPOT, markpointnum);
835 plr->message = buffer;
836 AM_addMark();
837 break;
838 case AM_CLEARMARKKEY:
839 AM_clearMarks();
840 plr->message = AMSTR_MARKSCLEARED;
841 break;
842 case AM_CHANGETYPE:
843 maponhu++;
844 if(maponhu>=MAX_HUTYPE)
845 maponhu=0;
846 AM_Start ();
847 viewactive = (maponhu != 0);
848 break;
849 case AM_ENDKEY:
850 bigstate = 0;
851 viewactive = true;
852 AM_Stop ();
853 break;
855 default:
856 cheatstate=0;
857 rc = false;
859 if (!deathmatch && cht_CheckCheat(&cheat_amap, ev->data1))
861 rc = false;
862 cheating = (cheating+1) % 3;
866 else if (ev->type == ev_keyup)
868 rc = false;
869 switch (ev->data1)
871 case AM_PANRIGHTKEY:
872 if (!followplayer) m_paninc.x = 0;
873 break;
874 case AM_PANLEFTKEY:
875 if (!followplayer) m_paninc.x = 0;
876 break;
877 case AM_PANUPKEY:
878 if (!followplayer) m_paninc.y = 0;
879 break;
880 case AM_PANDOWNKEY:
881 if (!followplayer) m_paninc.y = 0;
882 break;
883 case AM_ZOOMOUTKEY:
884 case AM_ZOOMINKEY:
885 mtof_zoommul = FRACUNIT;
886 ftom_zoommul = FRACUNIT;
887 break;
891 return rc;
897 // Zooming
899 void AM_changeWindowScale(void)
902 // Change the scaling multipliers
903 scale_mtof = FixedMul(scale_mtof, mtof_zoommul);
904 scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
906 if (scale_mtof < min_scale_mtof)
907 AM_minOutWindowScale();
908 else if (scale_mtof > max_scale_mtof)
909 AM_maxOutWindowScale();
910 else
911 AM_activateNewScale();
918 void AM_doFollowPlayer(void)
921 if (f_oldloc.x != plr->mo->x || f_oldloc.y != plr->mo->y)
923 m_x = FTOM(MTOF(plr->mo->x)) - m_w/2;
924 m_y = FTOM(MTOF(plr->mo->y)) - m_h/2;
925 m_x2 = m_x + m_w;
926 m_y2 = m_y + m_h;
927 f_oldloc.x = plr->mo->x;
928 f_oldloc.y = plr->mo->y;
930 // m_x = FTOM(MTOF(plr->mo->x - m_w/2));
931 // m_y = FTOM(MTOF(plr->mo->y - m_h/2));
932 // m_x = plr->mo->x - m_w/2;
933 // m_y = plr->mo->y - m_h/2;
942 void AM_updateLightLev(void)
944 static int nexttic = 0;
945 //static int litelevels[] = { 0, 3, 5, 6, 6, 7, 7, 7 };
946 static int litelevels[] = { 0, 4, 7, 10, 12, 14, 15, 15 };
947 static int litelevelscnt = 0;
949 // Change light level
950 if (amclock>nexttic)
952 lightlev = litelevels[litelevelscnt++];
953 if (litelevelscnt == sizeof(litelevels)/sizeof(int)) litelevelscnt = 0;
954 nexttic = amclock + 6 - (amclock % 6);
961 // Updates on Game Tick
963 void AM_Ticker (void)
966 if (!automapactive)
967 return;
969 amclock++;
971 if (followplayer)
972 AM_doFollowPlayer();
974 // Change the zoom if necessary
975 if (ftom_zoommul != FRACUNIT)
976 AM_changeWindowScale();
978 // Change x,y location
979 if (m_paninc.x || m_paninc.y)
980 AM_changeWindowLoc();
982 // Update light level
983 // AM_updateLightLev();
989 // Clear automap frame buffer.
991 void AM_clearFB(int color)
993 memset(fb, color, f_w*f_h);
998 // Automap clipping of lines.
1000 // Based on Cohen-Sutherland clipping algorithm but with a slightly
1001 // faster reject and precalculated slopes. If the speed is needed,
1002 // use a hash algorithm to handle the common cases.
1004 boolean
1005 AM_clipMline
1006 ( mline_t* ml,
1007 fline_t* fl )
1009 enum
1011 LEFT =1,
1012 RIGHT =2,
1013 BOTTOM =4,
1014 TOP =8
1017 register int outcode1 = 0;
1018 register int outcode2 = 0;
1019 register int outside;
1021 fpoint_t tmp;
1022 int dx;
1023 int dy;
1026 #define DOOUTCODE(oc, mx, my) \
1027 (oc) = 0; \
1028 if ((my) < 0) (oc) |= TOP; \
1029 else if ((my) >= f_h) (oc) |= BOTTOM; \
1030 if ((mx) < 0) (oc) |= LEFT; \
1031 else if ((mx) >= f_w) (oc) |= RIGHT;
1034 // do trivial rejects and outcodes
1035 if (ml->a.y > m_y2)
1036 outcode1 = TOP;
1037 else if (ml->a.y < m_y)
1038 outcode1 = BOTTOM;
1040 if (ml->b.y > m_y2)
1041 outcode2 = TOP;
1042 else if (ml->b.y < m_y)
1043 outcode2 = BOTTOM;
1045 if (outcode1 & outcode2)
1046 return false; // trivially outside
1048 if (ml->a.x < m_x)
1049 outcode1 |= LEFT;
1050 else if (ml->a.x > m_x2)
1051 outcode1 |= RIGHT;
1053 if (ml->b.x < m_x)
1054 outcode2 |= LEFT;
1055 else if (ml->b.x > m_x2)
1056 outcode2 |= RIGHT;
1058 if (outcode1 & outcode2)
1059 return false; // trivially outside
1061 // transform to frame-buffer coordinates.
1062 fl->a.x = CXMTOF(ml->a.x);
1063 fl->a.y = CYMTOF(ml->a.y);
1064 fl->b.x = CXMTOF(ml->b.x);
1065 fl->b.y = CYMTOF(ml->b.y);
1067 DOOUTCODE(outcode1, fl->a.x, fl->a.y);
1068 DOOUTCODE(outcode2, fl->b.x, fl->b.y);
1070 if (outcode1 & outcode2)
1071 return false;
1073 while (outcode1 | outcode2)
1075 // may be partially inside box
1076 // find an outside point
1077 if (outcode1)
1078 outside = outcode1;
1079 else
1080 outside = outcode2;
1082 // clip to each side
1083 if (outside & TOP)
1085 dy = fl->a.y - fl->b.y;
1086 dx = fl->b.x - fl->a.x;
1087 tmp.x = fl->a.x + (dx*(fl->a.y))/dy;
1088 tmp.y = 0;
1090 else if (outside & BOTTOM)
1092 dy = fl->a.y - fl->b.y;
1093 dx = fl->b.x - fl->a.x;
1094 tmp.x = fl->a.x + (dx*(fl->a.y-f_h))/dy;
1095 tmp.y = f_h-1;
1097 else if (outside & RIGHT)
1099 dy = fl->b.y - fl->a.y;
1100 dx = fl->b.x - fl->a.x;
1101 tmp.y = fl->a.y + (dy*(f_w-1 - fl->a.x))/dx;
1102 tmp.x = f_w-1;
1104 else if (outside & LEFT)
1106 dy = fl->b.y - fl->a.y;
1107 dx = fl->b.x - fl->a.x;
1108 tmp.y = fl->a.y + (dy*(-fl->a.x))/dx;
1109 tmp.x = 0;
1112 if (outside == outcode1)
1114 fl->a = tmp;
1115 DOOUTCODE(outcode1, fl->a.x, fl->a.y);
1117 else
1119 fl->b = tmp;
1120 DOOUTCODE(outcode2, fl->b.x, fl->b.y);
1123 if (outcode1 & outcode2)
1124 return false; // trivially outside
1127 return true;
1129 #undef DOOUTCODE
1133 // Classic Bresenham w/ whatever optimizations needed for speed
1135 void
1136 AM_drawFline
1137 ( fline_t* fl,
1138 int color )
1140 register int x;
1141 register int y;
1142 register int dx;
1143 register int dy;
1144 register int sx;
1145 register int sy;
1146 register int ax;
1147 register int ay;
1148 register int d;
1150 static fuck = 0;
1152 // For debugging only
1154 if ( fl->a.x < 0 || fl->a.x >= f_w
1155 || fl->a.y < 0 || fl->a.y >= f_h
1156 || fl->b.x < 0 || fl->b.x >= f_w
1157 || fl->b.y < 0 || fl->b.y >= f_h)
1159 fprintf(stderr, "fuck %d \r", fuck++);
1160 return;
1164 #define PUTDOT(xx,yy,cc) fb[(yy+wy)*finit_width+(xx+wx)]=(cc)
1166 dx = fl->b.x - fl->a.x;
1167 ax = 2 * (dx<0 ? -dx : dx);
1168 sx = dx<0 ? -1 : 1;
1170 dy = fl->b.y - fl->a.y;
1171 ay = 2 * (dy<0 ? -dy : dy);
1172 sy = dy<0 ? -1 : 1;
1174 x = fl->a.x;
1175 y = fl->a.y;
1177 if (ax > ay)
1179 d = ay - ax/2;
1180 while (1)
1182 PUTDOT(x,y,color);
1183 if (x == fl->b.x) return;
1184 if (d>=0)
1186 y += sy;
1187 d -= ax;
1189 x += sx;
1190 d += ay;
1193 else
1195 d = ax - ay/2;
1196 while (1)
1198 PUTDOT(x, y, color);
1199 if (y == fl->b.y) return;
1200 if (d >= 0)
1202 x += sx;
1203 d -= ay;
1205 y += sy;
1206 d += ax;
1214 // Clip lines, draw visible part sof lines.
1216 void
1217 AM_drawMline
1218 ( mline_t* ml,
1219 int color )
1221 static fline_t fl;
1222 mline_t l;
1224 /* Rotate Map Patch - CDE 98' */
1225 if(rotatemap) {
1226 l.a.x = ml->a.x-plr->mo->x;
1227 l.a.y = ml->a.y-plr->mo->y;
1228 l.b.x = ml->b.x-plr->mo->x;
1229 l.b.y = ml->b.y-plr->mo->y;
1231 AM_rotate(&l.a.x, &l.a.y, ANG90-plr->mo->angle);
1232 AM_rotate(&l.b.x, &l.b.y, ANG90-plr->mo->angle);
1234 l.a.x += plr->mo->x;
1235 l.a.y += plr->mo->y;
1236 l.b.x += plr->mo->x;
1237 l.b.y += plr->mo->y;
1239 if (AM_clipMline(&l, &fl))
1240 AM_drawFline(&fl, color); // draws it on frame buffer using fb coords
1241 } else {
1242 if (AM_clipMline(ml, &fl))
1243 AM_drawFline(&fl, color); // draws it on frame buffer using fb coords
1250 // Draws flat (floor/ceiling tile) aligned grid lines.
1252 void AM_drawGrid(int color)
1254 fixed_t x, y;
1255 fixed_t start, end;
1256 mline_t ml;
1258 // Figure out start of vertical gridlines
1259 start = m_x;
1260 if ((start-bmaporgx)%(MAPBLOCKUNITS<<FRACBITS))
1261 start += (MAPBLOCKUNITS<<FRACBITS)
1262 - ((start-bmaporgx)%(MAPBLOCKUNITS<<FRACBITS));
1263 end = m_x + m_w;
1265 // draw vertical gridlines
1266 ml.a.y = m_y;
1267 ml.b.y = m_y+m_h;
1268 for (x=start; x<end; x+=(MAPBLOCKUNITS<<FRACBITS))
1270 ml.a.x = x;
1271 ml.b.x = x;
1272 AM_drawMline(&ml, color);
1275 // Figure out start of horizontal gridlines
1276 start = m_y;
1277 if ((start-bmaporgy)%(MAPBLOCKUNITS<<FRACBITS))
1278 start += (MAPBLOCKUNITS<<FRACBITS)
1279 - ((start-bmaporgy)%(MAPBLOCKUNITS<<FRACBITS));
1280 end = m_y + m_h;
1282 // draw horizontal gridlines
1283 ml.a.x = m_x;
1284 ml.b.x = m_x + m_w;
1285 for (y=start; y<end; y+=(MAPBLOCKUNITS<<FRACBITS))
1287 ml.a.y = y;
1288 ml.b.y = y;
1289 AM_drawMline(&ml, color);
1295 // Determines visible lines, draws them.
1296 // This is LineDef based, not LineSeg based.
1298 void AM_drawWalls(void)
1300 int i;
1301 static mline_t l;
1303 for (i=0;i<numlines;i++)
1305 l.a.x = lines[i].v1->x;
1306 l.a.y = lines[i].v1->y;
1307 l.b.x = lines[i].v2->x;
1308 l.b.y = lines[i].v2->y;
1309 if (cheating || (lines[i].flags & ML_MAPPED))
1311 if ((lines[i].flags & LINE_NEVERSEE) && !cheating)
1312 continue;
1313 if (!lines[i].backsector)
1315 AM_drawMline(&l, WALLCOLORS+lightlev);
1317 else
1319 if (lines[i].special == 39)
1320 { // teleporters
1321 AM_drawMline(&l, WALLCOLORS+WALLRANGE/2);
1323 else if (lines[i].flags & ML_SECRET) // secret door
1325 if (cheating) AM_drawMline(&l, SECRETWALLCOLORS + lightlev);
1326 else AM_drawMline(&l, WALLCOLORS+lightlev);
1328 else if (lines[i].backsector->floorheight
1329 != lines[i].frontsector->floorheight) {
1330 AM_drawMline(&l, FDWALLCOLORS + lightlev); // floor level change
1332 else if (lines[i].backsector->ceilingheight
1333 != lines[i].frontsector->ceilingheight) {
1334 AM_drawMline(&l, CDWALLCOLORS+lightlev); // ceiling level change
1336 else if (cheating) {
1337 AM_drawMline(&l, TSWALLCOLORS+lightlev);
1341 else if (plr->powers[pw_allmap])
1343 if (!(lines[i].flags & LINE_NEVERSEE)) AM_drawMline(&l, GRAYS+3);
1348 void
1349 AM_drawLineCharacter
1350 ( mline_t* lineguy,
1351 int lineguylines,
1352 fixed_t scale,
1353 angle_t angle,
1354 int color,
1355 fixed_t x,
1356 fixed_t y )
1358 int i;
1359 mline_t l;
1361 for (i=0;i<lineguylines;i++)
1363 l.a.x = lineguy[i].a.x;
1364 l.a.y = lineguy[i].a.y;
1366 if (scale)
1368 l.a.x = FixedMul(scale, l.a.x);
1369 l.a.y = FixedMul(scale, l.a.y);
1372 if (angle)
1373 AM_rotate(&l.a.x, &l.a.y, angle);
1375 l.a.x += x;
1376 l.a.y += y;
1378 l.b.x = lineguy[i].b.x;
1379 l.b.y = lineguy[i].b.y;
1381 if (scale)
1383 l.b.x = FixedMul(scale, l.b.x);
1384 l.b.y = FixedMul(scale, l.b.y);
1387 if (angle)
1388 AM_rotate(&l.b.x, &l.b.y, angle);
1390 l.b.x += x;
1391 l.b.y += y;
1393 AM_drawMline(&l, color);
1397 void AM_drawPlayers(void)
1399 int i;
1400 player_t* p;
1401 static int their_colors[] = { GREENS, GRAYS, BROWNS, REDS };
1402 int their_color = -1;
1403 int color;
1405 if (!netgame)
1407 if (cheating)
1408 AM_drawLineCharacter
1409 (cheat_player_arrow, NUMCHEATPLYRLINES, 0,
1410 plr->mo->angle, WHITE, plr->mo->x, plr->mo->y);
1411 else
1412 AM_drawLineCharacter
1413 (player_arrow, NUMPLYRLINES, 0, plr->mo->angle,
1414 WHITE, plr->mo->x, plr->mo->y);
1415 return;
1418 for (i=0;i<MAXPLAYERS;i++)
1420 their_color++;
1421 p = &players[i];
1423 if ( (deathmatch && !singledemo) && p != plr)
1424 continue;
1426 if (!playeringame[i])
1427 continue;
1429 if (p->powers[pw_invisibility])
1430 color = 246; // *close* to black
1431 else
1432 color = their_colors[their_color];
1434 AM_drawLineCharacter
1435 (player_arrow, NUMPLYRLINES, 0, p->mo->angle,
1436 color, p->mo->x, p->mo->y);
1441 void
1442 AM_drawThings
1443 ( int colors,
1444 int colorrange)
1446 int i;
1447 mobj_t* t;
1449 for (i=0;i<numsectors;i++)
1451 t = sectors[i].thinglist;
1452 while (t)
1454 AM_drawLineCharacter
1455 (thintriangle_guy, NUMTHINTRIANGLEGUYLINES,
1456 16<<FRACBITS, t->angle, colors+lightlev, t->x, t->y);
1457 t = t->snext;
1462 void AM_drawMarks(void)
1464 int i, fx, fy, w, h;
1465 fixed_t x,y;
1468 for (i=0;i<AM_NUMMARKPOINTS;i++)
1470 if (markpoints[i].x != -1)
1472 // w = SWAPSHORT(marknums[i]->width);
1473 // h = SWAPSHORT(marknums[i]->height);
1474 w = 5; // because something's wrong with the wad, i guess
1475 h = 6; // because something's wrong with the wad, i guess
1477 /* CDE'98 Rotate Map Patch - Now rotate marks :) */
1478 if(rotatemap)
1480 x=markpoints[i].x-plr->mo->x;
1481 y=markpoints[i].y-plr->mo->y;
1482 AM_rotate(&x, &y, ANG90-plr->mo->angle);
1483 x += plr->mo->x;
1484 y += plr->mo->y;
1485 fx = CXMTOF(x);
1486 fy = CYMTOF(y);
1487 } else {
1488 fx = CXMTOF(markpoints[i].x);
1489 fy = CYMTOF(markpoints[i].y);
1492 if (fx >= f_x && fx <= f_w - w && fy >= f_y && fy <= f_h - h)
1493 V_DrawPatch(fx+wx, fy+wy, FB, marknums[i]);
1498 void AM_drawCrosshair(int color)
1500 /* CDE'98 - Crosshair on the view center whatever size/mode ! */
1503 //fb[((viewwidth+2*viewwindowx)*(viewheight+2*viewwindowy+1))/2] = color; // single point for now
1504 fb[(viewwidth+2*viewwindowx)*(wy+f_h/2)+(wx+f_w/2)] = color; // single point for now
1506 /* wx = viewwindowx;
1507 wy = viewwindowy;
1508 f_w = viewwidth;
1509 f_h = viewheight;*/
1511 void AM_drawBox(int color, int x, int y, int w, int h)
1513 fline_t l;
1514 int k;
1516 /* First draw the background */
1517 l.a.y = y-wy-1;
1518 l.b.y = y+h-wy;
1519 for(k=x-wx-1; k<x+w-wx; k++)
1521 l.a.x = k;
1522 l.b.x = k;
1523 AM_drawFline(&l, BLACK);
1526 /* Draw white border */
1527 l.a.x = x-wx-1;
1528 l.a.y = y-wy-1;
1529 l.b.x = x-wx-1;
1530 l.b.y = y+h-wy;
1531 AM_drawFline(&l, color);
1533 l.a.x = x+w-wx;
1534 l.a.y = y-wy-1;
1535 l.b.x = x+w-wx;
1536 l.b.y = y+h-wy;
1537 AM_drawFline(&l, color);
1539 l.a.x = x-wx-1;
1540 l.a.y = y-wy-1;
1541 l.b.x = x+w-wx;
1542 l.b.y = y-wy-1;
1543 AM_drawFline(&l, color);
1545 l.a.x = x-wx-1;
1546 l.a.y = y+h-wy;
1547 l.b.x = x+w-wx;
1548 l.b.y = y+h-wy;
1549 AM_drawFline(&l, color);
1553 void AM_Drawer (void)
1555 if (!automapactive) return;
1557 /* Map On HeadUp Patch - CDE 98' */
1558 if(maponhu==0)
1559 AM_clearFB(BACKGROUND);
1561 if(maponhu>1)
1562 AM_drawBox(WHITE, wx, wy, f_w, f_h);
1564 if (grid)
1565 AM_drawGrid(GRIDCOLORS);
1566 AM_drawWalls();
1567 AM_drawPlayers();
1568 if (cheating==2)
1569 AM_drawThings(THINGCOLORS, THINGRANGE);
1570 AM_drawCrosshair(XHAIRCOLORS);
1572 AM_drawMarks();
1574 I_MarkRect(f_x, f_y, f_w, f_h);