DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

am_map.cpp (24961B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
     10 it under the terms of the GNU General Public License as published by
     11 the Free Software Foundation, either version 3 of the License, or
     12 (at your option) any later version.
     13 
     14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
     15 but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 GNU General Public License for more details.
     18 
     19 You should have received a copy of the GNU General Public License
     20 along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code.  If not, please request a copy in writing from id Software at the address below.
     23 
     24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
     25 
     26 ===========================================================================
     27 */
     28 
     29 #include "Precompiled.h"
     30 #include "globaldata.h"
     31 
     32 #include <stdio.h>
     33 
     34 
     35 #include "z_zone.h"
     36 #include "doomdef.h"
     37 #include "st_stuff.h"
     38 #include "p_local.h"
     39 #include "w_wad.h"
     40 
     41 #include "m_cheat.h"
     42 #include "i_system.h"
     43 
     44 // Needs access to LFB.
     45 #include "v_video.h"
     46 
     47 // State.
     48 #include "doomstat.h"
     49 #include "r_state.h"
     50 
     51 // Data.
     52 #include "dstrings.h"
     53 
     54 #include "am_map.h"
     55 
     56 
     57 // For use if I do walls with outsides/insides
     58 
     59 // Automap colors
     60 
     61 // drawing stuff
     62 
     63 
     64 
     65 // scale on entry
     66 // how much the automap moves window per tic in frame-::g->buffer coordinates
     67 // moves 140 pixels in 1 second
     68 // how much zoom-in per tic
     69 // goes to 2x in 1 second
     70 // how much zoom-out per tic
     71 // pulls out to 0.5x in 1 second
     72 
     73 // translates between frame-::g->buffer and map distances
     74 // translates between frame-::g->buffer and map coordinates
     75 
     76 // the following is crap
     77 
     78 
     79 
     80 
     81 
     82 
     83 
     84 
     85 //
     86 // The vector graphics for the automap.
     87 //  A line drawing of the player pointing right,
     88 //   starting from the middle.
     89 //
     90 #define R ((8*PLAYERRADIUS)/7)
     91 mline_t player_arrow[] = 
     92 {
     93 	{ { -R+R/8, 0 }, { R, 0 } }, // -----
     94 	{ { R, 0 }, { R-R/2, R/4 } },  // ----->
     95 	{ { R, 0 }, { R-R/2, -R/4 } },
     96 	{ { -R+R/8, 0 }, { -R-R/8, R/4 } }, // >---->
     97 	{ { -R+R/8, 0 }, { -R-R/8, -R/4 } },
     98 	{ { -R+3*R/8, 0 }, { -R+R/8, R/4 } }, // >>--->
     99 	{ { -R+3*R/8, 0 }, { -R+R/8, -R/4 } }
    100 };
    101 #undef R
    102 
    103 #define R ((8*PLAYERRADIUS)/7)
    104 mline_t cheat_player_arrow[] = 
    105 {
    106 	{ { -R+R/8, 0 }, { R, 0 } }, // -----
    107 	{ { R, 0 }, { R-R/2, R/6 } },  // ----->
    108 	{ { R, 0 }, { R-R/2, -R/6 } },
    109 	{ { -R+R/8, 0 }, { -R-R/8, R/6 } }, // >----->
    110 	{ { -R+R/8, 0 }, { -R-R/8, -R/6 } },
    111 	{ { -R+3*R/8, 0 }, { -R+R/8, R/6 } }, // >>----->
    112 	{ { -R+3*R/8, 0 }, { -R+R/8, -R/6 } },
    113 	{ { -R/2, 0 }, { -R/2, -R/6 } }, // >>-d--->
    114 	{ { -R/2, -R/6 }, { -R/2+R/6, -R/6 } },
    115 	{ { -R/2+R/6, -R/6 }, { -R/2+R/6, R/4 } },
    116 	{ { -R/6, 0 }, { -R/6, -R/6 } }, // >>-dd-->
    117 	{ { -R/6, -R/6 }, { 0, -R/6 } },
    118 	{ { 0, -R/6 }, { 0, R/4 } },
    119 	{ { R/6, R/4 }, { R/6, -R/7 } }, // >>-ddt->
    120 	{ { R/6, -R/7 }, { R/6+R/32, -R/7-R/32 } },
    121 	{ { R/6+R/32, -R/7-R/32 }, { R/6+R/10, -R/7 } }
    122 };
    123 #undef R
    124 
    125 #define R (FRACUNIT)
    126 mline_t triangle_guy[] = 
    127 {
    128 	{ { fixed_t(-.867*R), fixed_t(-.5*R) }, { fixed_t(.867*R), fixed_t(-.5*R) } },
    129 	{ { fixed_t(.867*R), fixed_t(-.5*R) } , { 0, R } },
    130 	{ { 0, R }, { fixed_t(-.867*R), fixed_t(-.5*R) } }
    131 };
    132 #undef R
    133 
    134 #define R (FRACUNIT)
    135 mline_t thintriangle_guy[] = 
    136 {
    137 	{ { fixed_t(-.5*R), fixed_t(-.7*R) }, { R, 0 } },
    138 	{ { R, 0 }, { fixed_t(-.5*R), fixed_t(.7*R) } },
    139 	{ { fixed_t(-.5*R), fixed_t(.7*R) }, { fixed_t(-.5*R), fixed_t(-.7*R) } }
    140 };
    141 #undef R
    142 
    143 
    144 
    145 
    146 
    147 
    148 
    149 // location of window on screen
    150 
    151 // size of window on screen
    152 
    153 
    154 
    155 
    156 //
    157 // width/height of window on map (map coords)
    158 //
    159 
    160 // based on level size
    161 
    162 
    163 // based on player size
    164 
    165 
    166 
    167 // old stuff for recovery later
    168 
    169 // old location used by the Follower routine
    170 
    171 // used by MTOF to scale from map-to-frame-::g->buffer coords
    172 // used by FTOM to scale from frame-::g->buffer-to-map coords (=1/::g->scale_mtof)
    173 
    174 
    175 
    176 
    177 const unsigned char cheat_amap_seq[] = 
    178 { 
    179 	0xb2, 0x26, 0x26, 0x2e, 0xff 
    180 };
    181 cheatseq_t cheat_amap = cheatseq_t( cheat_amap_seq, 0 );
    182 
    183 
    184 //extern byte ::g->screens[][SCREENWIDTH*SCREENHEIGHT];
    185 
    186 
    187 
    188 void
    189 V_MarkRect
    190 ( int	x,
    191  int	y,
    192  int	width,
    193  int	height );
    194 
    195 // Calculates the slope and slope according to the x-axis of a line
    196 // segment in map coordinates (with the upright y-axis n' all) so
    197 // that it can be used with the brain-dead drawing stuff.
    198 
    199 void
    200 AM_getIslope
    201 ( mline_t*	ml,
    202  islope_t*	is )
    203 {
    204 	int dx, dy;
    205 
    206 	dy = ml->a.y - ml->b.y;
    207 	dx = ml->b.x - ml->a.x;
    208 	if (!dy) is->islp = (dx<0?-MAXINT:MAXINT);
    209 	else is->islp = FixedDiv(dx, dy);
    210 	if (!dx) is->slp = (dy<0?-MAXINT:MAXINT);
    211 	else is->slp = FixedDiv(dy, dx);
    212 
    213 }
    214 
    215 //
    216 //
    217 //
    218 void AM_activateNewScale(void)
    219 {
    220 	::g->m_x += ::g->m_w/2;
    221 	::g->m_y += ::g->m_h/2;
    222 	::g->m_w = FTOM(::g->f_w);
    223 	::g->m_h = FTOM(::g->f_h);
    224 	::g->m_x -= ::g->m_w/2;
    225 	::g->m_y -= ::g->m_h/2;
    226 	::g->m_x2 = ::g->m_x + ::g->m_w;
    227 	::g->m_y2 = ::g->m_y + ::g->m_h;
    228 }
    229 
    230 //
    231 //
    232 //
    233 void AM_saveScaleAndLoc(void)
    234 {
    235 	::g->old_m_x = ::g->m_x;
    236 	::g->old_m_y = ::g->m_y;
    237 	::g->old_m_w = ::g->m_w;
    238 	::g->old_m_h = ::g->m_h;
    239 }
    240 
    241 //
    242 //
    243 //
    244 void AM_restoreScaleAndLoc(void)
    245 {
    246 
    247 	::g->m_w = ::g->old_m_w;
    248 	::g->m_h = ::g->old_m_h;
    249 	if (!::g->followplayer)
    250 	{
    251 		::g->m_x = ::g->old_m_x;
    252 		::g->m_y = ::g->old_m_y;
    253 	} else {
    254 		::g->m_x = ::g->amap_plr->mo->x - ::g->m_w/2;
    255 		::g->m_y = ::g->amap_plr->mo->y - ::g->m_h/2;
    256 	}
    257 	::g->m_x2 = ::g->m_x + ::g->m_w;
    258 	::g->m_y2 = ::g->m_y + ::g->m_h;
    259 
    260 	// Change the scaling multipliers
    261 	::g->scale_mtof = FixedDiv(::g->f_w<<FRACBITS, ::g->m_w);
    262 	::g->scale_ftom = FixedDiv(FRACUNIT, ::g->scale_mtof);
    263 }
    264 
    265 //
    266 // adds a marker at the current location
    267 //
    268 void AM_addMark(void)
    269 {
    270 	::g->markpoints[::g->markpointnum].x = ::g->m_x + ::g->m_w/2;
    271 	::g->markpoints[::g->markpointnum].y = ::g->m_y + ::g->m_h/2;
    272 	::g->markpointnum = (::g->markpointnum + 1) % AM_NUMMARKPOINTS;
    273 
    274 }
    275 
    276 //
    277 // Determines bounding box of all vertices,
    278 // sets global variables controlling zoom range.
    279 //
    280 void AM_findMinMaxBoundaries(void)
    281 {
    282 	int i;
    283 	fixed_t a;
    284 	fixed_t b;
    285 
    286 	::g->min_x = ::g->min_y =  MAXINT;
    287 	::g->max_x = ::g->max_y = -MAXINT;
    288 
    289 	for (i=0; i < ::g->numvertexes; i++)
    290 	{
    291 		if (::g->vertexes[i].x < ::g->min_x)
    292 			::g->min_x = ::g->vertexes[i].x;
    293 		else if (::g->vertexes[i].x > ::g->max_x)
    294 			::g->max_x = ::g->vertexes[i].x;
    295 
    296 		if (::g->vertexes[i].y < ::g->min_y)
    297 			::g->min_y = ::g->vertexes[i].y;
    298 		else if (::g->vertexes[i].y > ::g->max_y)
    299 			::g->max_y = ::g->vertexes[i].y;
    300 	}
    301 
    302 	::g->max_w = ::g->max_x - ::g->min_x;
    303 	::g->max_h = ::g->max_y - ::g->min_y;
    304 
    305 	::g->min_w = 2*PLAYERRADIUS; // const? never changed?
    306 	::g->min_h = 2*PLAYERRADIUS;
    307 
    308 	a = FixedDiv(::g->f_w<<FRACBITS, ::g->max_w);
    309 	b = FixedDiv(::g->f_h<<FRACBITS, ::g->max_h);
    310 
    311 	::g->min_scale_mtof = a < b ? a : b;
    312 	::g->max_scale_mtof = FixedDiv(::g->f_h<<FRACBITS, 2*PLAYERRADIUS);
    313 
    314 }
    315 
    316 
    317 //
    318 //
    319 //
    320 void AM_changeWindowLoc(void)
    321 {
    322 	if (::g->m_paninc.x || ::g->m_paninc.y)
    323 	{
    324 		::g->followplayer = 0;
    325 		::g->f_oldloc.x = MAXINT;
    326 	}
    327 
    328 	::g->m_x += ::g->m_paninc.x;
    329 	::g->m_y += ::g->m_paninc.y;
    330 
    331 	if (::g->m_x + ::g->m_w/2 > ::g->max_x)
    332 		::g->m_x = ::g->max_x - ::g->m_w/2;
    333 	else if (::g->m_x + ::g->m_w/2 < ::g->min_x)
    334 		::g->m_x = ::g->min_x - ::g->m_w/2;
    335 
    336 	if (::g->m_y + ::g->m_h/2 > ::g->max_y)
    337 		::g->m_y = ::g->max_y - ::g->m_h/2;
    338 	else if (::g->m_y + ::g->m_h/2 < ::g->min_y)
    339 		::g->m_y = ::g->min_y - ::g->m_h/2;
    340 
    341 	::g->m_x2 = ::g->m_x + ::g->m_w;
    342 	::g->m_y2 = ::g->m_y + ::g->m_h;
    343 }
    344 
    345 
    346 //
    347 //
    348 //
    349 void AM_initVariables(void)
    350 {
    351 	static event_t st_notify = { ev_keyup, AM_MSGENTERED };
    352 	int pnum;
    353 
    354 	::g->automapactive = true;
    355 	::g->fb = ::g->screens[0];
    356 
    357 	::g->f_oldloc.x = MAXINT;
    358 	::g->amclock = 0;
    359 	::g->lightlev = 0;
    360 
    361 	::g->m_paninc.x = ::g->m_paninc.y = 0;
    362 	::g->ftom_zoommul = FRACUNIT;
    363 	::g->mtof_zoommul = FRACUNIT;
    364 
    365 	::g->m_w = FTOM(::g->f_w);
    366 	::g->m_h = FTOM(::g->f_h);
    367 
    368 	// find player to center on initially
    369 	if (!::g->playeringame[pnum = ::g->consoleplayer])
    370 		for (pnum=0;pnum<MAXPLAYERS;pnum++)
    371 			if (::g->playeringame[pnum])
    372 				break;
    373 
    374 	::g->amap_plr = &::g->players[pnum];
    375 	::g->m_x = ::g->amap_plr->mo->x - ::g->m_w/2;
    376 	::g->m_y = ::g->amap_plr->mo->y - ::g->m_h/2;
    377 	AM_changeWindowLoc();
    378 
    379 	// for saving & restoring
    380 	::g->old_m_x = ::g->m_x;
    381 	::g->old_m_y = ::g->m_y;
    382 	::g->old_m_w = ::g->m_w;
    383 	::g->old_m_h = ::g->m_h;
    384 
    385 	// inform the status bar of the change
    386 	ST_Responder(&st_notify);
    387 
    388 }
    389 
    390 //
    391 // 
    392 //
    393 void AM_loadPics(void)
    394 {
    395 	int i;
    396 	char namebuf[9];
    397 
    398 	for (i=0;i<10;i++)
    399 	{
    400 		sprintf(namebuf, "AMMNUM%d", i);
    401 		::g->marknums[i] = (patch_t*)W_CacheLumpName(namebuf, PU_STATIC_SHARED);
    402 	}
    403 
    404 }
    405 
    406 void AM_unloadPics(void)
    407 {
    408 //	int i;
    409 
    410 }
    411 
    412 void AM_clearMarks(void)
    413 {
    414 	int i;
    415 
    416 	for (i=0;i<AM_NUMMARKPOINTS;i++)
    417 		::g->markpoints[i].x = -1; // means empty
    418 	::g->markpointnum = 0;
    419 }
    420 
    421 //
    422 // should be called at the start of every level
    423 // right now, i figure it out myself
    424 //
    425 void AM_LevelInit(void)
    426 {
    427 	::g->leveljuststarted = 0;
    428 
    429 	::g->f_x = ::g->f_y = 0;
    430 	::g->f_w = ::g->finit_width;
    431 	::g->f_h = ::g->finit_height;
    432 
    433 	AM_clearMarks();
    434 
    435 	AM_findMinMaxBoundaries();
    436 	::g->scale_mtof = FixedDiv(::g->min_scale_mtof, (int) (0.7*FRACUNIT));
    437 	if (::g->scale_mtof > ::g->max_scale_mtof)
    438 		::g->scale_mtof = ::g->min_scale_mtof;
    439 	::g->scale_ftom = FixedDiv(FRACUNIT, ::g->scale_mtof);
    440 }
    441 
    442 
    443 
    444 
    445 //
    446 //
    447 //
    448 void AM_Stop (void)
    449 {
    450 	static event_t st_notify = { (evtype_t)0, ev_keyup, AM_MSGEXITED };
    451 
    452 	AM_unloadPics();
    453 	::g->automapactive = false;
    454 	ST_Responder(&st_notify);
    455 	::g->stopped = true;
    456 }
    457 
    458 //
    459 //
    460 //
    461 void AM_Start (void)
    462 {
    463 
    464 	if (!::g->stopped) AM_Stop();
    465 	::g->stopped = false;
    466 	if (::g->lastlevel != ::g->gamemap || ::g->lastepisode != ::g->gameepisode)
    467 	{
    468 		AM_LevelInit();
    469 		::g->lastlevel = ::g->gamemap;
    470 		::g->lastepisode = ::g->gameepisode;
    471 	}
    472 	AM_initVariables();
    473 	AM_loadPics();
    474 }
    475 
    476 //
    477 // set the window scale to the maximum size
    478 //
    479 void AM_minOutWindowScale(void)
    480 {
    481 	::g->scale_mtof = ::g->min_scale_mtof;
    482 	::g->scale_ftom = FixedDiv(FRACUNIT, ::g->scale_mtof);
    483 	AM_activateNewScale();
    484 }
    485 
    486 //
    487 // set the window scale to the minimum size
    488 //
    489 void AM_maxOutWindowScale(void)
    490 {
    491 	::g->scale_mtof = ::g->max_scale_mtof;
    492 	::g->scale_ftom = FixedDiv(FRACUNIT, ::g->scale_mtof);
    493 	AM_activateNewScale();
    494 }
    495 
    496 
    497 //
    498 // Handle ::g->events (user inputs) in automap mode
    499 //
    500 qboolean
    501 AM_Responder
    502 ( event_t*	ev )
    503 {
    504 
    505 	int rc;
    506 	rc = false;
    507 
    508 	if (!::g->automapactive)
    509 	{
    510 		if (ev->type == ev_keydown && ev->data1 == AM_STARTKEY)
    511 		{
    512 			AM_Start ();
    513 			::g->viewactive = false;
    514 			rc = true;
    515 		}
    516 	}
    517 
    518 	else if (ev->type == ev_keydown)
    519 	{
    520 
    521 		rc = true;
    522 		switch(ev->data1)
    523 		{
    524 		case AM_PANRIGHTKEY: // pan right
    525 			if (!::g->followplayer) ::g->m_paninc.x = FTOM(F_PANINC);
    526 			else rc = false;
    527 			break;
    528 		case AM_PANLEFTKEY: // pan left
    529 			if (!::g->followplayer) ::g->m_paninc.x = -FTOM(F_PANINC);
    530 			else rc = false;
    531 			break;
    532 		case AM_PANUPKEY: // pan up
    533 			if (!::g->followplayer) ::g->m_paninc.y = FTOM(F_PANINC);
    534 			else rc = false;
    535 			break;
    536 		case AM_PANDOWNKEY: // pan down
    537 			if (!::g->followplayer) ::g->m_paninc.y = -FTOM(F_PANINC);
    538 			else rc = false;
    539 			break;
    540 		case AM_ZOOMOUTKEY: // zoom out
    541 			::g->mtof_zoommul = M_ZOOMOUT;
    542 			::g->ftom_zoommul = M_ZOOMIN;
    543 			break;
    544 		case AM_ZOOMINKEY: // zoom in
    545 			::g->mtof_zoommul = M_ZOOMIN;
    546 			::g->ftom_zoommul = M_ZOOMOUT;
    547 			break;
    548 		case AM_ENDKEY:
    549 			::g->bigstate = 0;
    550 			::g->viewactive = true;
    551 			AM_Stop ();
    552 			break;
    553 		case AM_GOBIGKEY:
    554 			::g->bigstate = !::g->bigstate;
    555 			if (::g->bigstate)
    556 			{
    557 				AM_saveScaleAndLoc();
    558 				AM_minOutWindowScale();
    559 			}
    560 			else AM_restoreScaleAndLoc();
    561 			break;
    562 		case AM_FOLLOWKEY:
    563 			::g->followplayer = !::g->followplayer;
    564 			::g->f_oldloc.x = MAXINT;
    565 			::g->amap_plr->message = ::g->followplayer ? AMSTR_FOLLOWON : AMSTR_FOLLOWOFF;
    566 			break;
    567 		case AM_GRIDKEY:
    568 			::g->grid = !::g->grid;
    569 			::g->amap_plr->message = ::g->grid ? AMSTR_GRIDON : AMSTR_GRIDOFF;
    570 			break;
    571 		case AM_MARKKEY:
    572 			sprintf(::g->buffer, "%s %d", AMSTR_MARKEDSPOT, ::g->markpointnum);
    573 			::g->amap_plr->message = ::g->buffer;
    574 			AM_addMark();
    575 			break;
    576 		case AM_CLEARMARKKEY:
    577 			AM_clearMarks();
    578 			::g->amap_plr->message = AMSTR_MARKSCLEARED;
    579 			break;
    580 		default:
    581 			::g->cheatstate=0;
    582 			rc = false;
    583 		}
    584 		if (!::g->deathmatch && cht_CheckCheat(&cheat_amap, ev->data1))
    585 		{
    586 			rc = false;
    587 			::g->cheating = (::g->cheating+1) % 3;
    588 		}
    589 	}
    590 
    591 	else if (ev->type == ev_keyup)
    592 	{
    593 		rc = false;
    594 		switch (ev->data1)
    595 		{
    596 		case AM_PANRIGHTKEY:
    597 			if (!::g->followplayer) ::g->m_paninc.x = 0;
    598 			break;
    599 		case AM_PANLEFTKEY:
    600 			if (!::g->followplayer) ::g->m_paninc.x = 0;
    601 			break;
    602 		case AM_PANUPKEY:
    603 			if (!::g->followplayer) ::g->m_paninc.y = 0;
    604 			break;
    605 		case AM_PANDOWNKEY:
    606 			if (!::g->followplayer) ::g->m_paninc.y = 0;
    607 			break;
    608 		case AM_ZOOMOUTKEY:
    609 		case AM_ZOOMINKEY:
    610 			::g->mtof_zoommul = FRACUNIT;
    611 			::g->ftom_zoommul = FRACUNIT;
    612 			break;
    613 		}
    614 	}
    615 
    616 	return rc;
    617 
    618 }
    619 
    620 
    621 //
    622 // Zooming
    623 //
    624 void AM_changeWindowScale(void)
    625 {
    626 
    627 	// Change the scaling multipliers
    628 	::g->scale_mtof = FixedMul(::g->scale_mtof, ::g->mtof_zoommul);
    629 	::g->scale_ftom = FixedDiv(FRACUNIT, ::g->scale_mtof);
    630 
    631 	if (::g->scale_mtof < ::g->min_scale_mtof)
    632 		AM_minOutWindowScale();
    633 	else if (::g->scale_mtof > ::g->max_scale_mtof)
    634 		AM_maxOutWindowScale();
    635 	else
    636 		AM_activateNewScale();
    637 }
    638 
    639 
    640 //
    641 //
    642 //
    643 void AM_doFollowPlayer(void)
    644 {
    645 
    646 	if (::g->f_oldloc.x != ::g->amap_plr->mo->x || ::g->f_oldloc.y != ::g->amap_plr->mo->y)
    647 	{
    648 		::g->m_x = FTOM(MTOF(::g->amap_plr->mo->x)) - ::g->m_w/2;
    649 		::g->m_y = FTOM(MTOF(::g->amap_plr->mo->y)) - ::g->m_h/2;
    650 		::g->m_x2 = ::g->m_x + ::g->m_w;
    651 		::g->m_y2 = ::g->m_y + ::g->m_h;
    652 		::g->f_oldloc.x = ::g->amap_plr->mo->x;
    653 		::g->f_oldloc.y = ::g->amap_plr->mo->y;
    654 
    655 		//  ::g->m_x = FTOM(MTOF(::g->amap_plr->mo->x - ::g->m_w/2));
    656 		//  ::g->m_y = FTOM(MTOF(::g->amap_plr->mo->y - ::g->m_h/2));
    657 		//  ::g->m_x = ::g->amap_plr->mo->x - ::g->m_w/2;
    658 		//  ::g->m_y = ::g->amap_plr->mo->y - ::g->m_h/2;
    659 
    660 	}
    661 
    662 }
    663 
    664 //
    665 //
    666 //
    667 void AM_updateLightLev(void)
    668 {
    669 	//static int litelevels[] = { 0, 3, 5, 6, 6, 7, 7, 7 };
    670 	const static int litelevels[] = { 0, 4, 7, 10, 12, 14, 15, 15 };
    671 
    672 	// Change light level
    673 	if (::g->amclock>::g->nexttic)
    674 	{
    675 		::g->lightlev = litelevels[::g->litelevelscnt++];
    676 		if (::g->litelevelscnt == sizeof(litelevels)/sizeof(int)) ::g->litelevelscnt = 0;
    677 		::g->nexttic = ::g->amclock + 6 - (::g->amclock % 6);
    678 	}
    679 
    680 }
    681 
    682 
    683 //
    684 // Updates on Game Tick
    685 //
    686 void AM_Ticker (void)
    687 {
    688 
    689 	if (!::g->automapactive)
    690 		return;
    691 
    692 	::g->amclock++;
    693 
    694 	if (::g->followplayer)
    695 		AM_doFollowPlayer();
    696 
    697 	// Change the zoom if necessary
    698 	if (::g->ftom_zoommul != FRACUNIT)
    699 		AM_changeWindowScale();
    700 
    701 	// Change x,y location
    702 	if (::g->m_paninc.x || ::g->m_paninc.y)
    703 		AM_changeWindowLoc();
    704 
    705 	// Update light level
    706 	// AM_updateLightLev();
    707 
    708 }
    709 
    710 
    711 //
    712 // Clear automap frame ::g->buffer.
    713 //
    714 void AM_clearFB(int color)
    715 {
    716 	memset(::g->fb, color, ::g->f_w*::g->f_h);
    717 }
    718 
    719 
    720 //
    721 // Automap clipping of ::g->lines.
    722 //
    723 // Based on Cohen-Sutherland clipping algorithm but with a slightly
    724 // faster reject and precalculated slopes.  If the speed is needed,
    725 // use a hash algorithm to handle  the common cases.
    726 //
    727 qboolean
    728 AM_clipMline
    729 ( mline_t*	ml,
    730  fline_t*	fl )
    731 {
    732 	enum
    733 	{
    734 		LEFT	=1,
    735 		RIGHT	=2,
    736 		BOTTOM	=4,
    737 		TOP	=8
    738 	};
    739 
    740 	register	int outcode1 = 0;
    741 	register	int outcode2 = 0;
    742 	register	int outside;
    743 
    744 	fpoint_t	tmp = { 0, 0 };
    745 	int		dx;
    746 	int		dy;
    747 
    748 
    749 
    750 
    751 	// do trivial rejects and outcodes
    752 	if (ml->a.y > ::g->m_y2)
    753 		outcode1 = TOP;
    754 	else if (ml->a.y < ::g->m_y)
    755 		outcode1 = BOTTOM;
    756 
    757 	if (ml->b.y > ::g->m_y2)
    758 		outcode2 = TOP;
    759 	else if (ml->b.y < ::g->m_y)
    760 		outcode2 = BOTTOM;
    761 
    762 	if (outcode1 & outcode2)
    763 		return false; // trivially outside
    764 
    765 	if (ml->a.x < ::g->m_x)
    766 		outcode1 |= LEFT;
    767 	else if (ml->a.x > ::g->m_x2)
    768 		outcode1 |= RIGHT;
    769 
    770 	if (ml->b.x < ::g->m_x)
    771 		outcode2 |= LEFT;
    772 	else if (ml->b.x > ::g->m_x2)
    773 		outcode2 |= RIGHT;
    774 
    775 	if (outcode1 & outcode2)
    776 		return false; // trivially outside
    777 
    778 	// transform to frame-::g->buffer coordinates.
    779 	fl->a.x = CXMTOF(ml->a.x);
    780 	fl->a.y = CYMTOF(ml->a.y);
    781 	fl->b.x = CXMTOF(ml->b.x);
    782 	fl->b.y = CYMTOF(ml->b.y);
    783 
    784 	DOOUTCODE(outcode1, fl->a.x, fl->a.y);
    785 	DOOUTCODE(outcode2, fl->b.x, fl->b.y);
    786 
    787 	if (outcode1 & outcode2)
    788 		return false;
    789 
    790 	while (outcode1 | outcode2)
    791 	{
    792 		// may be partially inside box
    793 		// find an outside point
    794 		if (outcode1)
    795 			outside = outcode1;
    796 		else
    797 			outside = outcode2;
    798 
    799 		// clip to each side
    800 		if (outside & TOP)
    801 		{
    802 			dy = fl->a.y - fl->b.y;
    803 			dx = fl->b.x - fl->a.x;
    804 			tmp.x = fl->a.x + (dx*(fl->a.y))/dy;
    805 			tmp.y = 0;
    806 		}
    807 		else if (outside & BOTTOM)
    808 		{
    809 			dy = fl->a.y - fl->b.y;
    810 			dx = fl->b.x - fl->a.x;
    811 			tmp.x = fl->a.x + (dx*(fl->a.y-::g->f_h))/dy;
    812 			tmp.y = ::g->f_h-1;
    813 		}
    814 		else if (outside & RIGHT)
    815 		{
    816 			dy = fl->b.y - fl->a.y;
    817 			dx = fl->b.x - fl->a.x;
    818 			tmp.y = fl->a.y + (dy*(::g->f_w-1 - fl->a.x))/dx;
    819 			tmp.x = ::g->f_w-1;
    820 		}
    821 		else if (outside & LEFT)
    822 		{
    823 			dy = fl->b.y - fl->a.y;
    824 			dx = fl->b.x - fl->a.x;
    825 			tmp.y = fl->a.y + (dy*(-fl->a.x))/dx;
    826 			tmp.x = 0;
    827 		}
    828 
    829 		if (outside == outcode1)
    830 		{
    831 			fl->a = tmp;
    832 			DOOUTCODE(outcode1, fl->a.x, fl->a.y);
    833 		}
    834 		else
    835 		{
    836 			fl->b = tmp;
    837 			DOOUTCODE(outcode2, fl->b.x, fl->b.y);
    838 		}
    839 
    840 		if (outcode1 & outcode2)
    841 			return false; // trivially outside
    842 	}
    843 
    844 	return true;
    845 }
    846 #undef DOOUTCODE
    847 
    848 
    849 //
    850 // Classic Bresenham w/ whatever optimizations needed for speed
    851 //
    852 void
    853 AM_drawFline
    854 ( fline_t*	fl,
    855  int		color )
    856 {
    857 	register int x;
    858 	register int y;
    859 	register int dx;
    860 	register int dy;
    861 	register int sx;
    862 	register int sy;
    863 	register int ax;
    864 	register int ay;
    865 	register int d;
    866 
    867 	static int fuck = 0;
    868 
    869 	// For debugging only
    870 	if (      fl->a.x < 0 || fl->a.x >= ::g->f_w
    871 		|| fl->a.y < 0 || fl->a.y >= ::g->f_h
    872 		|| fl->b.x < 0 || fl->b.x >= ::g->f_w
    873 		|| fl->b.y < 0 || fl->b.y >= ::g->f_h)
    874 	{
    875 		I_PrintfE("fuck %d \r", fuck++);
    876 		return;
    877 	}
    878 
    879 
    880 	dx = fl->b.x - fl->a.x;
    881 	ax = 2 * (dx<0 ? -dx : dx);
    882 	sx = dx<0 ? -1 : 1;
    883 
    884 	dy = fl->b.y - fl->a.y;
    885 	ay = 2 * (dy<0 ? -dy : dy);
    886 	sy = dy<0 ? -1 : 1;
    887 
    888 	x = fl->a.x;
    889 	y = fl->a.y;
    890 
    891 	if (ax > ay)
    892 	{
    893 		d = ay - ax/2;
    894 		while (1)
    895 		{
    896 			PUTDOT(x,y,color);
    897 			if (x == fl->b.x) return;
    898 			if (d>=0)
    899 			{
    900 				y += sy;
    901 				d -= ax;
    902 			}
    903 			x += sx;
    904 			d += ay;
    905 		}
    906 	}
    907 	else
    908 	{
    909 		d = ax - ay/2;
    910 		while (1)
    911 		{
    912 			PUTDOT(x, y, color);
    913 			if (y == fl->b.y) return;
    914 			if (d >= 0)
    915 			{
    916 				x += sx;
    917 				d -= ay;
    918 			}
    919 			y += sy;
    920 			d += ax;
    921 		}
    922 	}
    923 }
    924 
    925 
    926 //
    927 // Clip ::g->lines, draw visible part sof ::g->lines.
    928 //
    929 void
    930 AM_drawMline
    931 ( mline_t*	ml,
    932  int		color )
    933 {
    934 	static fline_t fl;
    935 
    936 	if (AM_clipMline(ml, &fl))
    937 		AM_drawFline(&fl, color); // draws it on frame ::g->buffer using ::g->fb coords
    938 }
    939 
    940 
    941 
    942 //
    943 // Draws flat (floor/ceiling tile) aligned ::g->grid ::g->lines.
    944 //
    945 void AM_drawGrid(int color)
    946 {
    947 	fixed_t x, y;
    948 	fixed_t start, end;
    949 	mline_t ml;
    950 
    951 	// Figure out start of vertical gridlines
    952 	start = ::g->m_x;
    953 	if ((start-::g->bmaporgx)%(MAPBLOCKUNITS<<FRACBITS))
    954 		start += (MAPBLOCKUNITS<<FRACBITS)
    955 		- ((start-::g->bmaporgx)%(MAPBLOCKUNITS<<FRACBITS));
    956 	end = ::g->m_x + ::g->m_w;
    957 
    958 	// draw vertical gridlines
    959 	ml.a.y = ::g->m_y;
    960 	ml.b.y = ::g->m_y+::g->m_h;
    961 	for (x=start; x<end; x+=(MAPBLOCKUNITS<<FRACBITS))
    962 	{
    963 		ml.a.x = x;
    964 		ml.b.x = x;
    965 		AM_drawMline(&ml, color);
    966 	}
    967 
    968 	// Figure out start of horizontal gridlines
    969 	start = ::g->m_y;
    970 	if ((start-::g->bmaporgy)%(MAPBLOCKUNITS<<FRACBITS))
    971 		start += (MAPBLOCKUNITS<<FRACBITS)
    972 		- ((start-::g->bmaporgy)%(MAPBLOCKUNITS<<FRACBITS));
    973 	end = ::g->m_y + ::g->m_h;
    974 
    975 	// draw horizontal gridlines
    976 	ml.a.x = ::g->m_x;
    977 	ml.b.x = ::g->m_x + ::g->m_w;
    978 	for (y=start; y<end; y+=(MAPBLOCKUNITS<<FRACBITS))
    979 	{
    980 		ml.a.y = y;
    981 		ml.b.y = y;
    982 		AM_drawMline(&ml, color);
    983 	}
    984 
    985 }
    986 
    987 //
    988 // Determines visible ::g->lines, draws them.
    989 // This is LineDef based, not LineSeg based.
    990 //
    991 void AM_drawWalls(void)
    992 {
    993 	int i;
    994 	static mline_t l;
    995 
    996 	for (i = 0; i < ::g->numlines; i++)
    997 	{
    998 		l.a.x = ::g->lines[i].v1->x;
    999 		l.a.y = ::g->lines[i].v1->y;
   1000 		l.b.x = ::g->lines[i].v2->x;
   1001 		l.b.y = ::g->lines[i].v2->y;
   1002 		if (::g->cheating || (::g->lines[i].flags & ML_MAPPED))
   1003 		{
   1004 			if ((::g->lines[i].flags & LINE_NEVERSEE) && !::g->cheating)
   1005 				continue;
   1006 			if (!::g->lines[i].backsector)
   1007 			{
   1008 				AM_drawMline(&l, WALLCOLORS+::g->lightlev);
   1009 			}
   1010 			else
   1011 			{
   1012 				if (::g->lines[i].special == 39)
   1013 				{ // teleporters
   1014 					AM_drawMline(&l, WALLCOLORS+WALLRANGE/2);
   1015 				}
   1016 				else if (::g->lines[i].flags & ML_SECRET) // secret door
   1017 				{
   1018 					if (::g->cheating) AM_drawMline(&l, SECRETWALLCOLORS + ::g->lightlev);
   1019 					else AM_drawMline(&l, WALLCOLORS+::g->lightlev);
   1020 				}
   1021 				else if (::g->lines[i].backsector->floorheight
   1022 					!= ::g->lines[i].frontsector->floorheight) {
   1023 						AM_drawMline(&l, FDWALLCOLORS + ::g->lightlev); // floor level change
   1024 					}
   1025 				else if (::g->lines[i].backsector->ceilingheight
   1026 					!= ::g->lines[i].frontsector->ceilingheight) {
   1027 						AM_drawMline(&l, CDWALLCOLORS+::g->lightlev); // ceiling level change
   1028 					}
   1029 				else if (::g->cheating) {
   1030 					AM_drawMline(&l, TSWALLCOLORS+::g->lightlev);
   1031 				}
   1032 			}
   1033 		}
   1034 		else if (::g->amap_plr->powers[pw_allmap])
   1035 		{
   1036 			if (!(::g->lines[i].flags & LINE_NEVERSEE)) AM_drawMline(&l, GRAYS+3);
   1037 		}
   1038 	}
   1039 }
   1040 
   1041 
   1042 //
   1043 // Rotation in 2D.
   1044 // Used to rotate player arrow line character.
   1045 //
   1046 void
   1047 AM_rotate
   1048 ( fixed_t*	x,
   1049  fixed_t*	y,
   1050  angle_t	a )
   1051 {
   1052 	fixed_t tmpx;
   1053 
   1054 	tmpx =
   1055 		FixedMul(*x,finecosine[a>>ANGLETOFINESHIFT])
   1056 		- FixedMul(*y,finesine[a>>ANGLETOFINESHIFT]);
   1057 
   1058 	*y   =
   1059 		FixedMul(*x,finesine[a>>ANGLETOFINESHIFT])
   1060 		+ FixedMul(*y,finecosine[a>>ANGLETOFINESHIFT]);
   1061 
   1062 	*x = tmpx;
   1063 }
   1064 
   1065 void
   1066 AM_drawLineCharacter
   1067 ( mline_t*	lineguy,
   1068  int		lineguylines,
   1069  fixed_t	scale,
   1070  angle_t	angle,
   1071  int		color,
   1072  fixed_t	x,
   1073  fixed_t	y )
   1074 {
   1075 	int		i;
   1076 	mline_t	l;
   1077 
   1078 	for (i=0;i<lineguylines;i++)
   1079 	{
   1080 		l.a.x = lineguy[i].a.x;
   1081 		l.a.y = lineguy[i].a.y;
   1082 
   1083 		if (scale)
   1084 		{
   1085 			l.a.x = FixedMul(scale, l.a.x);
   1086 			l.a.y = FixedMul(scale, l.a.y);
   1087 		}
   1088 
   1089 		if (angle)
   1090 			AM_rotate(&l.a.x, &l.a.y, angle);
   1091 
   1092 		l.a.x += x;
   1093 		l.a.y += y;
   1094 
   1095 		l.b.x = lineguy[i].b.x;
   1096 		l.b.y = lineguy[i].b.y;
   1097 
   1098 		if (scale)
   1099 		{
   1100 			l.b.x = FixedMul(scale, l.b.x);
   1101 			l.b.y = FixedMul(scale, l.b.y);
   1102 		}
   1103 
   1104 		if (angle)
   1105 			AM_rotate(&l.b.x, &l.b.y, angle);
   1106 
   1107 		l.b.x += x;
   1108 		l.b.y += y;
   1109 
   1110 		AM_drawMline(&l, color);
   1111 	}
   1112 }
   1113 
   1114 void AM_drawPlayers(void)
   1115 {
   1116 	int		i;
   1117 	player_t*	p;
   1118 	static int 	their_colors[] = { GREENS, GRAYS, BROWNS, REDS };
   1119 	int		their_color = -1;
   1120 	int		color;
   1121 
   1122 	if (!::g->netgame)
   1123 	{
   1124 		if (::g->cheating)
   1125 			AM_drawLineCharacter
   1126 			(cheat_player_arrow, NUMCHEATPLYRLINES, 0,
   1127 			::g->amap_plr->mo->angle, WHITE, ::g->amap_plr->mo->x, ::g->amap_plr->mo->y);
   1128 		else
   1129 			AM_drawLineCharacter
   1130 			(player_arrow, NUMPLYRLINES, 0, ::g->amap_plr->mo->angle,
   1131 			WHITE, ::g->amap_plr->mo->x, ::g->amap_plr->mo->y);
   1132 		return;
   1133 	}
   1134 
   1135 	for (i=0;i<MAXPLAYERS;i++)
   1136 	{
   1137 		their_color++;
   1138 		p = &::g->players[i];
   1139 
   1140 		if ( (::g->deathmatch && !::g->singledemo) && p != ::g->amap_plr)
   1141 			continue;
   1142 
   1143 		if (!::g->playeringame[i])
   1144 			continue;
   1145 
   1146 		if (p->powers[pw_invisibility])
   1147 			color = 246; // *close* to black
   1148 		else
   1149 			color = their_colors[their_color];
   1150 
   1151 		AM_drawLineCharacter
   1152 			(player_arrow, NUMPLYRLINES, 0, p->mo->angle,
   1153 			color, p->mo->x, p->mo->y);
   1154 	}
   1155 
   1156 }
   1157 
   1158 void
   1159 AM_drawThings
   1160 ( int	colors,
   1161  int 	colorrange)
   1162 {
   1163 	int		i;
   1164 	mobj_t*	t;
   1165 
   1166 	for (i = 0; i < ::g->numsectors; i++)
   1167 	{
   1168 		t = ::g->sectors[i].thinglist;
   1169 		while (t)
   1170 		{
   1171 			AM_drawLineCharacter
   1172 				(thintriangle_guy, NUMTHINTRIANGLEGUYLINES,
   1173 				16<<FRACBITS, t->angle, colors+::g->lightlev, t->x, t->y);
   1174 			t = t->snext;
   1175 		}
   1176 	}
   1177 }
   1178 
   1179 void AM_drawMarks(void)
   1180 {
   1181 	int i, fx, fy, w, h;
   1182 
   1183 	for (i=0;i<AM_NUMMARKPOINTS;i++)
   1184 	{
   1185 		if (::g->markpoints[i].x != -1)
   1186 		{
   1187 			//      w = SHORT(::g->marknums[i]->width);
   1188 			//      h = SHORT(::g->marknums[i]->height);
   1189 			w = 5; // because something's wrong with the wad, i guess
   1190 			h = 6; // because something's wrong with the wad, i guess
   1191 			fx = CXMTOF(::g->markpoints[i].x);
   1192 			fy = CYMTOF(::g->markpoints[i].y);
   1193 			if (fx >= ::g->f_x && fx <= ::g->f_w - w && fy >= ::g->f_y && fy <= ::g->f_h - h)
   1194 				V_DrawPatch(fx/GLOBAL_IMAGE_SCALER, fy/GLOBAL_IMAGE_SCALER, FB, ::g->marknums[i]);
   1195 		}
   1196 	}
   1197 
   1198 }
   1199 
   1200 void AM_drawCrosshair(int color)
   1201 {
   1202 	::g->fb[(::g->f_w*(::g->f_h+1))/2] = color; // single point for now
   1203 
   1204 }
   1205 
   1206 void AM_Drawer (void)
   1207 {
   1208 	if (!::g->automapactive) return;
   1209 
   1210 	AM_clearFB(BACKGROUND);
   1211 	if (::g->grid)
   1212 		AM_drawGrid(GRIDCOLORS);
   1213 	AM_drawWalls();
   1214 	AM_drawPlayers();
   1215 	if (::g->cheating==2)
   1216 		AM_drawThings(THINGCOLORS, THINGRANGE);
   1217 	AM_drawCrosshair(XHAIRCOLORS);
   1218 
   1219 	AM_drawMarks();
   1220 
   1221 	V_MarkRect(::g->f_x, ::g->f_y, ::g->f_w, ::g->f_h);
   1222 
   1223 }
   1224