DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

p_maputl.cpp (17235B)


      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 
     33 #include <stdlib.h>
     34 
     35 
     36 #include "m_bbox.h"
     37 
     38 #include "doomdef.h"
     39 #include "p_local.h"
     40 
     41 
     42 // State.
     43 #include "r_state.h"
     44 
     45 //
     46 // P_AproxDistance
     47 // Gives an estimation of distance (not exact)
     48 //
     49 
     50 fixed_t
     51 P_AproxDistance
     52 ( fixed_t	dx,
     53   fixed_t	dy )
     54 {
     55     dx = abs(dx);
     56     dy = abs(dy);
     57     if (dx < dy)
     58 	return dx+dy-(dx>>1);
     59     return dx+dy-(dy>>1);
     60 }
     61 
     62 
     63 //
     64 // P_PointOnLineSide
     65 // Returns 0 or 1
     66 //
     67 int
     68 P_PointOnLineSide
     69 ( fixed_t	x,
     70   fixed_t	y,
     71   line_t*	line )
     72 {
     73     fixed_t	dx;
     74     fixed_t	dy;
     75     fixed_t	left;
     76     fixed_t	right;
     77 	
     78     if (!line->dx)
     79     {
     80 	if (x <= line->v1->x)
     81 	    return line->dy > 0;
     82 	
     83 	return line->dy < 0;
     84     }
     85     if (!line->dy)
     86     {
     87 	if (y <= line->v1->y)
     88 	    return line->dx < 0;
     89 	
     90 	return line->dx > 0;
     91     }
     92 	
     93     dx = (x - line->v1->x);
     94     dy = (y - line->v1->y);
     95 	
     96     left = FixedMul ( line->dy>>FRACBITS , dx );
     97     right = FixedMul ( dy , line->dx>>FRACBITS );
     98 	
     99     if (right < left)
    100 	return 0;		// front side
    101     return 1;			// back side
    102 }
    103 
    104 
    105 
    106 //
    107 // P_BoxOnLineSide
    108 // Considers the line to be infinite
    109 // Returns side 0 or 1, -1 if box crosses the line.
    110 //
    111 int
    112 P_BoxOnLineSide
    113 ( fixed_t*	tmbox,
    114   line_t*	ld )
    115 {
    116     int		p1 = 0;
    117     int		p2 = 0;
    118 	
    119     switch (ld->slopetype)
    120     {
    121       case ST_HORIZONTAL:
    122 	p1 = tmbox[BOXTOP] > ld->v1->y;
    123 	p2 = tmbox[BOXBOTTOM] > ld->v1->y;
    124 	if (ld->dx < 0)
    125 	{
    126 	    p1 ^= 1;
    127 	    p2 ^= 1;
    128 	}
    129 	break;
    130 	
    131       case ST_VERTICAL:
    132 	p1 = tmbox[BOXRIGHT] < ld->v1->x;
    133 	p2 = tmbox[BOXLEFT] < ld->v1->x;
    134 	if (ld->dy < 0)
    135 	{
    136 	    p1 ^= 1;
    137 	    p2 ^= 1;
    138 	}
    139 	break;
    140 	
    141       case ST_POSITIVE:
    142 	p1 = P_PointOnLineSide (tmbox[BOXLEFT], tmbox[BOXTOP], ld);
    143 	p2 = P_PointOnLineSide (tmbox[BOXRIGHT], tmbox[BOXBOTTOM], ld);
    144 	break;
    145 	
    146       case ST_NEGATIVE:
    147 	p1 = P_PointOnLineSide (tmbox[BOXRIGHT], tmbox[BOXTOP], ld);
    148 	p2 = P_PointOnLineSide (tmbox[BOXLEFT], tmbox[BOXBOTTOM], ld);
    149 	break;
    150     }
    151 
    152     if (p1 == p2)
    153 	return p1;
    154     return -1;
    155 }
    156 
    157 
    158 //
    159 // P_PointOnDivlineSide
    160 // Returns 0 or 1.
    161 //
    162 int
    163 P_PointOnDivlineSide
    164 ( fixed_t	x,
    165   fixed_t	y,
    166   divline_t*	line )
    167 {
    168     fixed_t	dx;
    169     fixed_t	dy;
    170     fixed_t	left;
    171     fixed_t	right;
    172 	
    173     if (!line->dx)
    174     {
    175 	if (x <= line->x)
    176 	    return line->dy > 0;
    177 	
    178 	return line->dy < 0;
    179     }
    180     if (!line->dy)
    181     {
    182 	if (y <= line->y)
    183 	    return line->dx < 0;
    184 
    185 	return line->dx > 0;
    186     }
    187 	
    188     dx = (x - line->x);
    189     dy = (y - line->y);
    190 	
    191     // try to quickly decide by looking at sign bits
    192     if ( (line->dy ^ line->dx ^ dx ^ dy)&0x80000000 )
    193     {
    194 	if ( (line->dy ^ dx) & 0x80000000 )
    195 	    return 1;		// (left is negative)
    196 	return 0;
    197     }
    198 	
    199     left = FixedMul ( line->dy>>8, dx>>8 );
    200     right = FixedMul ( dy>>8 , line->dx>>8 );
    201 	
    202     if (right < left)
    203 	return 0;		// front side
    204     return 1;			// back side
    205 }
    206 
    207 
    208 
    209 //
    210 // P_MakeDivline
    211 //
    212 void
    213 P_MakeDivline
    214 ( line_t*	li,
    215   divline_t*	dl )
    216 {
    217     dl->x = li->v1->x;
    218     dl->y = li->v1->y;
    219     dl->dx = li->dx;
    220     dl->dy = li->dy;
    221 }
    222 
    223 
    224 
    225 //
    226 // P_InterceptVector
    227 // Returns the fractional intercept point
    228 // along the first divline.
    229 // This is only called by the addthings
    230 // and addlines traversers.
    231 //
    232 fixed_t
    233 P_InterceptVector
    234 ( divline_t*	v2,
    235   divline_t*	v1 )
    236 {
    237 #if 1
    238     fixed_t	frac;
    239     fixed_t	num;
    240     fixed_t	den;
    241 	
    242     den = FixedMul (v1->dy>>8,v2->dx) - FixedMul(v1->dx>>8,v2->dy);
    243 
    244     if (den == 0)
    245 	return 0;
    246     //	I_Error ("P_InterceptVector: parallel");
    247     
    248     num =
    249 	FixedMul ( (v1->x - v2->x)>>8 ,v1->dy )
    250 	+FixedMul ( (v2->y - v1->y)>>8, v1->dx );
    251 
    252     frac = FixedDiv (num , den);
    253 
    254     return frac;
    255 #else	// UNUSED, float debug.
    256     float	frac;
    257     float	num;
    258     float	den;
    259     float	v1x;
    260     float	v1y;
    261     float	v1dx;
    262     float	v1dy;
    263     float	v2x;
    264     float	v2y;
    265     float	v2dx;
    266     float	v2dy;
    267 
    268     v1x = (float)v1->x/FRACUNIT;
    269     v1y = (float)v1->y/FRACUNIT;
    270     v1dx = (float)v1->dx/FRACUNIT;
    271     v1dy = (float)v1->dy/FRACUNIT;
    272     v2x = (float)v2->x/FRACUNIT;
    273     v2y = (float)v2->y/FRACUNIT;
    274     v2dx = (float)v2->dx/FRACUNIT;
    275     v2dy = (float)v2->dy/FRACUNIT;
    276 	
    277     den = v1dy*v2dx - v1dx*v2dy;
    278 
    279     if (den == 0)
    280 	return 0;	// parallel
    281     
    282     num = (v1x - v2x)*v1dy + (v2y - v1y)*v1dx;
    283     frac = num / den;
    284 
    285     return frac*FRACUNIT;
    286 #endif
    287 }
    288 
    289 
    290 //
    291 // P_LineOpening
    292 // Sets ::g->opentop and ::g->openbottom to the window
    293 // through a two sided line.
    294 // OPTIMIZE: keep this precalculated
    295 //
    296 
    297 
    298 void P_LineOpening (line_t* maputil_linedef)
    299 {
    300     sector_t*	front;
    301     sector_t*	back;
    302 	
    303     if (maputil_linedef->sidenum[1] == -1)
    304     {
    305 	// single sided line
    306 	::g->openrange = 0;
    307 	return;
    308     }
    309 	 
    310     front = maputil_linedef->frontsector;
    311     back = maputil_linedef->backsector;
    312 	
    313     if (front->ceilingheight < back->ceilingheight)
    314 	::g->opentop = front->ceilingheight;
    315     else
    316 	::g->opentop = back->ceilingheight;
    317 
    318     if (front->floorheight > back->floorheight)
    319     {
    320 	::g->openbottom = front->floorheight;
    321 	::g->lowfloor = back->floorheight;
    322     }
    323     else
    324     {
    325 	::g->openbottom = back->floorheight;
    326 	::g->lowfloor = front->floorheight;
    327     }
    328 	
    329     ::g->openrange = ::g->opentop - ::g->openbottom;
    330 }
    331 
    332 
    333 //
    334 // THING POSITION SETTING
    335 //
    336 
    337 
    338 //
    339 // P_UnsetThingPosition
    340 // Unlinks a thing from block map and ::g->sectors.
    341 // On each position change, BLOCKMAP and other
    342 // lookups maintaining lists ot things inside
    343 // these structures need to be updated.
    344 //
    345 void P_UnsetThingPosition (mobj_t* thing)
    346 {
    347     int		blockx;
    348     int		blocky;
    349 
    350     if ( ! (thing->flags & MF_NOSECTOR) )
    351     {
    352 	// inert things don't need to be in blockmap?
    353 	// unlink from subsector
    354 	if (thing->snext)
    355 	    thing->snext->sprev = thing->sprev;
    356 
    357 	if (thing->sprev)
    358 	    thing->sprev->snext = thing->snext;
    359 	else
    360 	    thing->subsector->sector->thinglist = thing->snext;
    361     }
    362 	
    363     if ( ! (thing->flags & MF_NOBLOCKMAP) )
    364     {
    365 	// inert things don't need to be in ::g->blockmap
    366 	// unlink from block map
    367 	if (thing->bnext)
    368 	    thing->bnext->bprev = thing->bprev;
    369 	
    370 	if (thing->bprev)
    371 	    thing->bprev->bnext = thing->bnext;
    372 	else
    373 	{
    374 	    blockx = (thing->x - ::g->bmaporgx)>>MAPBLOCKSHIFT;
    375 	    blocky = (thing->y - ::g->bmaporgy)>>MAPBLOCKSHIFT;
    376 
    377 	    if (blockx>=0 && blockx < ::g->bmapwidth
    378 		&& blocky>=0 && blocky < ::g->bmapheight)
    379 	    {
    380 		::g->blocklinks[blocky*::g->bmapwidth+blockx] = thing->bnext;
    381 	    }
    382 	}
    383     }
    384 }
    385 
    386 
    387 //
    388 // P_SetThingPosition
    389 // Links a thing into both a block and a subsector
    390 // based on it's x y.
    391 // Sets thing->subsector properly
    392 //
    393 void
    394 P_SetThingPosition (mobj_t* thing)
    395 {
    396     subsector_t*	ss;
    397     sector_t*		sec;
    398     int			blockx;
    399     int			blocky;
    400     mobj_t**		link;
    401 
    402     
    403     // link into subsector
    404     ss = R_PointInSubsector (thing->x,thing->y);
    405     thing->subsector = ss;
    406     
    407     if ( ! (thing->flags & MF_NOSECTOR) )
    408     {
    409 	// invisible things don't go into the sector links
    410 	sec = ss->sector;
    411 	
    412 	thing->sprev = NULL;
    413 	thing->snext = sec->thinglist;
    414 
    415 	if (sec->thinglist)
    416 	    sec->thinglist->sprev = thing;
    417 
    418 	sec->thinglist = thing;
    419     }
    420 
    421     
    422     // link into ::g->blockmap
    423     if ( ! (thing->flags & MF_NOBLOCKMAP) )
    424     {
    425 	// inert things don't need to be in ::g->blockmap		
    426 	blockx = (thing->x - ::g->bmaporgx)>>MAPBLOCKSHIFT;
    427 	blocky = (thing->y - ::g->bmaporgy)>>MAPBLOCKSHIFT;
    428 
    429 	if (blockx>=0
    430 	    && blockx < ::g->bmapwidth
    431 	    && blocky>=0
    432 	    && blocky < ::g->bmapheight)
    433 	{
    434 	    link = &::g->blocklinks[blocky*::g->bmapwidth+blockx];
    435 	    thing->bprev = NULL;
    436 	    thing->bnext = *link;
    437 	    if (*link)
    438 		(*link)->bprev = thing;
    439 
    440 	    *link = thing;
    441 	}
    442 	else
    443 	{
    444 	    // thing is off the map
    445 	    thing->bnext = thing->bprev = NULL;
    446 	}
    447     }
    448 }
    449 
    450 
    451 
    452 //
    453 // BLOCK MAP ITERATORS
    454 // For each line/thing in the given mapblock,
    455 // call the passed PIT_* function.
    456 // If the function returns false,
    457 // exit with false without checking anything else.
    458 //
    459 
    460 
    461 //
    462 // P_BlockLinesIterator
    463 // The ::g->validcount flags are used to avoid checking ::g->lines
    464 // that are marked in multiple mapblocks,
    465 // so increment ::g->validcount before the first call
    466 // to P_BlockLinesIterator, then make one or more calls
    467 // to it.
    468 //
    469 qboolean
    470 P_BlockLinesIterator
    471 ( int			x,
    472   int			y,
    473   qboolean(*func)(line_t*) )
    474 {
    475     int			offset;
    476     short*		list;
    477     line_t*		ld;
    478 	
    479     if (x<0
    480 	|| y<0
    481 	|| x>=::g->bmapwidth
    482 	|| y>=::g->bmapheight)
    483     {
    484 	return true;
    485     }
    486     
    487     offset = y*::g->bmapwidth+x;
    488 	
    489     offset = *(::g->blockmap+offset);
    490 
    491     for ( list = ::g->blockmaplump+offset ; *list != -1 ; list++)
    492     {
    493 	ld = &::g->lines[*list];
    494 
    495 	if (ld->validcount == ::g->validcount)
    496 	    continue; 	// line has already been checked
    497 
    498 	ld->validcount = ::g->validcount;
    499 
    500 	if ( !func(ld) )
    501 	    return false;
    502     }
    503     return true;	// everything was checked
    504 }
    505 
    506 
    507 //
    508 // P_BlockThingsIterator
    509 //
    510 qboolean
    511 P_BlockThingsIterator
    512 ( int			x,
    513   int			y,
    514   qboolean(*func)(mobj_t*) )
    515 {
    516     mobj_t*		mobj;
    517 	
    518     if ( x<0
    519 	 || y<0
    520 	 || x>=::g->bmapwidth
    521 	 || y>=::g->bmapheight)
    522     {
    523 	return true;
    524     }
    525     
    526 
    527     for (mobj = ::g->blocklinks[y*::g->bmapwidth+x] ;
    528 	 mobj ;
    529 	 mobj = mobj->bnext)
    530     {
    531 	if (!func( mobj ) )
    532 	    return false;
    533     }
    534     return true;
    535 }
    536 
    537 
    538 
    539 //
    540 // INTERCEPT ROUTINES
    541 //
    542 
    543 
    544 //
    545 // PIT_AddLineIntercepts.
    546 // Looks for ::g->lines in the given block
    547 // that intercept the given ::g->trace
    548 // to add to the ::g->intercepts list.
    549 //
    550 // A line is crossed if its endpoints
    551 // are on opposite ::g->sides of the ::g->trace.
    552 // Returns true if ::g->earlyout and a solid line hit.
    553 //
    554 qboolean
    555 PIT_AddLineIntercepts (line_t* ld)
    556 {
    557     int			s1;
    558     int			s2;
    559     fixed_t		frac;
    560     divline_t		dl;
    561 	
    562     // avoid precision problems with two routines
    563     if ( ::g->trace.dx > FRACUNIT*16
    564 	 || ::g->trace.dy > FRACUNIT*16
    565 	 || ::g->trace.dx < -FRACUNIT*16
    566 	 || ::g->trace.dy < -FRACUNIT*16)
    567     {
    568 	s1 = P_PointOnDivlineSide (ld->v1->x, ld->v1->y, &::g->trace);
    569 	s2 = P_PointOnDivlineSide (ld->v2->x, ld->v2->y, &::g->trace);
    570     }
    571     else
    572     {
    573 	s1 = P_PointOnLineSide (::g->trace.x, ::g->trace.y, ld);
    574 	s2 = P_PointOnLineSide (::g->trace.x+::g->trace.dx, ::g->trace.y+::g->trace.dy, ld);
    575     }
    576     
    577     if (s1 == s2)
    578 	return true;	// line isn't crossed
    579     
    580     // hit the line
    581     P_MakeDivline (ld, &dl);
    582     frac = P_InterceptVector (&::g->trace, &dl);
    583 
    584     if (frac < 0)
    585 	return true;	// behind source
    586 	
    587     // try to early out the check
    588     if (::g->earlyout
    589 	&& frac < FRACUNIT
    590 	&& !ld->backsector)
    591     {
    592 	return false;	// stop checking
    593     }
    594     
    595 	
    596     ::g->intercept_p->frac = frac;
    597     ::g->intercept_p->isaline = true;
    598     ::g->intercept_p->d.line = ld;
    599     ::g->intercept_p++;
    600 
    601     return true;	// continue
    602 }
    603 
    604 
    605 
    606 //
    607 // PIT_AddThingIntercepts
    608 //
    609 qboolean PIT_AddThingIntercepts (mobj_t* thing)
    610 {
    611     fixed_t		x1;
    612     fixed_t		y1;
    613     fixed_t		x2;
    614     fixed_t		y2;
    615     
    616     int			s1;
    617     int			s2;
    618     
    619     qboolean		tracepositive;
    620 
    621     divline_t		dl;
    622     
    623     fixed_t		frac;
    624 	
    625     tracepositive = (::g->trace.dx ^ ::g->trace.dy)>0;
    626 		
    627     // check a corner to corner crossection for hit
    628     if (tracepositive)
    629     {
    630 	x1 = thing->x - thing->radius;
    631 	y1 = thing->y + thing->radius;
    632 		
    633 	x2 = thing->x + thing->radius;
    634 	y2 = thing->y - thing->radius;			
    635     }
    636     else
    637     {
    638 	x1 = thing->x - thing->radius;
    639 	y1 = thing->y - thing->radius;
    640 		
    641 	x2 = thing->x + thing->radius;
    642 	y2 = thing->y + thing->radius;			
    643     }
    644     
    645     s1 = P_PointOnDivlineSide (x1, y1, &::g->trace);
    646     s2 = P_PointOnDivlineSide (x2, y2, &::g->trace);
    647 
    648     if (s1 == s2)
    649 	return true;		// line isn't crossed
    650 	
    651     dl.x = x1;
    652     dl.y = y1;
    653     dl.dx = x2-x1;
    654     dl.dy = y2-y1;
    655     
    656     frac = P_InterceptVector (&::g->trace, &dl);
    657 
    658     if (frac < 0)
    659 	return true;		// behind source
    660 
    661     ::g->intercept_p->frac = frac;
    662     ::g->intercept_p->isaline = false;
    663     ::g->intercept_p->d.thing = thing;
    664     ::g->intercept_p++;
    665 
    666     return true;		// keep going
    667 }
    668 
    669 
    670 //
    671 // P_TraverseIntercepts
    672 // Returns true if the traverser function returns true
    673 // for all ::g->lines.
    674 // 
    675 qboolean
    676 P_TraverseIntercepts
    677 ( traverser_t	func,
    678   fixed_t	maxfrac )
    679 {
    680     int			count;
    681     fixed_t		dist;
    682     intercept_t*	scan;
    683     intercept_t*	in;
    684 	
    685     count = ::g->intercept_p - ::g->intercepts;
    686     
    687     in = 0;			// shut up compiler warning
    688 	
    689     while (count--)
    690     {
    691 	dist = MAXINT;
    692 	for (scan = ::g->intercepts ; scan < ::g->intercept_p ; scan++)
    693 	{
    694 	    if (scan->frac < dist)
    695 	    {
    696 		dist = scan->frac;
    697 		in = scan;
    698 	    }
    699 	}
    700 	
    701 	if (dist > maxfrac)
    702 	    return true;	// checked everything in range		
    703 
    704 #if 0  // UNUSED
    705     {
    706 	// don't check these yet, there may be others inserted
    707 	in = scan = ::g->intercepts;
    708 	for ( scan = ::g->intercepts ; scan<::g->intercept_p ; scan++)
    709 	    if (scan->frac > maxfrac)
    710 		*in++ = *scan;
    711 	::g->intercept_p = in;
    712 	return false;
    713     }
    714 #endif
    715 
    716         if ( !func (in) )
    717 	    return false;	// don't bother going farther
    718 
    719 	in->frac = MAXINT;
    720     }
    721 	
    722     return true;		// everything was traversed
    723 }
    724 
    725 
    726 
    727 
    728 //
    729 // P_PathTraverse
    730 // Traces a line from x1,y1 to x2,y2,
    731 // calling the traverser function for each.
    732 // Returns true if the traverser function returns true
    733 // for all ::g->lines.
    734 //
    735 qboolean
    736 P_PathTraverse
    737 ( fixed_t		x1,
    738   fixed_t		y1,
    739   fixed_t		x2,
    740   fixed_t		y2,
    741   int			flags,
    742   qboolean (*trav) (intercept_t *))
    743 {
    744     fixed_t	xt1;
    745     fixed_t	yt1;
    746     fixed_t	xt2;
    747     fixed_t	yt2;
    748     
    749     fixed_t	xstep;
    750     fixed_t	ystep;
    751     
    752     fixed_t	partial;
    753     
    754     fixed_t	xintercept;
    755     fixed_t	yintercept;
    756     
    757     int		mapx;
    758     int		mapy;
    759     
    760     int		mapxstep;
    761     int		mapystep;
    762 
    763     int		count;
    764 		
    765     ::g->earlyout = flags & PT_EARLYOUT;
    766 		
    767     ::g->validcount++;
    768     ::g->intercept_p = ::g->intercepts;
    769 	
    770     if ( ((x1-::g->bmaporgx)&(MAPBLOCKSIZE-1)) == 0)
    771 	x1 += FRACUNIT;	// don't side exactly on a line
    772     
    773     if ( ((y1-::g->bmaporgy)&(MAPBLOCKSIZE-1)) == 0)
    774 	y1 += FRACUNIT;	// don't side exactly on a line
    775 
    776     ::g->trace.x = x1;
    777     ::g->trace.y = y1;
    778     ::g->trace.dx = x2 - x1;
    779     ::g->trace.dy = y2 - y1;
    780 
    781     x1 -= ::g->bmaporgx;
    782     y1 -= ::g->bmaporgy;
    783     xt1 = x1>>MAPBLOCKSHIFT;
    784     yt1 = y1>>MAPBLOCKSHIFT;
    785 
    786     x2 -= ::g->bmaporgx;
    787     y2 -= ::g->bmaporgy;
    788     xt2 = x2>>MAPBLOCKSHIFT;
    789     yt2 = y2>>MAPBLOCKSHIFT;
    790 
    791     if (xt2 > xt1)
    792     {
    793 	mapxstep = 1;
    794 	partial = FRACUNIT - ((x1>>MAPBTOFRAC)&(FRACUNIT-1));
    795 	ystep = FixedDiv (y2-y1,abs(x2-x1));
    796     }
    797     else if (xt2 < xt1)
    798     {
    799 	mapxstep = -1;
    800 	partial = (x1>>MAPBTOFRAC)&(FRACUNIT-1);
    801 	ystep = FixedDiv (y2-y1,abs(x2-x1));
    802     }
    803     else
    804     {
    805 	mapxstep = 0;
    806 	partial = FRACUNIT;
    807 	ystep = 256*FRACUNIT;
    808     }	
    809 
    810     yintercept = (y1>>MAPBTOFRAC) + FixedMul (partial, ystep);
    811 
    812 	
    813     if (yt2 > yt1)
    814     {
    815 	mapystep = 1;
    816 	partial = FRACUNIT - ((y1>>MAPBTOFRAC)&(FRACUNIT-1));
    817 	xstep = FixedDiv (x2-x1,abs(y2-y1));
    818     }
    819     else if (yt2 < yt1)
    820     {
    821 	mapystep = -1;
    822 	partial = (y1>>MAPBTOFRAC)&(FRACUNIT-1);
    823 	xstep = FixedDiv (x2-x1,abs(y2-y1));
    824     }
    825     else
    826     {
    827 	mapystep = 0;
    828 	partial = FRACUNIT;
    829 	xstep = 256*FRACUNIT;
    830     }	
    831     xintercept = (x1>>MAPBTOFRAC) + FixedMul (partial, xstep);
    832     
    833     // Step through map blocks.
    834     // Count is present to prevent a round off error
    835     // from skipping the break.
    836     mapx = xt1;
    837     mapy = yt1;
    838 	
    839     for (count = 0 ; count < 64 ; count++)
    840     {
    841 	if (flags & PT_ADDLINES)
    842 	{
    843 	    if (!P_BlockLinesIterator (mapx, mapy,PIT_AddLineIntercepts))
    844 		return false;	// early out
    845 	}
    846 	
    847 	if (flags & PT_ADDTHINGS)
    848 	{
    849 	    if (!P_BlockThingsIterator (mapx, mapy,PIT_AddThingIntercepts))
    850 		return false;	// early out
    851 	}
    852 		
    853 	if (mapx == xt2
    854 	    && mapy == yt2)
    855 	{
    856 	    break;
    857 	}
    858 	
    859 	if ( (yintercept >> FRACBITS) == mapy)
    860 	{
    861 	    yintercept += ystep;
    862 	    mapx += mapxstep;
    863 	}
    864 	else if ( (xintercept >> FRACBITS) == mapx)
    865 	{
    866 	    xintercept += xstep;
    867 	    mapy += mapystep;
    868 	}
    869 		
    870     }
    871     // go through the sorted list
    872     return P_TraverseIntercepts ( trav, FRACUNIT );
    873 }
    874 
    875 
    876 
    877