DOOM64-RE

DOOM 64 Reverse Engineering
Log | Files | Refs | README | LICENSE

p_base.c (17188B)


      1 /* p_base.c */
      2 
      3 #include "doomdef.h"
      4 #include "p_local.h"
      5 
      6 //completo y revisado
      7 
      8 mobj_t *checkthing;		/* Used for PB_CheckThing */    // 800A55D0
      9 fixed_t testx, testy;                                    // 800A55D8, 800A55DC
     10 static fixed_t testfloorz, testceilingz, testdropoffz;          // 800A5604, 800A5608, 800A560C
     11 static subsector_t *testsubsec;                                 // 800A55F8
     12 static line_t *ceilingline;                                     // 800A5600
     13 static mobj_t *hitthing;                                        // 800A55fC
     14 static fixed_t testbbox[4];		/* Bounding box for tests */    // 800A55E8
     15 int testflags;                                           // 800A55D4
     16 fixed_t testradius;                                      // 800A55E0
     17 
     18 void P_XYMovement(mobj_t *mo);
     19 void P_FloatChange(mobj_t *mo);
     20 void P_ZMovement(mobj_t *mo);
     21 void P_MobjThinker(mobj_t *mobj);
     22 boolean PB_TryMove(int tryx, int tryy);
     23 void PB_UnsetThingPosition(mobj_t *thing);
     24 void PB_SetThingPosition(mobj_t *thing);
     25 boolean PB_CheckPosition(void);
     26 boolean PB_BoxCrossLine(line_t *ld);
     27 boolean PB_CheckLine(line_t *ld);
     28 boolean PB_CheckThing(mobj_t *thing);
     29 boolean PB_BlockLinesIterator(int x, int y);
     30 boolean PB_BlockThingsIterator(int x, int y);
     31 
     32 /*
     33 =================
     34 =
     35 = P_RunMobjBase
     36 =
     37 = Execute base think logic for the critters every tic
     38 =
     39 =================
     40 */
     41 
     42 void P_RunMobjBase(void) // 8000CDE0
     43 {
     44     mobj_t *mo;
     45     mobj_t *next;
     46 
     47 	for (mo = mobjhead.next; mo != &mobjhead; mo = mo->next)
     48 	{
     49 	    /* Based on Doom 64 Ex */
     50 	    /*-----------------------------------------------------------------------------------*/
     51         if((players[0].cheats & CF_LOCKMOSTERS) && !mo->player && mo->flags & MF_COUNTKILL) {
     52             continue;
     53         }
     54         /*-----------------------------------------------------------------------------------*/
     55 
     56 		if (!mo->player)
     57 		{
     58 			mo->latecall = NULL;
     59 			P_MobjThinker(mo);
     60 		}
     61 	}
     62 
     63     //P_RunMobjLate();
     64 	for (mo = mobjhead.next; mo != &mobjhead; mo = next)
     65 	{
     66 	    next = mo->next;	/* in case mo is removed this time */
     67 
     68 	    /* Based on Doom 64 Ex */
     69 	    /*-----------------------------------------------------------------------------------*/
     70         if((players[0].cheats & CF_LOCKMOSTERS) && !mo->player && mo->flags & MF_COUNTKILL) {
     71             continue;
     72         }
     73         /*-----------------------------------------------------------------------------------*/
     74 
     75 	    if(mo->latecall)
     76 		{
     77 			mo->latecall(mo);
     78 		}
     79 	}
     80 }
     81 
     82 /*
     83 ===================
     84 =
     85 = P_MobjThinker
     86 =
     87 = Process all the critter logic
     88 =
     89 ===================
     90 */
     91 
     92 void P_MobjThinker(mobj_t *mobj) // 8000CE74
     93 {
     94 	state_t *st;
     95 	statenum_t state;
     96 
     97 	checkthing = mobj;
     98 
     99 	// momentum movement
    100 	if (mobj->momx || mobj->momy)
    101     {
    102 		P_XYMovement(mobj);
    103 
    104         // removed or has a special action to perform?
    105         if (mobj->latecall)
    106             return;
    107     }
    108 
    109 	if (mobj->z != mobj->floorz || mobj->momz)
    110     {
    111 		P_ZMovement(mobj);
    112 
    113         // removed or has a special action to perform?
    114         if (mobj->latecall)
    115             return;
    116     }
    117 
    118 	// cycle through states
    119 	if (mobj->tics != -1)
    120 	{
    121 		mobj->tics--;
    122 
    123 		// you can cycle through multiple states in a tic
    124         if (mobj->tics <= 0)
    125 		{
    126 			state = mobj->state->nextstate;
    127 			if (state == S_000)
    128 			{
    129 				mobj->latecall = P_RemoveMobj;
    130 			}
    131 			else
    132 			{
    133 				st = &states[state];
    134 				mobj->state = st;
    135 				mobj->tics = st->tics;
    136 				mobj->sprite = st->sprite;
    137 				mobj->frame = st->frame;
    138 				mobj->latecall = st->action;
    139 			}
    140 		}
    141 	}
    142 }
    143 
    144 
    145 /*
    146 ===================
    147 =
    148 = P_XYMovement
    149 =
    150 ===================
    151 */
    152 
    153 #define	STOPSPEED		0x1000
    154 #define	FRICTION		0xd200  //Jag 0xd240
    155 
    156 void P_XYMovement(mobj_t *mo) // 8000CF98
    157 {
    158 	fixed_t xleft, yleft;
    159 	fixed_t xuse, yuse;
    160 
    161 	//
    162 	// cut the move into chunks if too large
    163 	//
    164 
    165 	xleft = xuse = mo->momx & ~7;
    166 	yleft = yuse = mo->momy & ~7;
    167 
    168 	while (xuse > MAXMOVE || xuse < -MAXMOVE
    169 		|| yuse > MAXMOVE || yuse < -MAXMOVE)
    170 	{
    171 		xuse >>= 1;
    172 		yuse >>= 1;
    173 	}
    174 
    175 	while (xleft || yleft)
    176 	{
    177 		xleft -= xuse;
    178 		yleft -= yuse;
    179 		if (!PB_TryMove(mo->x + xuse, mo->y + yuse))
    180 		{
    181 			// blocked move
    182 			if (mo->flags & MF_SKULLFLY)
    183 			{
    184 				mo->latecall = L_SkullBash;
    185 				mo->extradata = (mobj_t*)hitthing;
    186 			}
    187 
    188 			// explode a missile
    189 			if (mo->flags & MF_MISSILE)
    190 			{
    191 			    if(hitthing == NULL && ceilingline)
    192                 {
    193                     if ((ceilingline->backsector && (ceilingline->backsector->ceilingpic == -1)) ||
    194                        ((ceilingline->backsector == NULL) && (sides[ceilingline->sidenum[0]].midtexture == 1))) // hack to prevent missiles exploding against the sky
    195                     {
    196                         mo->latecall = P_RemoveMobj;
    197                         return;
    198                     }
    199                 }
    200 
    201 				mo->latecall = L_MissileHit;
    202 				mo->extradata = (mobj_t*)hitthing;
    203 				return;
    204 			}
    205 
    206 			mo->momx = mo->momy = 0;
    207 			return;
    208 		}
    209 	}
    210 
    211 	//
    212 	// slow down
    213 	//
    214 	if (mo->flags & (MF_MISSILE | MF_SKULLFLY))
    215 		return;		// no friction for missiles ever
    216 
    217 	if (mo->z > mo->floorz)
    218 		return;		// no friction when airborne
    219 
    220 	if ((mo->flags & MF_CORPSE) && (mo->floorz != mo->subsector->sector->floorheight))
    221         return;		// don't stop halfway off a step
    222 
    223 	if (mo->momx > -STOPSPEED && mo->momx < STOPSPEED &&
    224         mo->momy > -STOPSPEED && mo->momy < STOPSPEED)
    225     {
    226 		mo->momx = 0;
    227 		mo->momy = 0;
    228 	}
    229 	else
    230     {
    231 		mo->momx = (mo->momx >> 8) * (FRICTION >> 8);
    232 		mo->momy = (mo->momy >> 8) * (FRICTION >> 8);
    233 	}
    234 }
    235 
    236 /*
    237 ===================
    238 =
    239 = P_FloatChange
    240 =
    241 = Float up or down at a set speed, used by flying monsters
    242 =
    243 ===================
    244 */
    245 
    246 void P_FloatChange(mobj_t *mo) // inline function
    247 {
    248 	mobj_t *target;
    249 	fixed_t dist, delta;
    250 
    251 	target = mo->target;		/* Get the target object */
    252 
    253 	dist = P_AproxDistance(target->x - mo->x, target->y - mo->y);	/* Distance to target */
    254 
    255     delta = (target->z + (mo->height >> 1)) - mo->z;	/* Get the height differance */
    256 	delta *= 3; /* Mul by 3 for a fudge factor */
    257 
    258 	if (delta<0)		                /* Delta is signed... */
    259     {
    260 		if (dist < (-delta))	        /* Negate */
    261         {
    262 			mo->z -= FLOATSPEED;        /* Adjust the height */
    263 		}
    264 	}
    265 	else if (delta>0)		            /* Delta is signed... */
    266     {
    267         if (dist < delta)		        /* Normal compare */
    268         {
    269             mo->z += FLOATSPEED;	    /* Adjust the height */
    270         }
    271 	}
    272 }
    273 
    274 /*
    275 ===================
    276 =
    277 = P_ZMovement
    278 =
    279 = Move a critter in the Z axis
    280 =
    281 ===================
    282 */
    283 
    284 void P_ZMovement(mobj_t *mo) // 8000D228
    285 {
    286 
    287 	mo->z += mo->momz;		/* Basic z motion */
    288 
    289 	if ((mo->flags & MF_FLOAT) && mo->target)   /* float down towards target if too close */
    290     {
    291 		P_FloatChange(mo);
    292 	}
    293 
    294 	//
    295 	// clip movement
    296 	//
    297 	if (mo->z <= mo->floorz)	// hit the floor
    298 	{
    299 		if (mo->momz < 0)
    300 			mo->momz = 0;
    301 
    302 		mo->z = mo->floorz;
    303 		if ((mo->flags & MF_MISSILE) && (mo->type != MT_PROJ_RECTFIRE))
    304 		{
    305 			mo->latecall = P_ExplodeMissile;
    306 			return;
    307 		}
    308 	}
    309 	else if (mo->flags & MF_GRAVITY)
    310 	{
    311 		// apply gravity
    312 		if (mo->momz == 0)
    313 			mo->momz = -(GRAVITY/2);
    314 		else
    315 			mo->momz -= ((GRAVITY/FRACBITS)*3); // [d64]: non-players fall slightly slower
    316 	}
    317 
    318 	if (mo->z + mo->height > mo->ceilingz) // hit the ceiling
    319 	{
    320 		if (mo->momz > 0)
    321 			mo->momz = 0;
    322 
    323 		mo->z = mo->ceilingz - mo->height;
    324 		if (mo->flags & MF_MISSILE)
    325 			mo->latecall = P_ExplodeMissile;
    326 	}
    327 }
    328 
    329 /*
    330 ===================
    331 =
    332 = PB_TryMove
    333 =
    334 = Attempt to move to a new position
    335 =
    336 ===================
    337 */
    338 
    339 boolean PB_TryMove(int tryx, int tryy) // 8000D3F4
    340 {
    341     testradius = checkthing->radius;
    342     testflags = checkthing->flags;
    343 	testx = tryx;
    344 	testy = tryy;
    345 
    346 	if (!PB_CheckPosition())
    347 		return false;		// solid wall or thing
    348 
    349 	if (testceilingz - testfloorz < checkthing->height)
    350 		return false;			// doesn't fit
    351 	if (testceilingz - checkthing->z < checkthing->height)
    352 		return false;			// mobj must lower itself to fit
    353 	if (testfloorz - checkthing->z > 24 * FRACUNIT)
    354 		return false;			// too big a step up
    355 	if (!(testflags&(MF_DROPOFF | MF_FLOAT)) && testfloorz - testdropoffz > 24 * FRACUNIT)
    356 		return false;			// don't stand over a dropoff
    357 
    358 	//
    359 	// the move is ok, so link the thing into its new position
    360 	//
    361 
    362 	PB_UnsetThingPosition(checkthing);
    363 	checkthing->floorz = testfloorz;
    364 	checkthing->ceilingz = testceilingz;
    365 	checkthing->x = tryx;
    366 	checkthing->y = tryy;
    367 	PB_SetThingPosition(checkthing);
    368 	return true;
    369 }
    370 
    371 /*
    372 ===================
    373 =
    374 = PB_UnsetThingPosition
    375 =
    376 ===================
    377 */
    378 
    379 void PB_UnsetThingPosition(mobj_t *thing) // 8000D55C
    380 {
    381 	int blockx, blocky;
    382 
    383 	// inert things don't need to be in blockmap
    384 	// unlink from subsector
    385 	if (thing->snext)
    386 		thing->snext->sprev = thing->sprev;
    387 	if (thing->sprev)
    388 		thing->sprev->snext = thing->snext;
    389 	else
    390 		thing->subsector->sector->thinglist = thing->snext;
    391 
    392 	if (!(testflags & MF_NOBLOCKMAP))
    393 	{
    394 		// inert things don't need to be in blockmap
    395 		// unlink from block map
    396 		if (thing->bnext)
    397 			thing->bnext->bprev = thing->bprev;
    398 		if (thing->bprev)
    399 			thing->bprev->bnext = thing->bnext;
    400 		else
    401 		{
    402 			blockx = (thing->x - bmaporgx) >> MAPBLOCKSHIFT;
    403 			blocky = (thing->y - bmaporgy) >> MAPBLOCKSHIFT;
    404 
    405 			// Prevent buffer overflow if the map object is out of bounds.
    406             // This is part of the fix for the famous 'linedef deletion' bug.
    407             // From PsyDoom (StationDoom) by BodbDearg
    408 			#if FIX_LINEDEFS_DELETION == 1
    409             if (blockx>=0 && blockx <bmapwidth
    410              && blocky>=0 && blocky <bmapheight)
    411             {
    412                 blocklinks[blocky*bmapwidth+blockx] = thing->bnext;
    413             }
    414             #else
    415                 blocklinks[blocky*bmapwidth+blockx] = thing->bnext;
    416 			#endif
    417 		}
    418 	}
    419 }
    420 
    421 /*
    422 ===================
    423 =
    424 = PB_SetThingPosition
    425 =
    426 ===================
    427 */
    428 
    429 void PB_SetThingPosition(mobj_t *thing) // 8000D650
    430 {
    431 	sector_t     *sec;
    432 	int           blockx, blocky;
    433 	mobj_t      **link;
    434 
    435 	//
    436 	// link into subsector
    437 	//
    438 
    439 	thing->subsector = testsubsec;
    440 	sec = thing->subsector->sector;
    441 
    442 	thing->sprev = NULL;
    443 	thing->snext = sec->thinglist;
    444 
    445 	if (sec->thinglist)
    446 		sec->thinglist->sprev = thing;
    447 
    448 	sec->thinglist = thing;
    449 
    450 	//
    451 	// link into blockmap
    452 	//
    453 	if (!(testflags & MF_NOBLOCKMAP))
    454 	{
    455 		// inert things don't need to be in blockmap
    456 		blockx = (thing->x - bmaporgx) >> MAPBLOCKSHIFT;
    457 		blocky = (thing->y - bmaporgy) >> MAPBLOCKSHIFT;
    458 		if (blockx >= 0 && blockx < bmapwidth && blocky >= 0 && blocky < bmapheight)
    459 		{
    460 			link = &blocklinks[blocky*bmapwidth + blockx];
    461 			thing->bprev = NULL;
    462 			thing->bnext = *link;
    463 			if (*link)
    464 				(*link)->bprev = thing;
    465 			*link = thing;
    466 		}
    467 		else
    468 		{
    469 			// thing is off the map
    470 			thing->bnext = thing->bprev = NULL;
    471 		}
    472 	}
    473 }
    474 
    475 /*
    476 ==================
    477 =
    478 = PB_CheckPosition
    479 =
    480 = This is purely informative, nothing is modified (except things picked up)
    481 
    482 in:
    483 basething		a mobj_t
    484 testx,testy		a position to be checked (doesn't need relate to the mobj_t->x,y)
    485 
    486 out:
    487 
    488 testsubsec
    489 floorz
    490 ceilingz
    491 testdropoffz		the lowest point contacted (monsters won't move to a dropoff)
    492 hitthing
    493 
    494 ==================
    495 */
    496 
    497 boolean PB_CheckPosition(void) // 8000D750
    498 {
    499 	int			xl, xh, yl, yh, bx, by;
    500 
    501 	testbbox[BOXTOP   ] = testy + testradius;
    502 	testbbox[BOXBOTTOM] = testy - testradius;
    503 	testbbox[BOXRIGHT ] = testx + testradius;
    504 	testbbox[BOXLEFT  ] = testx - testradius;
    505 
    506 	//
    507 	// the base floor / ceiling is from the subsector that contains the
    508 	// point.  Any contacted lines the step closer together will adjust them
    509 	//
    510 	testsubsec = R_PointInSubsector(testx, testy);
    511 	testfloorz = testdropoffz = testsubsec->sector->floorheight;
    512 	testceilingz = testsubsec->sector->ceilingheight;
    513 
    514 	++validcount;
    515 
    516 	ceilingline = NULL;
    517 	hitthing = NULL;
    518 
    519 	//
    520 	// the bounding box is extended by MAXRADIUS because mobj_ts are grouped
    521 	// into mapblocks based on their origin point, and can overlap into adjacent
    522 	// blocks by up to MAXRADIUS units
    523 	//
    524 
    525 	// [d64]: intentionally removed MAXRADIUS?
    526 	xl = (testbbox[BOXLEFT  ] - bmaporgx) >> MAPBLOCKSHIFT;
    527 	xh = (testbbox[BOXRIGHT ] - bmaporgx) >> MAPBLOCKSHIFT;
    528 	yl = (testbbox[BOXBOTTOM] - bmaporgy) >> MAPBLOCKSHIFT;
    529 	yh = (testbbox[BOXTOP   ] - bmaporgy) >> MAPBLOCKSHIFT;
    530 
    531 	if (xl<0)
    532 	{
    533 		xl = 0;
    534 	}
    535 	if (yl<0)
    536 	{
    537 		yl = 0;
    538 	}
    539 	if (xh >= bmapwidth)
    540 	{
    541 		xh = bmapwidth - 1;
    542 	}
    543 	if (yh >= bmapheight)
    544 	{
    545 		yh = bmapheight - 1;
    546 	}
    547 
    548 	for (bx = xl; bx <= xh; bx++)
    549 	{
    550 		for (by = yl; by <= yh; by++)
    551         {
    552 			if (!PB_BlockLinesIterator(bx, by))
    553 				return false;
    554 			if (!PB_BlockThingsIterator(bx, by))
    555 				return false;
    556 		}
    557 	}
    558 
    559 	return true;
    560 }
    561 
    562 /*
    563 =================
    564 =
    565 = PB_BoxCrossLine
    566 =
    567 =================
    568 */
    569 
    570 boolean PB_BoxCrossLine(line_t *ld) // 8000920
    571 {
    572 	fixed_t x1, x2;
    573 	fixed_t lx, ly;
    574 	fixed_t ldx, ldy;
    575 	fixed_t dx1, dy1;
    576 	fixed_t dx2, dy2;
    577 	boolean side1, side2;
    578 
    579     // entirely outside bounding box of line?
    580     if(testbbox[BOXRIGHT ] <= ld->bbox[BOXLEFT  ] ||
    581        testbbox[BOXLEFT  ] >= ld->bbox[BOXRIGHT ] ||
    582        testbbox[BOXTOP   ] <= ld->bbox[BOXBOTTOM] ||
    583        testbbox[BOXBOTTOM] >= ld->bbox[BOXTOP   ])
    584     {
    585         return false;
    586     }
    587 
    588 	if (ld->slopetype == ST_POSITIVE)
    589     {
    590 		x1 = testbbox[BOXLEFT];
    591 		x2 = testbbox[BOXRIGHT];
    592 	}
    593 	else
    594 	{
    595 		x1 = testbbox[BOXRIGHT];
    596 		x2 = testbbox[BOXLEFT];
    597 	}
    598 
    599 	lx = ld->v1->x;
    600 	ly = ld->v1->y;
    601 	ldx = ld->dx >> FRACBITS;
    602 	ldy = ld->dy >> FRACBITS;
    603 
    604 	dx1 = (x1 - lx) >> 16;
    605 	dy1 = (testbbox[BOXTOP] - ly) >> FRACBITS;
    606 	dx2 = (x2 - lx) >> 16;
    607 	dy2 = (testbbox[BOXBOTTOM] - ly) >> FRACBITS;
    608 
    609 	side1 = ldy*dx1 < dy1*ldx;
    610 	side2 = ldy*dx2 < dy2*ldx;
    611 
    612 	return (side1 != side2);
    613 }
    614 
    615 /*
    616 ==================
    617 =
    618 = PB_CheckLine
    619 =
    620 = Adjusts testfloorz and testceilingz as lines are contacted
    621 ==================
    622 */
    623 
    624 boolean PB_CheckLine(line_t *ld) // 8000DA44
    625 {
    626 	fixed_t opentop, openbottom;
    627 	fixed_t lowfloor;
    628 	sector_t	*front, *back;
    629 
    630 	/*
    631 	=
    632 	= The moving thing's destination position will cross the given line.
    633 	= If this should not be allowed, return FALSE.
    634 	*/
    635 	if (!ld->backsector)
    636     {
    637         ceilingline  = ld;
    638 		return false;		// one sided line
    639     }
    640 
    641 	if (!(testflags & MF_MISSILE) && (ld->flags & (ML_BLOCKING | ML_BLOCKMONSTERS)))
    642     {
    643         ceilingline  = ld;
    644 		return false;		// explicitly blocking
    645     }
    646 
    647     // [d64] don't cross projectile blockers
    648 	if ((ld->flags & ML_BLOCKPROJECTILES)) //psx doom / doom 64 new
    649     {
    650         ceilingline  = ld;
    651 		return false;
    652     }
    653 
    654 	front = ld->frontsector;
    655 	back = ld->backsector;
    656 
    657 	if (front->ceilingheight < back->ceilingheight)
    658 		opentop = front->ceilingheight;
    659 	else
    660 		opentop = back->ceilingheight;
    661 
    662 	if (front->floorheight > back->floorheight)
    663 	{
    664 		openbottom = front->floorheight;
    665 		lowfloor = back->floorheight;
    666 	}
    667 	else
    668 	{
    669 		openbottom = back->floorheight;
    670 		lowfloor = front->floorheight;
    671 	}
    672 
    673 	// adjust floor / ceiling heights
    674 	if (opentop < testceilingz)
    675 	{
    676 		testceilingz = opentop;
    677 		ceilingline = ld;
    678 	}
    679 	if (openbottom > testfloorz)
    680 		testfloorz = openbottom;
    681 	if (lowfloor < testdropoffz)
    682 		testdropoffz = lowfloor;
    683 
    684 	return true;
    685 }
    686 
    687 /*
    688 ==================
    689 =
    690 = PB_BlockLinesIterator
    691 =
    692 ==================
    693 */
    694 
    695 boolean PB_BlockLinesIterator(int x, int y) // 8000DB70
    696 {
    697 	int     offset;
    698 	short  *list;
    699 	line_t *ld;
    700 
    701 	offset = y*bmapwidth+x;
    702 
    703 	offset = *(blockmap + offset);
    704 
    705 	for (list = blockmaplump + offset; *list != -1; list++)
    706 	{
    707 		ld = &lines[*list];
    708 		if (ld->validcount == validcount)
    709 			continue; // line has already been checked
    710 		ld->validcount = validcount;
    711 
    712 		if (PB_BoxCrossLine(ld))
    713 		{
    714 			if (!PB_CheckLine(ld))
    715 				return false;
    716 		}
    717 	}
    718 
    719 	return true; // everything was checked
    720 }
    721 
    722 /*
    723 ==================
    724 =
    725 = PB_CheckThing
    726 =
    727 ==================
    728 */
    729 
    730 boolean PB_CheckThing(mobj_t *thing) // 8000DC70
    731 {
    732 	fixed_t  blockdist;
    733 	int      delta;
    734 	mobj_t  *mo;
    735 
    736 	if (!(thing->flags & MF_SOLID))
    737 		return true; // not blocking
    738 
    739 	mo = checkthing;
    740 
    741 	if(thing == mo)
    742         return true;    // don't clip against self
    743 
    744 	blockdist = thing->radius + testradius;
    745 
    746 	delta = thing->x - testx;
    747 	if (delta < 0)
    748 		delta = -delta;
    749 
    750 	if (delta >= blockdist)
    751 		return true; // didn't hit it
    752 
    753 	delta = thing->y - testy;
    754 	if (delta < 0)
    755 		delta = -delta;
    756 
    757 	if (delta >= blockdist)
    758 		return true; // didn't hit it
    759 
    760 	//
    761 	// check for skulls slamming into things
    762 	//
    763 	if (testflags & MF_SKULLFLY)
    764 	{
    765 		hitthing = thing;
    766 		return false;		// stop moving
    767 	}
    768 
    769 	//
    770 	// missiles can hit other things
    771 	//
    772 	if (testflags & MF_MISSILE)
    773     {
    774 		// see if it went over / under
    775 		if (mo->z > thing->z + thing->height)
    776 			return true;		// overhead
    777 
    778 		if (mo->z + mo->height < thing->z)
    779 			return true;		// underneath
    780 
    781 		if (mo->target->type == thing->type)	// don't hit same species as originator
    782         {
    783 			if (thing == mo->target)
    784 				return true;	// don't explode on shooter
    785 
    786 			if (thing->type != MT_PLAYER)
    787 				return false;	// explode, but do no damage
    788 								// let players missile other players
    789 		}
    790 		if (!(thing->flags & MF_SHOOTABLE))
    791 			return !(thing->flags & MF_SOLID);		// didn't do any damage
    792 													// damage / explode
    793 		hitthing = thing;
    794 		return false;			// don't traverse any more
    795 	}
    796 
    797 	return !(thing->flags & MF_SOLID);
    798 }
    799 
    800 
    801 /*
    802 ==================
    803 =
    804 = PB_BlockThingsIterator
    805 =
    806 ==================
    807 */
    808 
    809 boolean PB_BlockThingsIterator(int x, int y) // 8000DDD4
    810 {
    811 	mobj_t *mobj;
    812 
    813 	for (mobj = blocklinks[y*bmapwidth+x]; mobj; mobj = mobj->bnext)
    814 	{
    815 		if (!PB_CheckThing(mobj))
    816 			return false;
    817 	}
    818 
    819 	return true;
    820 }