doom

a minimalistic implementation of doom
git clone git://ssnf.xyz/doom
Log | Files | Refs

am_map.c (19937B)


      1 #include <stdio.h>
      2 #include <limits.h>
      3 
      4 #include "z_zone.h"
      5 #include "doomdef.h"
      6 #include "st_stuff.h"
      7 #include "p_local.h"
      8 #include "w_wad.h"
      9 #include "m_cheat.h"
     10 #include "i_system.h"
     11 #include "v_video.h"
     12 #include "doomstat.h"
     13 #include "r_state.h"
     14 #include "dstrings.h"
     15 #include "am_map.h"
     16 
     17 #define REDS		(256-5*16)
     18 #define REDRANGE	16
     19 #define BLUES		(256-4*16+8)
     20 #define BLUERANGE	8
     21 #define GREENS		(7*16)
     22 #define GREENRANGE	16
     23 #define GRAYS		(6*16)
     24 #define GRAYSRANGE	16
     25 #define BROWNS		(4*16)
     26 #define BROWNRANGE	16
     27 #define YELLOWS		(256-32+7)
     28 #define YELLOWRANGE	1
     29 #define BLACK		0
     30 #define WHITE		(256-47)
     31 #define BACKGROUND	BLACK
     32 #define YOURCOLORS	WHITE
     33 #define YOURRANGE	0
     34 #define WALLCOLORS	REDS
     35 #define WALLRANGE	REDRANGE
     36 #define TSWALLCOLORS	GRAYS
     37 #define TSWALLRANGE	GRAYSRANGE
     38 #define FDWALLCOLORS	BROWNS
     39 #define FDWALLRANGE	BROWNRANGE
     40 #define CDWALLCOLORS	YELLOWS
     41 #define CDWALLRANGE	YELLOWRANGE
     42 #define THINGCOLORS	GREENS
     43 #define THINGRANGE	GREENRANGE
     44 #define SECRETWALLCOLORS WALLCOLORS
     45 #define SECRETWALLRANGE WALLRANGE
     46 #define GRIDCOLORS	(GRAYS + GRAYSRANGE/2)
     47 #define GRIDRANGE	0
     48 #define XHAIRCOLORS	GRAYS
     49 #define	FB		0
     50 #define AM_PANDOWNKEY	KEY_DOWNARROW
     51 #define AM_PANUPKEY	KEY_UPARROW
     52 #define AM_PANRIGHTKEY	KEY_RIGHTARROW
     53 #define AM_PANLEFTKEY	KEY_LEFTARROW
     54 #define AM_ZOOMINKEY	'='
     55 #define AM_ZOOMOUTKEY	'-'
     56 #define AM_STARTKEY	KEY_TAB
     57 #define AM_ENDKEY	KEY_TAB
     58 #define AM_GOBIGKEY	'0'
     59 #define AM_FOLLOWKEY	'f'
     60 #define AM_GRIDKEY	'g'
     61 #define AM_MARKKEY	'm'
     62 #define AM_CLEARMARKKEY	'c'
     63 #define AM_NUMMARKPOINTS 10
     64 #define INITSCALEMTOF (.2*FRACUNIT)
     65 #define F_PANINC	4
     66 #define M_ZOOMIN        ((int) (1.02*FRACUNIT))
     67 #define M_ZOOMOUT       ((int) (FRACUNIT/1.02))
     68 #define FTOM(x) FixedMul(((x)<<16),scale_ftom)
     69 #define MTOF(x) (FixedMul((x),scale_mtof)>>16)
     70 #define CXMTOF(x)  (f_x + MTOF((x)-m_x))
     71 #define CYMTOF(y)  (f_y + (f_h - MTOF((y)-m_y)))
     72 #define LINE_NEVERSEE ML_DONTDRAW
     73 #define NUMPLYRLINES (sizeof(player_arrow)/sizeof(mline_t))
     74 #define NUMCHEATPLYRLINES (sizeof(cheat_player_arrow)/sizeof(mline_t))
     75 #define NUMTRIANGLEGUYLINES (sizeof(triangle_guy)/sizeof(mline_t))
     76 #define NUMTHINTRIANGLEGUYLINES (sizeof(thintriangle_guy)/sizeof(mline_t))
     77 #define PUTDOT(xx,yy,cc) fb[(yy)*f_w+(xx)]=(cc)
     78 #define DOOUTCODE(oc, mx, my) \
     79 	(oc) = 0; \
     80 	if ((my) < 0) (oc) |= TOP; \
     81 	if ((my) >= f_h) (oc) |= BOTTOM; \
     82 	if ((mx) < 0) (oc) |= LEFT; \
     83 	if ((mx) >= f_w) (oc) |= RIGHT;
     84 
     85 typedef struct {
     86 	int x, y;
     87 }fpoint_t;
     88 
     89 typedef struct {
     90 	fpoint_t a, b;
     91 }fline_t;
     92 
     93 typedef struct {
     94 	fixed_t		x,y;
     95 }mpoint_t;
     96 
     97 typedef struct {
     98 	mpoint_t a, b;
     99 }mline_t;
    100 
    101 typedef struct {
    102 	fixed_t slp, islp;
    103 }islope_t;
    104 
    105 #define R ((8*PLAYERRADIUS)/7)
    106 
    107 mline_t player_arrow[] = {
    108 	{{ -R+R/8, 0 }, { R, 0 }},
    109 	{{ R, 0 }, { R-R/2, R/4 }}, 
    110 	{{ R, 0 }, { R-R/2, -R/4 }},
    111 	{{ -R+R/8, 0 }, { -R-R/8, R/4 }},
    112 	{{ -R+R/8, 0 }, { -R-R/8, -R/4 }},
    113 	{{ -R+3*R/8, 0 }, { -R+R/8, R/4 }},
    114 	{{ -R+3*R/8, 0 }, { -R+R/8, -R/4 }}
    115 };
    116 #undef R
    117 
    118 #define R ((8*PLAYERRADIUS)/7)
    119 mline_t cheat_player_arrow[] = {
    120 	{ { -R+R/8, 0 }, { R, 0 } },
    121 	{ { R, 0 }, { R-R/2, R/6 } }, 
    122 	{ { R, 0 }, { R-R/2, -R/6 } },
    123 	{ { -R+R/8, 0 }, { -R-R/8, R/6 } },
    124 	{ { -R+R/8, 0 }, { -R-R/8, -R/6 } },
    125 	{ { -R+3*R/8, 0 }, { -R+R/8, R/6 } },
    126 	{ { -R+3*R/8, 0 }, { -R+R/8, -R/6 } },
    127 	{ { -R/2, 0 }, { -R/2, -R/6 } },
    128 	{ { -R/2, -R/6 }, { -R/2+R/6, -R/6 } },
    129 	{ { -R/2+R/6, -R/6 }, { -R/2+R/6, R/4 } },
    130 	{ { -R/6, 0 }, { -R/6, -R/6 } },
    131 	{ { -R/6, -R/6 }, { 0, -R/6 } },
    132 	{ { 0, -R/6 }, { 0, R/4 } },
    133 	{ { R/6, R/4 }, { R/6, -R/7 } },
    134 	{ { R/6, -R/7 }, { R/6+R/32, -R/7-R/32 } },
    135 	{ { R/6+R/32, -R/7-R/32 }, { R/6+R/10, -R/7 } }
    136 };
    137 #undef R
    138 
    139 #define R (FRACUNIT)
    140 mline_t triangle_guy[] = {
    141 	{ { -.867*R, -.5*R }, { .867*R, -.5*R } },
    142 	{ { .867*R, -.5*R } , { 0, R } },
    143 	{ { 0, R }, { -.867*R, -.5*R } }
    144 };
    145 #undef R
    146 
    147 #define R (FRACUNIT)
    148 mline_t thintriangle_guy[] = {
    149 	{ { -.5*R, -.7*R }, { R, 0 } },
    150 	{ { R, 0 }, { -.5*R, .7*R } },
    151 	{ { -.5*R, .7*R }, { -.5*R, -.7*R } }
    152 };
    153 #undef R
    154 
    155 static int 	cheating = 0;
    156 static int 	grid = 0;
    157 static int 	leveljuststarted = 1; 
    158 boolean    	automapactive = false;
    159 static int 	finit_width = SCREENWIDTH;
    160 static int 	finit_height = SCREENHEIGHT - 32;
    161 static int 	f_x;
    162 static int	f_y;
    163 static int 	f_w;
    164 static int	f_h;
    165 static int 	lightlev; 	
    166 static byte*	fb; 		
    167 static int 	amclock;
    168 static mpoint_t m_paninc;
    169 static fixed_t 	mtof_zoommul;
    170 static fixed_t 	ftom_zoommul;
    171 static fixed_t 	m_x, m_y;  
    172 static fixed_t 	m_x2, m_y2;
    173 static fixed_t 	m_w;
    174 static fixed_t	m_h;
    175 static fixed_t 	min_x;
    176 static fixed_t	min_y;
    177 static fixed_t 	max_x;
    178 static fixed_t  max_y;
    179 static fixed_t 	max_w;
    180 static fixed_t  max_h;
    181 static fixed_t 	min_w;
    182 static fixed_t  min_h;
    183 static fixed_t 	min_scale_mtof;
    184 static fixed_t 	max_scale_mtof;
    185 static fixed_t old_m_w, old_m_h;
    186 static fixed_t old_m_x, old_m_y;
    187 static mpoint_t f_oldloc;
    188 static fixed_t scale_mtof = INITSCALEMTOF;
    189 static fixed_t scale_ftom;
    190 static player_t *plr;
    191 static patch_t *marknums[10];
    192 static mpoint_t markpoints[AM_NUMMARKPOINTS];
    193 static int markpointnum = 0;
    194 static int followplayer = 1;
    195 static unsigned char cheat_amap_seq[] = { 0xb2, 0x26, 0x26, 0x2e, 0xff };
    196 static cheatseq_t cheat_amap = { cheat_amap_seq, 0 };
    197 static boolean stopped = true;
    198 extern boolean viewactive;
    199 
    200 void V_MarkRect(int x, int y, int width, int height);
    201 
    202 void
    203 AM_getIslope(mline_t* ml, islope_t* is)
    204 {
    205 	int dx, dy;
    206 
    207 	dy = ml->a.y - ml->b.y;
    208 	dx = ml->b.x - ml->a.x;
    209 	if (!dy) is->islp = (dx<0?-INT_MAX:INT_MAX);
    210 	else is->islp = FixedDiv(dx, dy);
    211 	if (!dx) is->slp = (dy<0?-INT_MAX:INT_MAX);
    212 	else is->slp = FixedDiv(dy, dx);
    213 }
    214 
    215 void
    216 AM_activateNewScale()
    217 {
    218 	m_x += m_w/2;
    219 	m_y += m_h/2;
    220 	m_w = FTOM(f_w);
    221 	m_h = FTOM(f_h);
    222 	m_x -= m_w/2;
    223 	m_y -= m_h/2;
    224 	m_x2 = m_x + m_w;
    225 	m_y2 = m_y + m_h;
    226 }
    227 
    228 void
    229 AM_saveScaleAndLoc()
    230 {
    231 	old_m_x = m_x;
    232 	old_m_y = m_y;
    233 	old_m_w = m_w;
    234 	old_m_h = m_h;
    235 }
    236 
    237 void
    238 AM_restoreScaleAndLoc()
    239 {
    240 	m_w = old_m_w;
    241 	m_h = old_m_h;
    242 	if (!followplayer) {
    243 		m_x = old_m_x;
    244 		m_y = old_m_y;
    245 	} else {
    246 		m_x = plr->mo->x - m_w/2;
    247 		m_y = plr->mo->y - m_h/2;
    248 	}
    249 	m_x2 = m_x + m_w;
    250 	m_y2 = m_y + m_h;
    251 	scale_mtof = FixedDiv(f_w<<FRACBITS, m_w);
    252 	scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
    253 }
    254 
    255 void
    256 AM_addMark()
    257 {
    258 	markpoints[markpointnum].x = m_x + m_w/2;
    259 	markpoints[markpointnum].y = m_y + m_h/2;
    260 	markpointnum = (markpointnum + 1) % AM_NUMMARKPOINTS;
    261 }
    262 
    263 void
    264 AM_findMinMaxBoundaries()
    265 {
    266 	int     i;
    267 	fixed_t a;
    268 	fixed_t b;
    269 
    270 	min_x = min_y =  INT_MAX;
    271 	max_x = max_y = -INT_MAX;
    272 	for (i = 0; i < numvertexes; ++i) {
    273 		if (vertexes[i].x < min_x) min_x = vertexes[i].x;
    274 		if (vertexes[i].x > max_x) max_x = vertexes[i].x;
    275 		if (vertexes[i].y < min_y) min_y = vertexes[i].y;
    276 		if (vertexes[i].y > max_y) max_y = vertexes[i].y;
    277 	}
    278 	max_w = max_x - min_x;
    279 	max_h = max_y - min_y;
    280 	min_w = 2 * PLAYERRADIUS;
    281 	min_h = 2 * PLAYERRADIUS;
    282 	a = FixedDiv(f_w << FRACBITS, max_w);
    283 	b = FixedDiv(f_h << FRACBITS, max_h);
    284 	min_scale_mtof = a < b ? a : b;
    285 	max_scale_mtof = FixedDiv(f_h<<FRACBITS, 2*PLAYERRADIUS);
    286 }
    287 
    288 void
    289 AM_changeWindowLoc()
    290 {
    291 	if (m_paninc.x || m_paninc.y) {
    292 		followplayer = 0;
    293 		f_oldloc.x = INT_MAX;
    294 	}
    295 	m_x += m_paninc.x;
    296 	m_y += m_paninc.y;
    297 	if (m_x + m_w/2 > max_x) m_x = max_x - m_w/2;
    298 	if (m_x + m_w/2 < min_x) m_x = min_x - m_w/2;
    299 	if (m_y + m_h/2 > max_y) m_y = max_y - m_h/2;
    300 	if (m_y + m_h/2 < min_y) m_y = min_y - m_h/2;
    301 	m_x2 = m_x + m_w;
    302 	m_y2 = m_y + m_h;
    303 }
    304 
    305 void
    306 AM_initVariables()
    307 {
    308 	static event_t st_notify = { ev_keyup, AM_MSGENTERED };
    309 	int            pnum;
    310 
    311 	automapactive = true;
    312 	fb = screens[0];
    313 	f_oldloc.x = INT_MAX;
    314 	amclock = 0;
    315 	lightlev = 0;
    316 	m_paninc.x = m_paninc.y = 0;
    317 	ftom_zoommul = FRACUNIT;
    318 	mtof_zoommul = FRACUNIT;
    319 	m_w = FTOM(f_w);
    320 	m_h = FTOM(f_h);
    321 	if (!playeringame[pnum = consoleplayer])
    322 		for (pnum=0;pnum<MAXPLAYERS;pnum++)
    323 			if (playeringame[pnum]) break;
    324 	plr = &players[pnum];
    325 	m_x = plr->mo->x - m_w/2;
    326 	m_y = plr->mo->y - m_h/2;
    327 	AM_changeWindowLoc();
    328 	old_m_x = m_x;
    329 	old_m_y = m_y;
    330 	old_m_w = m_w;
    331 	old_m_h = m_h;
    332 	ST_Responder(&st_notify);
    333 }
    334 
    335 void
    336 AM_loadPics()
    337 {
    338 	int  i;
    339 	char namebuf[9];
    340  
    341 	for (i = 0; i < 10; ++i) {
    342 		sprintf(namebuf, "AMMNUM%d", i);
    343 		marknums[i] = W_CacheLumpName(namebuf, PU_STATIC);
    344 	}
    345 }
    346 
    347 void
    348 AM_unloadPics()
    349 {
    350 	int i;
    351  
    352 	for (i=0;i<10;i++)
    353 	Z_ChangeTag(marknums[i], PU_CACHE);
    354 
    355 }
    356 
    357 void AM_clearMarks()
    358 {
    359 	int i;
    360 
    361 	for (i=0;i<AM_NUMMARKPOINTS;i++)
    362 	markpoints[i].x = -1;
    363 	markpointnum = 0;
    364 }
    365 
    366 void
    367 AM_LevelInit()
    368 {
    369 	leveljuststarted = 0;
    370 	f_x = f_y = 0;
    371 	f_w = finit_width;
    372 	f_h = finit_height;
    373 	AM_clearMarks();
    374 	AM_findMinMaxBoundaries();
    375 	scale_mtof = FixedDiv(min_scale_mtof, (int) (0.7*FRACUNIT));
    376 	if (scale_mtof > max_scale_mtof) scale_mtof = min_scale_mtof;
    377 	scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
    378 }
    379 
    380 void
    381 AM_Stop()
    382 {
    383 	static event_t st_notify = { 0, ev_keyup, AM_MSGEXITED };
    384 
    385 	AM_unloadPics();
    386 	automapactive = false;
    387 	ST_Responder(&st_notify);
    388 	stopped = true;
    389 }
    390 
    391 void
    392 AM_Start()
    393 {
    394 	static int lastlevel = -1, lastepisode = -1;
    395 
    396 	if (!stopped)
    397 		AM_Stop();
    398 	stopped = false;
    399 	if (lastlevel != gamemap || lastepisode != gameepisode) {
    400 		AM_LevelInit();
    401 		lastlevel = gamemap;
    402 		lastepisode = gameepisode;
    403 	}
    404 	AM_initVariables();
    405 	AM_loadPics();
    406 }
    407 
    408 void
    409 AM_minOutWindowScale()
    410 {
    411 	scale_mtof = min_scale_mtof;
    412 	scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
    413 	AM_activateNewScale();
    414 }
    415 
    416 void
    417 AM_maxOutWindowScale()
    418 {
    419 	scale_mtof = max_scale_mtof;
    420 	scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
    421 	AM_activateNewScale();
    422 }
    423 
    424 boolean
    425 AM_Responder(event_t* ev)
    426 {
    427 	static int  bigstate=0;
    428 	static char buffer[20];
    429 	int         rc;
    430 
    431 	rc = false;
    432 	if (!automapactive) {
    433 		if (ev->type == ev_keydown && ev->data1 == AM_STARTKEY) {
    434 			AM_Start();
    435 			viewactive = false;
    436 			rc = true;
    437 		}
    438 	}
    439 	else if (ev->type == ev_keydown) {
    440 		rc = true;
    441 		switch (ev->data1) {
    442 			case AM_PANRIGHTKEY:
    443 				if (!followplayer) m_paninc.x = FTOM(F_PANINC);
    444 				else rc = false;
    445 				break;
    446 			case AM_PANLEFTKEY:
    447 				if (!followplayer) m_paninc.x = -FTOM(F_PANINC);
    448 				else rc = false;
    449 				break;
    450 			case AM_PANUPKEY:
    451 				if (!followplayer) m_paninc.y = FTOM(F_PANINC);
    452 				else rc = false;
    453 				break;
    454 			case AM_PANDOWNKEY:
    455 				if (!followplayer) m_paninc.y = -FTOM(F_PANINC);
    456 				else rc = false;
    457 				break;
    458 			case AM_ZOOMOUTKEY:
    459 				mtof_zoommul = M_ZOOMOUT;
    460 				ftom_zoommul = M_ZOOMIN;
    461 				break;
    462 			case AM_ZOOMINKEY:
    463 				mtof_zoommul = M_ZOOMIN;
    464 				ftom_zoommul = M_ZOOMOUT;
    465 				break;
    466 			case AM_ENDKEY:
    467 				bigstate = 0;
    468 				viewactive = true;
    469 				AM_Stop();
    470 				break;
    471 			case AM_GOBIGKEY:
    472 				bigstate = !bigstate;
    473 				if (bigstate) {
    474 					AM_saveScaleAndLoc();
    475 					AM_minOutWindowScale();
    476 				}
    477 				else AM_restoreScaleAndLoc();
    478 				break;
    479 			case AM_FOLLOWKEY:
    480 				followplayer = !followplayer;
    481 				f_oldloc.x = INT_MAX;
    482 				plr->message = followplayer ? lang[AMSTR_FOLLOWON] : lang[AMSTR_FOLLOWOFF];
    483 				break;
    484 			case AM_GRIDKEY:
    485 				grid = !grid;
    486 				plr->message = grid ? lang[AMSTR_GRIDON] : lang[AMSTR_GRIDOFF];
    487 				break;
    488 			case AM_MARKKEY:
    489 				sprintf(buffer, "%s %d", lang[AMSTR_MARKEDSPOT], markpointnum);
    490 				plr->message = buffer;
    491 				AM_addMark();
    492 				break;
    493 			case AM_CLEARMARKKEY:
    494 				AM_clearMarks();
    495 				plr->message = lang[AMSTR_MARKSCLEARED];
    496 				break;
    497 			default:
    498 				rc = false;
    499 		}
    500 		if (!deathmatch && cht_CheckCheat(&cheat_amap, ev->data1)) {
    501 			rc = false;
    502 			cheating = (cheating+1) % 3;
    503 		}
    504 	}
    505 	else if (ev->type == ev_keyup) {
    506 		rc = false;
    507 		switch (ev->data1) {
    508 			case AM_PANRIGHTKEY:
    509 				if (!followplayer) m_paninc.x = 0;
    510 				break;
    511 			case AM_PANLEFTKEY:
    512 				if (!followplayer) m_paninc.x = 0;
    513 				break;
    514 			case AM_PANUPKEY:
    515 				if (!followplayer) m_paninc.y = 0;
    516 				break;
    517 			case AM_PANDOWNKEY:
    518 				if (!followplayer) m_paninc.y = 0;
    519 				break;
    520 			case AM_ZOOMOUTKEY:
    521 			case AM_ZOOMINKEY:
    522 				mtof_zoommul = FRACUNIT;
    523 				ftom_zoommul = FRACUNIT;
    524 				break;
    525 		}
    526 	}
    527 	return rc;
    528 }
    529 
    530 void
    531 AM_changeWindowScale()
    532 {
    533 	scale_mtof = FixedMul(scale_mtof, mtof_zoommul);
    534 	scale_ftom = FixedDiv(FRACUNIT, scale_mtof);
    535 	if (scale_mtof < min_scale_mtof) AM_minOutWindowScale();
    536 	if (scale_mtof > max_scale_mtof) AM_maxOutWindowScale();
    537 	else AM_activateNewScale();
    538 }
    539 
    540 void
    541 AM_doFollowPlayer()
    542 {
    543 	if (f_oldloc.x != plr->mo->x || f_oldloc.y != plr->mo->y) {
    544 		m_x = FTOM(MTOF(plr->mo->x)) - m_w/2;
    545 		m_y = FTOM(MTOF(plr->mo->y)) - m_h/2;
    546 		m_x2 = m_x + m_w;
    547 		m_y2 = m_y + m_h;
    548 		f_oldloc.x = plr->mo->x;
    549 		f_oldloc.y = plr->mo->y;
    550 	}
    551 }
    552 
    553 void
    554 AM_updateLightLev()
    555 {
    556 	static int litelevels[] = { 0, 4, 7, 10, 12, 14, 15, 15 };
    557 	static int nexttic = 0;
    558 	static int litelevelscnt = 0;
    559 
    560 	if (amclock>nexttic) {
    561 		lightlev = litelevels[litelevelscnt++];
    562 		if (litelevelscnt == sizeof(litelevels)/sizeof(int)) litelevelscnt = 0;
    563 		nexttic = amclock + 6 - (amclock % 6);
    564 	}
    565 }
    566 
    567 void
    568 AM_Ticker()
    569 {
    570 	if (!automapactive)
    571 		return;
    572 	amclock++;
    573 	if (followplayer) AM_doFollowPlayer();
    574 	if (ftom_zoommul != FRACUNIT)
    575 	AM_changeWindowScale();
    576 	if (m_paninc.x || m_paninc.y)
    577 	AM_changeWindowLoc();
    578 }
    579 
    580 void
    581 AM_clearFB(int color)
    582 {
    583 	memset(fb, color, f_w * f_h);
    584 }
    585 
    586 boolean
    587 AM_clipMline(mline_t* ml, fline_t* fl)
    588 {
    589 	enum {
    590 		LEFT	=1,
    591 		RIGHT	=2,
    592 		BOTTOM	=4,
    593 		TOP	=8
    594 	};
    595 
    596 	int outcode1, outcode2, outside, dx, dy;
    597 	fpoint_t	tmp;
    598 
    599 	outcode1 = outcode2 = 0;
    600 	if (ml->a.y > m_y2) outcode1 = TOP;
    601 	if (ml->a.y < m_y) outcode1 = BOTTOM;
    602 	if (ml->b.y > m_y2) outcode2 = TOP;
    603 	if (ml->b.y < m_y) outcode2 = BOTTOM;
    604 	if (outcode1 & outcode2) return false;
    605 	if (ml->a.x < m_x) outcode1 |= LEFT;
    606 	if (ml->a.x > m_x2) outcode1 |= RIGHT;
    607 	if (ml->b.x < m_x) outcode2 |= LEFT;
    608 	if (ml->b.x > m_x2) outcode2 |= RIGHT;
    609 	if (outcode1 & outcode2) return false;
    610 	fl->a.x = CXMTOF(ml->a.x);
    611 	fl->a.y = CYMTOF(ml->a.y);
    612 	fl->b.x = CXMTOF(ml->b.x);
    613 	fl->b.y = CYMTOF(ml->b.y);
    614 	DOOUTCODE(outcode1, fl->a.x, fl->a.y);
    615 	DOOUTCODE(outcode2, fl->b.x, fl->b.y);
    616 	if (outcode1 & outcode2) return false;
    617 
    618 	while (outcode1 | outcode2) {
    619 		if (outcode1) outside = outcode1;
    620 		else outside = outcode2;
    621 		if (outside & TOP) {
    622 			dy = fl->a.y - fl->b.y;
    623 			dx = fl->b.x - fl->a.x;
    624 			tmp.x = fl->a.x + (dx*(fl->a.y))/dy;
    625 			tmp.y = 0;
    626 		}
    627 		if (outside & BOTTOM) {
    628 			dy = fl->a.y - fl->b.y;
    629 			dx = fl->b.x - fl->a.x;
    630 			tmp.x = fl->a.x + (dx*(fl->a.y-f_h))/dy;
    631 			tmp.y = f_h-1;
    632 		}
    633 		if (outside & RIGHT) {
    634 			dy = fl->b.y - fl->a.y;
    635 			dx = fl->b.x - fl->a.x;
    636 			tmp.y = fl->a.y + (dy*(f_w-1 - fl->a.x))/dx;
    637 			tmp.x = f_w-1;
    638 		}
    639 		if (outside & LEFT) {
    640 			dy = fl->b.y - fl->a.y;
    641 			dx = fl->b.x - fl->a.x;
    642 			tmp.y = fl->a.y + (dy*(-fl->a.x))/dx;
    643 			tmp.x = 0;
    644 		}
    645 		if (outside == outcode1) {
    646 			fl->a = tmp;
    647 			DOOUTCODE(outcode1, fl->a.x, fl->a.y);
    648 		} else {
    649 			fl->b = tmp;
    650 			DOOUTCODE(outcode2, fl->b.x, fl->b.y);
    651 		}
    652 		if (outcode1 & outcode2) return false;
    653 	}
    654 	return true;
    655 }
    656 #undef DOOUTCODE
    657 
    658 void
    659 AM_drawFline(fline_t* fl, int color)
    660 {
    661 	static int fuck = 0;
    662 	int x, y, dx, dy, sx, sy, ax, ay, d;
    663 	if (fl->a.x < 0 || fl->a.x >= f_w || fl->a.y < 0 || fl->a.y >= f_h || fl->b.x < 0 || fl->b.x >= f_w || fl->b.y < 0 || fl->b.y >= f_h) {
    664 		fprintf(stderr, "fuck %d \r", fuck++);
    665 		return;
    666 	}
    667 	dx = fl->b.x - fl->a.x;
    668 	ax = 2 * (dx<0 ? -dx : dx);
    669 	sx = dx<0 ? -1 : 1;
    670 	dy = fl->b.y - fl->a.y;
    671 	ay = 2 * (dy<0 ? -dy : dy);
    672 	sy = dy<0 ? -1 : 1;
    673 	x = fl->a.x;
    674 	y = fl->a.y;
    675 	if (ax > ay) {
    676 		d = ay - ax/2;
    677 		for (;;) {
    678 			PUTDOT(x,y,color);
    679 			if (x == fl->b.x) return;
    680 			if (d>=0) {
    681 				y += sy;
    682 				d -= ax;
    683 			}
    684 			x += sx;
    685 			d += ay;
    686 		}
    687 	} else {
    688 		d = ax - ay/2;
    689 		for (;;) {
    690 			PUTDOT(x, y, color);
    691 			if (y == fl->b.y) return;
    692 			if (d >= 0) {
    693 				x += sx;
    694 				d -= ay;
    695 			}
    696 			y += sy;
    697 			d += ax;
    698 		}
    699 	}
    700 }
    701 
    702 void
    703 AM_drawMline(mline_t* ml, int color)
    704 {
    705 	static fline_t fl;
    706 
    707 	if (AM_clipMline(ml, &fl)) AM_drawFline(&fl, color);
    708 }
    709 
    710 void
    711 AM_drawGrid(int color)
    712 {
    713 	fixed_t x, y, start, end;
    714 	mline_t ml;
    715 
    716 	start = m_x;
    717 	if ((start-bmaporgx)%(MAPBLOCKUNITS<<FRACBITS))	start += (MAPBLOCKUNITS<<FRACBITS) - ((start-bmaporgx)%(MAPBLOCKUNITS<<FRACBITS));
    718 	end = m_x + m_w;
    719 	ml.a.y = m_y;
    720 	ml.b.y = m_y+m_h;
    721 	for (x=start; x<end; x+=(MAPBLOCKUNITS<<FRACBITS)) {
    722 		ml.a.x = x;
    723 		ml.b.x = x;
    724 		AM_drawMline(&ml, color);
    725 	}
    726 	start = m_y;
    727 	if ((start-bmaporgy)%(MAPBLOCKUNITS<<FRACBITS)) start += (MAPBLOCKUNITS<<FRACBITS) - ((start-bmaporgy)%(MAPBLOCKUNITS<<FRACBITS));
    728 	end = m_y + m_h;
    729 	ml.a.x = m_x;
    730 	ml.b.x = m_x + m_w;
    731 	for (y=start; y<end; y+=(MAPBLOCKUNITS<<FRACBITS)) {
    732 		ml.a.y = y;
    733 		ml.b.y = y;
    734 		AM_drawMline(&ml, color);
    735 	}
    736 }
    737 
    738 void
    739 AM_drawWalls()
    740 {
    741 	static mline_t l;
    742 	int            i;
    743 
    744 	for (i=0;i<numlines;i++) {
    745 		l.a.x = lines[i].v1->x;
    746 		l.a.y = lines[i].v1->y;
    747 		l.b.x = lines[i].v2->x;
    748 		l.b.y = lines[i].v2->y;
    749 		if (cheating || (lines[i].flags & ML_MAPPED)) {
    750 			if ((lines[i].flags & LINE_NEVERSEE) && !cheating) continue;
    751 			if (!lines[i].backsector) AM_drawMline(&l, WALLCOLORS+lightlev);
    752 			else {
    753 				if (lines[i].special == 39) AM_drawMline(&l, WALLCOLORS+WALLRANGE/2);
    754 				if (lines[i].flags & ML_SECRET) {
    755 					if (cheating) AM_drawMline(&l, SECRETWALLCOLORS + lightlev);
    756 					else AM_drawMline(&l, WALLCOLORS+lightlev);
    757 				}
    758 				if (lines[i].backsector->floorheight != lines[i].frontsector->floorheight) AM_drawMline(&l, FDWALLCOLORS + lightlev);
    759 				if (lines[i].backsector->ceilingheight != lines[i].frontsector->ceilingheight) AM_drawMline(&l, CDWALLCOLORS+lightlev);
    760 				if (cheating) AM_drawMline(&l, TSWALLCOLORS+lightlev);
    761 			}
    762 		}
    763 		if (plr->powers[pw_allmap])
    764 			if (!(lines[i].flags & LINE_NEVERSEE)) AM_drawMline(&l, GRAYS+3);
    765 	}
    766 }
    767 
    768 void
    769 AM_rotate(fixed_t* x, fixed_t* y, angle_t a)
    770 {
    771 	fixed_t tmpx;
    772 
    773 	tmpx = FixedMul(*x,finecosine[a>>ANGLETOFINESHIFT]) - FixedMul(*y,finesine[a>>ANGLETOFINESHIFT]);
    774 	*y = FixedMul(*x,finesine[a>>ANGLETOFINESHIFT]) + FixedMul(*y,finecosine[a>>ANGLETOFINESHIFT]);
    775 	*x = tmpx;
    776 }
    777 
    778 void
    779 AM_drawLineCharacter(mline_t* lineguy, int lineguylines, fixed_t scale, angle_t angle, int color, fixed_t x, fixed_t y)
    780 {
    781 	mline_t l;
    782 	int     i;
    783 
    784 	for (i = 0; i < lineguylines; ++i) {
    785 		l.a.x = lineguy[i].a.x;
    786 		l.a.y = lineguy[i].a.y;
    787 		if (scale) {
    788 			l.a.x = FixedMul(scale, l.a.x);
    789 			l.a.y = FixedMul(scale, l.a.y);
    790 		}
    791 		if (angle) AM_rotate(&l.a.x, &l.a.y, angle);
    792 		l.a.x += x;
    793 		l.a.y += y;
    794 		l.b.x = lineguy[i].b.x;
    795 		l.b.y = lineguy[i].b.y;
    796 		if (scale) {
    797 			l.b.x = FixedMul(scale, l.b.x);
    798 			l.b.y = FixedMul(scale, l.b.y);
    799 		}
    800 		if (angle) AM_rotate(&l.b.x, &l.b.y, angle);
    801 		l.b.x += x;
    802 		l.b.y += y;
    803 		AM_drawMline(&l, color);
    804 	}
    805 }
    806 
    807 void
    808 AM_drawPlayers()
    809 {
    810 	static int their_colors[] = { GREENS, GRAYS, BROWNS, REDS };
    811 	player_t*  p;
    812 	int        i, color, their_color;
    813 
    814 	their_color = -1;
    815 	if (!netgame) {
    816 		if (cheating) AM_drawLineCharacter(cheat_player_arrow, NUMCHEATPLYRLINES, 0, plr->mo->angle, WHITE, plr->mo->x, plr->mo->y);
    817 		else AM_drawLineCharacter(player_arrow, NUMPLYRLINES, 0, plr->mo->angle, WHITE, plr->mo->x, plr->mo->y);
    818 		return;
    819 	}
    820 	for (i = 0; i < MAXPLAYERS; ++i) {
    821 		++their_color;
    822 		p = &players[i];
    823 		if ((deathmatch && !singledemo) && p != plr) continue;
    824 		if (!playeringame[i]) continue;
    825 		if (p->powers[pw_invisibility]) color = 246;
    826 		else color = their_colors[their_color];
    827 		AM_drawLineCharacter(player_arrow, NUMPLYRLINES, 0, p->mo->angle, color, p->mo->x, p->mo->y);
    828 	}
    829 }
    830 
    831 void
    832 AM_drawThings(int colors, int colorrange)
    833 {
    834 	mobj_t* t;
    835 	int     i;
    836 
    837 	for (i = 0; i < numsectors; ++i)
    838 		for (t = sectors[i].thinglist; t; t = t->snext)
    839 			AM_drawLineCharacter(thintriangle_guy, NUMTHINTRIANGLEGUYLINES, 16<<FRACBITS, t->angle, colors+lightlev, t->x, t->y);
    840 }
    841 
    842 void
    843 AM_drawMarks()
    844 {
    845 	int i, fx, fy, w, h;
    846 
    847 	for (i = 0; i < AM_NUMMARKPOINTS; ++i) {
    848 		if (markpoints[i].x != -1) {
    849 			w = 5;
    850 			h = 6;
    851 			fx = CXMTOF(markpoints[i].x);
    852 			fy = CYMTOF(markpoints[i].y);
    853 			if (fx >= f_x && fx <= f_w - w && fy >= f_y && fy <= f_h - h) V_DrawPatch(fx, fy, FB, marknums[i]);
    854 		}
    855 	}
    856 }
    857 
    858 void
    859 AM_drawCrosshair(int color)
    860 {
    861 	fb[(f_w*(f_h+1))/2] = color;
    862 }
    863 
    864 void
    865 AM_Drawer()
    866 {
    867 	if (!automapactive)
    868 		return;
    869 	AM_clearFB(BACKGROUND);
    870 	if (grid) AM_drawGrid(GRIDCOLORS);
    871 	AM_drawWalls();
    872 	AM_drawPlayers();
    873 	if (cheating==2) AM_drawThings(THINGCOLORS, THINGRANGE);
    874 	AM_drawCrosshair(XHAIRCOLORS);
    875 	AM_drawMarks();
    876 	V_MarkRect(f_x, f_y, f_w, f_h);
    877 }