📄 p_map.c
字号:
} } } else if(tmthing->type == MT_MSTAFF_FX2 && thing != tmthing->target) { if(!thing->player && !(thing->flags2&MF2_BOSS)) { switch(thing->type) { case MT_FIGHTER_BOSS: // these not flagged boss case MT_CLERIC_BOSS: // so they can be blasted case MT_MAGE_BOSS: break; default: P_DamageMobj(thing, tmthing, tmthing->target, 10); return true; break; } } } if(tmthing->target && tmthing->target->type == thing->type) { // Don't hit same species as originator if(thing == tmthing->target) { // Don't missile self return(true); } if(!thing->player) { // Hit same species as originator, explode, no damage return(false); } } if(!(thing->flags&MF_SHOOTABLE)) { // Didn't do any damage return!(thing->flags&MF_SOLID); } if(tmthing->flags2&MF2_RIP) { if (!(thing->flags&MF_NOBLOOD) && !(thing->flags2&MF2_REFLECTIVE) && !(thing->flags2&MF2_INVULNERABLE)) { // Ok to spawn some blood P_RipperBlood(tmthing); } //S_StartSound(tmthing, sfx_ripslop); damage = ((P_Random()&3)+2)*tmthing->damage; P_DamageMobj(thing, tmthing, tmthing->target, damage); if(thing->flags2&MF2_PUSHABLE && !(tmthing->flags2&MF2_CANNOTPUSH)) { // Push thing thing->momx += tmthing->momx>>2; thing->momy += tmthing->momy>>2; } numspechit = 0; return(true); } // Do damage damage = ((P_Random()%8)+1)*tmthing->damage; if(damage) { if (!(thing->flags&MF_NOBLOOD) && !(thing->flags2&MF2_REFLECTIVE) && !(thing->flags2&MF2_INVULNERABLE) && !(tmthing->type == MT_TELOTHER_FX1) && !(tmthing->type == MT_TELOTHER_FX2) && !(tmthing->type == MT_TELOTHER_FX3) && !(tmthing->type == MT_TELOTHER_FX4) && !(tmthing->type == MT_TELOTHER_FX5) && (P_Random() < 192)) { P_BloodSplatter(tmthing->x, tmthing->y, tmthing->z, thing); } P_DamageMobj(thing, tmthing, tmthing->target, damage); } return(false); } if(thing->flags2&MF2_PUSHABLE && !(tmthing->flags2&MF2_CANNOTPUSH)) { // Push thing thing->momx += tmthing->momx>>2; thing->momy += tmthing->momy>>2; } // Check for special thing if(thing->flags&MF_SPECIAL) { solid = thing->flags&MF_SOLID; if(tmflags&MF_PICKUP) { // Can be picked up by tmthing P_TouchSpecialThing(thing, tmthing); // Can remove thing } return(!solid); } return(!(thing->flags&MF_SOLID));}//---------------------------------------------------------------------------//// PIT_CheckOnmobjZ////---------------------------------------------------------------------------boolean PIT_CheckOnmobjZ(mobj_t *thing){ fixed_t blockdist; if(!(thing->flags&(MF_SOLID|MF_SPECIAL|MF_SHOOTABLE))) { // Can't hit thing return(true); } blockdist = thing->radius+tmthing->radius; if(abs(thing->x-tmx) >= blockdist || abs(thing->y-tmy) >= blockdist) { // Didn't hit thing return(true); } if(thing == tmthing) { // Don't clip against self return(true); } if(tmthing->z > thing->z+thing->height) { return(true); } else if(tmthing->z+tmthing->height < thing->z) { // under thing return(true); } if(thing->flags&MF_SOLID) { onmobj = thing; } return(!(thing->flags&MF_SOLID));}/*=============================================================================== MOVEMENT CLIPPING===============================================================================*///----------------------------------------------------------------------------//// FUNC P_TestMobjLocation//// Returns true if the mobj is not blocked by anything at its current// location, otherwise returns false.////----------------------------------------------------------------------------boolean P_TestMobjLocation(mobj_t *mobj){ int flags; flags = mobj->flags; mobj->flags &= ~MF_PICKUP; if(P_CheckPosition(mobj, mobj->x, mobj->y)) { // XY is ok, now check Z mobj->flags = flags; if((mobj->z < mobj->floorz) || (mobj->z+mobj->height > mobj->ceilingz)) { // Bad Z return(false); } return(true); } mobj->flags = flags; return(false);}/*==================== P_CheckPosition== This is purely informative, nothing is modified (except things picked up)in:a mobj_t (can be valid or invalid)a position to be checked (doesn't need to be related to the mobj_t->x,y)during:special things are touched if MF_PICKUPearly out on solid lines?out:newsubsecfloorzceilingztmdropoffz = the lowest point contacted (monsters won't move to a dropoff)speciallines[]numspeciallinesmobj_t *BlockingMobj = pointer to thing that blocked position (NULL if notblocked, or blocked by a line).==================*/boolean P_CheckPosition (mobj_t *thing, fixed_t x, fixed_t y){ int xl,xh,yl,yh,bx,by; subsector_t *newsubsec; tmthing = thing; tmflags = thing->flags; tmx = x; tmy = y; tmbbox[BOXTOP] = y + tmthing->radius; tmbbox[BOXBOTTOM] = y - tmthing->radius; tmbbox[BOXRIGHT] = x + tmthing->radius; tmbbox[BOXLEFT] = x - tmthing->radius; newsubsec = R_PointInSubsector (x,y); ceilingline = NULL;//// the base floor / ceiling is from the subsector that contains the// point. Any contacted lines the step closer together will adjust them// tmfloorz = tmdropoffz = newsubsec->sector->floorheight; tmceilingz = newsubsec->sector->ceilingheight; tmfloorpic = newsubsec->sector->floorpic; validcount++; numspechit = 0; if(tmflags&MF_NOCLIP && !(tmflags&MF_SKULLFLY)) { return true; }//// check things first, possibly picking things up// the bounding box is extended by MAXRADIUS because mobj_ts are grouped// into mapblocks based on their origin point, and can overlap into adjacent// blocks by up to MAXRADIUS units// xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; BlockingMobj = NULL; for (bx=xl ; bx<=xh ; bx++) for (by=yl ; by<=yh ; by++) if (!P_BlockThingsIterator(bx,by,PIT_CheckThing)) return false;//// check lines// if(tmflags&MF_NOCLIP) { return true; } BlockingMobj = NULL; xl = (tmbbox[BOXLEFT] - bmaporgx)>>MAPBLOCKSHIFT; xh = (tmbbox[BOXRIGHT] - bmaporgx)>>MAPBLOCKSHIFT; yl = (tmbbox[BOXBOTTOM] - bmaporgy)>>MAPBLOCKSHIFT; yh = (tmbbox[BOXTOP] - bmaporgy)>>MAPBLOCKSHIFT; for (bx=xl ; bx<=xh ; bx++) for (by=yl ; by<=yh ; by++) if (!P_BlockLinesIterator (bx,by,PIT_CheckLine)) return false; return true;}//=============================================================================//// P_CheckOnmobj(mobj_t *thing)//// Checks if the new Z position is legal//=============================================================================mobj_t *P_CheckOnmobj(mobj_t *thing){ int xl,xh,yl,yh,bx,by; subsector_t *newsubsec; fixed_t x; fixed_t y; mobj_t oldmo; x = thing->x; y = thing->y; tmthing = thing; tmflags = thing->flags; oldmo = *thing; // save the old mobj before the fake zmovement P_FakeZMovement(tmthing); tmx = x; tmy = y; tmbbox[BOXTOP] = y + tmthing->radius; tmbbox[BOXBOTTOM] = y - tmthing->radius; tmbbox[BOXRIGHT] = x + tmthing->radius; tmbbox[BOXLEFT] = x - tmthing->radius; newsubsec = R_PointInSubsector (x,y); ceilingline = NULL;//// the base floor / ceiling is from the subsector that contains the// point. Any contacted lines the step closer together will adjust them// tmfloorz = tmdropoffz = newsubsec->sector->floorheight; tmceilingz = newsubsec->sector->ceilingheight; tmfloorpic = newsubsec->sector->floorpic; validcount++; numspechit = 0; if ( tmflags & MF_NOCLIP ) return NULL;//// check things first, possibly picking things up// the bounding box is extended by MAXRADIUS because mobj_ts are grouped// into mapblocks based on their origin point, and can overlap into adjacent// blocks by up to MAXRADIUS units// xl = (tmbbox[BOXLEFT] - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; xh = (tmbbox[BOXRIGHT] - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; yl = (tmbbox[BOXBOTTOM] - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; yh = (tmbbox[BOXTOP] - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; for (bx=xl ; bx<=xh ; bx++) for (by=yl ; by<=yh ; by++) if (!P_BlockThingsIterator(bx,by,PIT_CheckOnmobjZ)) { *tmthing = oldmo; return onmobj; } *tmthing = oldmo; return NULL;}//=============================================================================//// P_FakeZMovement//// Fake the zmovement so that we can check if a move is legal//=============================================================================void P_FakeZMovement(mobj_t *mo){ int dist; int delta;//// adjust height// mo->z += mo->momz; if(mo->flags&MF_FLOAT && mo->target) { // float down towards target if too close if(!(mo->flags&MF_SKULLFLY) && !(mo->flags&MF_INFLOAT)) { dist = P_AproxDistance(mo->x-mo->target->x, mo->y-mo->target->y); delta =( mo->target->z+(mo->height>>1))-mo->z; if (delta < 0 && dist < -(delta*3)) mo->z -= FLOATSPEED; else if (delta > 0 && dist < (delta*3)) mo->z += FLOATSPEED; } } if(mo->player && mo->flags2&MF2_FLY && !(mo->z <= mo->floorz) && leveltime&2) { mo->z += finesine[(FINEANGLES/20*leveltime>>2)&FINEMASK]; }//// clip movement// if(mo->z <= mo->floorz) { // Hit the floor mo->z = mo->floorz; if(mo->momz < 0) { mo->momz = 0; } if(mo->flags&MF_SKULLFLY) { // The skull slammed into something mo->momz = -mo->momz; } if(mo->info->crashstate && (mo->flags&MF_CORPSE)) { return; } } else if(mo->flags2&MF2_LOGRAV) { if(mo->momz == 0) mo->momz = -(GRAVITY>>3)*2; else mo->momz -= GRAVITY>>3; } else if (! (mo->flags & MF_NOGRAVITY) ) { if (mo->momz == 0) mo->momz = -GRAVITY*2; else mo->momz -= GRAVITY; } if (mo->z + mo->height > mo->ceilingz) { // hit the ceiling if (mo->momz > 0) mo->momz = 0; mo->z = mo->ceilingz - mo->height; if (mo->flags & MF_SKULLFLY) { // the skull slammed into something mo->momz = -mo->momz; } }}//===========================================================================//// CheckForPushSpecial////===========================================================================static void CheckForPushSpecial(line_t *line, int side, mobj_t *mobj){ if (line->special) { if(mobj->flags2&MF2_PUSHWALL) { P_ActivateLine(line, mobj, side, SPAC_PUSH); } else if(mobj->flags2&MF2_IMPACT) { P_ActivateLine(line, mobj, side, SPAC_IMPACT); } }}/*===================== P_TryMove== Attempt to move to a new position, crossing special lines unless MF_TELEPORT= is set====================*/boolean P_TryMove (mobj_t *thing, fixed_t x, fixed_t y){ fixed_t oldx, oldy; int side, oldside; line_t *ld; floatok = false; if(!P_CheckPosition(thing, x, y)) { // Solid wall or thing if(!BlockingMobj || BlockingMobj->player || !thing->player) { goto pushline; } else if (BlockingMobj->z+BlockingMobj->height-thing->z > 24*FRACUNIT || (BlockingMobj->subsector->sector->ceilingheight -(BlockingMobj->z+BlockingMobj->height) < thing->height) || (tmceilingz-(BlockingMobj->z+BlockingMobj->height) < thing->height)) { goto pushline; } } if(!(thing->flags&MF_NOCLIP)) { if(tmceilingz-tmfloorz < thing->height) { // Doesn't fit goto pushline; } floatok = true; if(!(thing->flags&MF_TELEPORT) && tmceilingz-thing->z < thing->height && thing->type != MT_LIGHTNING_CEILING && !(thing->flags2&MF2_FLY)) { // mobj must lower itself to fit goto pushline; } if(thing->flags2&MF2_FLY) { if(thing->z+thing->height > tmceilingz) { thing->momz = -8*FRACUNIT; goto pushline; } else if(thing->z < tmfloorz && tmfloorz-tmdropoffz > 24*FRACUNIT) { thing->momz = 8*FRACUNIT; goto pushline; } } if(!(thing->flags&MF_TELEPORT) // The Minotaur floor fire (MT_MNTRFX2) can step up any amount && thing->type != MT_MNTRFX2 && thing->type != MT_LIGHTNING_FLOOR && tmfloorz-thing->z > 24*FRACUNIT) { goto pushline; } if (!(thing->flags&(MF_DROPOFF|MF_FLOAT)) && (tmfloorz-tmdropoffz > 24*FRACUNIT) && !(thing->flags2&MF2_BLASTED)) { // Can't move over a dropoff unless it's been blasted return(false); } if(thing->flags2&MF2_CANTLEAVEFLOORPIC && (tmfloorpic != thing->subsector->sector->floorpic || tmfloorz-thing->z != 0)) { // must stay within a sector of a certain floor type return false; } }//// the move is ok, so link the thing into its new position// P_UnsetThingPosition (thing); oldx = thing->x; oldy = thing->y; thing->floorz = tmfloorz; thing->ceilingz = tmceilingz; thing->floorpic = tmfloorpic; thing->x = x; thing->y = y; P_SetThingPosition (thing); if(thing->flags2&MF2_FLOORCLIP) { if(thing->z == thing->subsector->sector->floorheight && P_GetThingFloorType(thing) >= FLOOR_LIQUID) { thing->floorclip = 10*FRACUNIT; } else { thing->floorclip = 0; } }//// if any special lines were hit, do the effect// if (! (thing->flags&(MF_TELEPORT|MF_NOCLIP)) ) { while (numspechit > 0) { numspechit--; // see if the line was crossed ld = spechit[numspechit]; side = P_PointOnLineSide (thing->x, thing->y, ld); oldside = P_PointOnLineSide (oldx, oldy, ld); if (side != oldside) { if (ld->special) { if(thing->player) { P_ActivateLine(ld, thing, oldside, SPAC_CROSS); } else if(thing->flags2&MF2_MCROSS) { P_ActivateLine(ld, thing, oldside, SPAC_MCROSS); } else if(thing->flags2&MF2_PCROSS) { P_ActivateLine(ld, thing, oldside, SPAC_PCROSS);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -