📄 p_map.c
字号:
//**************************************************************************//**//** p_map.c : Heretic 2 : Raven Software, Corp.//**//** $RCSfile: p_map.c,v $//** $Revision: 1.107 $//** $Date: 95/10/13 04:26:47 $//** $Author: paul $//**//**************************************************************************#include "h2def.h"#include "p_local.h"#include "soundst.h"static void CheckForPushSpecial(line_t *line, int side, mobj_t *mobj);/*===============================================================================NOTES:===============================================================================*//*===============================================================================mobj_t NOTESmobj_ts are used to tell the refresh where to draw an image, tell the world simulation when objects are contacted, and tell the sound driver how to position a sound.The refresh uses the next and prev links to follow lists of things in sectors as they are being drawn. The sprite, frame, and angle elements determine which patch_t is used to draw the sprite if it is visible. The sprite and frame values are allmost allways set from state_t structures. The statescr.exe utility generates the states.h and states.c files that contain the sprite/frame numbers from the statescr.txt source file. The xyz origin point represents a point at the bottom middle of the sprite (between the feet of a biped). This is the default origin position for patch_ts grabbed with lumpy.exe. A walking creature will have its z equal to the floor it is standing on.The sound code uses the x,y, and subsector fields to do stereo positioning of any sound effited by the mobj_t.The play simulation uses the blocklinks, x,y,z, radius, height to determine when mobj_ts are touching each other, touching lines in the map, or hit by trace lines (gunshots, lines of sight, etc). The mobj_t->flags element has various bit flags used by the simulation.Every mobj_t is linked into a single sector based on it's origin coordinates.The subsector_t is found with R_PointInSubsector(x,y), and the sector_t can be found with subsector->sector. The sector links are only used by the rendering code, the play simulation does not care about them at all.Any mobj_t that needs to be acted upon be something else in the play world (block movement, be shot, etc) will also need to be linked into the blockmap. If the thing has the MF_NOBLOCK flag set, it will not use the block links. It can still interact with other things, but only as the instigator (missiles will run into other things, but nothing can run into a missile). Each block in the grid is 128*128 units, and knows about every line_t that it contains a piece of, and every interactable mobj_t that has it's origin contained.A valid mobj_t is a mobj_t that has the proper subsector_t filled in for it's xy coordinates and is linked into the subsector's sector or has the MF_NOSECTOR flag set (the subsector_t needs to be valid even if MF_NOSECTOR is set), and is linked into a blockmap block or has the MF_NOBLOCKMAP flag set. Links should only be modified by the P_[Un]SetThingPosition () functions. Do not change the MF_NO? flags while a thing is valid.===============================================================================*/fixed_t tmbbox[4];mobj_t *tmthing;mobj_t *tsthing;int tmflags;fixed_t tmx, tmy;boolean floatok; // if true, move would be ok if // within tmfloorz - tmceilingzfixed_t tmfloorz, tmceilingz, tmdropoffz;int tmfloorpic;// keep track of the line that lowers the ceiling, so missiles don't explode// against sky hack wallsline_t *ceilingline;// keep track of special lines as they are hit, but don't process them// until the move is proven valid#define MAXSPECIALCROSS 8line_t *spechit[MAXSPECIALCROSS];int numspechit;mobj_t *onmobj; // generic global onmobj...used for landing on pods/playersmobj_t *BlockingMobj;/*=============================================================================== TELEPORT MOVE===============================================================================*//*==================== PIT_StompThing===================*/boolean PIT_StompThing (mobj_t *thing){ fixed_t blockdist; if (!(thing->flags & MF_SHOOTABLE) ) return true; blockdist = thing->radius + tmthing->radius; if ( abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist ) return true; // didn't hit it if (thing == tmthing) return true; // don't clip against self if(!(tmthing->flags2&MF2_TELESTOMP)) { // Not allowed to stomp things return(false); } P_DamageMobj (thing, tmthing, tmthing, 10000); return true;}/*===================== P_TeleportMove====================*/boolean P_TeleportMove (mobj_t *thing, fixed_t x, fixed_t y){ int xl,xh,yl,yh,bx,by; subsector_t *newsubsec;//// kill anything occupying the position// 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;//// stomp on any things contacted// 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_StompThing)) return false;//// the move is ok, so link the thing into its new position// P_UnsetThingPosition (thing); thing->floorz = tmfloorz; thing->ceilingz = tmceilingz; thing->x = x; thing->y = y; P_SetThingPosition (thing); return true;}boolean PIT_ThrustStompThing (mobj_t *thing){ fixed_t blockdist; if (!(thing->flags & MF_SHOOTABLE) ) return true; blockdist = thing->radius + tsthing->radius; if ( abs(thing->x - tsthing->x) >= blockdist || abs(thing->y - tsthing->y) >= blockdist || (thing->z > tsthing->z+tsthing->height) ) return true; // didn't hit it if (thing == tsthing) return true; // don't clip against self P_DamageMobj (thing, tsthing, tsthing, 10001); tsthing->args[1] = 1; // Mark thrust thing as bloody return true;}void PIT_ThrustSpike(mobj_t *actor){ int xl,xh,yl,yh,bx,by; int x0,x2,y0,y2; tsthing = actor; x0 = actor->x - actor->info->radius; x2 = actor->x + actor->info->radius; y0 = actor->y - actor->info->radius; y2 = actor->y + actor->info->radius; xl = (x0 - bmaporgx - MAXRADIUS)>>MAPBLOCKSHIFT; xh = (x2 - bmaporgx + MAXRADIUS)>>MAPBLOCKSHIFT; yl = (y0 - bmaporgy - MAXRADIUS)>>MAPBLOCKSHIFT; yh = (y2 - bmaporgy + MAXRADIUS)>>MAPBLOCKSHIFT; // stomp on any things contacted for (bx=xl ; bx<=xh ; bx++) for (by=yl ; by<=yh ; by++) P_BlockThingsIterator(bx,by,PIT_ThrustStompThing);}/*=============================================================================== MOVEMENT ITERATOR FUNCTIONS===============================================================================*//*==================== PIT_CheckLine== Adjusts tmfloorz and tmceilingz as lines are contacted==================*/boolean PIT_CheckLine(line_t *ld){ if (tmbbox[BOXRIGHT] <= ld->bbox[BOXLEFT] || tmbbox[BOXLEFT] >= ld->bbox[BOXRIGHT] || tmbbox[BOXTOP] <= ld->bbox[BOXBOTTOM] || tmbbox[BOXBOTTOM] >= ld->bbox[BOXTOP]) { return(true); } if(P_BoxOnLineSide(tmbbox, ld) != -1) { return(true); }// a line has been hit/*== The moving thing's destination position will cross the given line.= If this should not be allowed, return false.= If the line is special, keep track of it to process later if the move= is proven ok. NOTE: specials are NOT sorted by order, so two special lines= that are only 8 pixels apart could be crossed in either order.*/ if(!ld->backsector) { // One sided line if (tmthing->flags2&MF2_BLASTED) { P_DamageMobj(tmthing, NULL, NULL, tmthing->info->mass>>5); } CheckForPushSpecial(ld, 0, tmthing); return(false); } if(!(tmthing->flags&MF_MISSILE)) { if(ld->flags&ML_BLOCKING) { // Explicitly blocking everything if (tmthing->flags2&MF2_BLASTED) { P_DamageMobj(tmthing, NULL, NULL, tmthing->info->mass>>5); } CheckForPushSpecial(ld, 0, tmthing); return(false); } if(!tmthing->player && ld->flags&ML_BLOCKMONSTERS) { // Block monsters only if (tmthing->flags2&MF2_BLASTED) { P_DamageMobj(tmthing, NULL, NULL, tmthing->info->mass>>5); } return(false); } } P_LineOpening(ld); // set openrange, opentop, openbottom // adjust floor / ceiling heights if(opentop < tmceilingz) { tmceilingz = opentop; ceilingline = ld; } if(openbottom > tmfloorz) { tmfloorz = openbottom; } if(lowfloor < tmdropoffz) { tmdropoffz = lowfloor; } if(ld->special) { // Contacted a special line, add it to the list spechit[numspechit] = ld; numspechit++; } return(true);}//---------------------------------------------------------------------------//// FUNC PIT_CheckThing////---------------------------------------------------------------------------boolean PIT_CheckThing(mobj_t *thing){ fixed_t blockdist; boolean solid; int damage; 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); } BlockingMobj = thing; if(tmthing->flags2&MF2_PASSMOBJ) { // check if a mobj passed over/under another object if(tmthing->type == MT_BISHOP && thing->type == MT_BISHOP) { // don't let bishops fly over other bishops return false; } if(tmthing->z >= thing->z+thing->height && !(thing->flags&MF_SPECIAL)) { return(true); } else if(tmthing->z+tmthing->height < thing->z && !(thing->flags&MF_SPECIAL)) { // under thing return(true); } } // Check for skulls slamming into things if(tmthing->flags&MF_SKULLFLY) { if(tmthing->type == MT_MINOTAUR) { // Slamming minotaurs shouldn't move non-creatures if (!(thing->flags&MF_COUNTKILL)) { return(false); } } else if(tmthing->type == MT_HOLY_FX) { if(thing->flags&MF_SHOOTABLE && thing != tmthing->target) { if(netgame && !deathmatch && thing->player) { // don't attack other co-op players return true; } if(thing->flags2&MF2_REFLECTIVE && (thing->player || thing->flags2&MF2_BOSS)) { tmthing->special1 = (int)tmthing->target; tmthing->target = thing; return true; } if(thing->flags&MF_COUNTKILL || thing->player) { tmthing->special1 = (int)thing; } if(P_Random() < 96) { damage = 12; if(thing->player || thing->flags2&MF2_BOSS) { damage = 3; // ghost burns out faster when attacking players/bosses tmthing->health -= 6; } P_DamageMobj(thing, tmthing, tmthing->target, damage); if(P_Random() < 128) { P_SpawnMobj(tmthing->x, tmthing->y, tmthing->z, MT_HOLY_PUFF); S_StartSound(tmthing, SFX_SPIRIT_ATTACK); if(thing->flags&MF_COUNTKILL && P_Random() < 128 && !S_GetSoundPlayingInfo(thing, SFX_PUPPYBEAT)) { if ((thing->type == MT_CENTAUR) || (thing->type == MT_CENTAURLEADER) || (thing->type == MT_ETTIN)) { S_StartSound(thing, SFX_PUPPYBEAT); } } } } if(thing->health <= 0) { tmthing->special1 = 0; } } return true; } damage = ((P_Random()%8)+1)*tmthing->damage; P_DamageMobj(thing, tmthing, tmthing, damage); tmthing->flags &= ~MF_SKULLFLY; tmthing->momx = tmthing->momy = tmthing->momz = 0; P_SetMobjState(tmthing, tmthing->info->seestate); return(false); } // Check for blasted thing running into another if(tmthing->flags2&MF2_BLASTED && thing->flags&MF_SHOOTABLE) { if (!(thing->flags2&MF2_BOSS) && (thing->flags&MF_COUNTKILL)) { thing->momx += tmthing->momx; thing->momy += tmthing->momy; if ((thing->momx + thing->momy) > 3*FRACUNIT) { damage = (tmthing->info->mass/100)+1; P_DamageMobj(thing, tmthing, tmthing, damage); damage = (thing->info->mass/100)+1; P_DamageMobj(tmthing, thing, thing, damage>>2); } return(false); } } // Check for missile if(tmthing->flags&MF_MISSILE) { // Check for a non-shootable mobj if(thing->flags2&MF2_NONSHOOTABLE) { return true; } // Check if it went over / under if(tmthing->z > thing->z+thing->height) { // Over thing return(true); } if(tmthing->z+tmthing->height < thing->z) { // Under thing return(true); } if(tmthing->flags2&MF2_FLOORBOUNCE) { if(tmthing->target == thing || !(thing->flags&MF_SOLID)) { return true; } else { return false; } } if(tmthing->type == MT_LIGHTNING_FLOOR || tmthing->type == MT_LIGHTNING_CEILING) { if(thing->flags&MF_SHOOTABLE && thing != tmthing->target) { if(thing->info->mass != MAXINT) { thing->momx += tmthing->momx>>4; thing->momy += tmthing->momy>>4; } if((!thing->player && !(thing->flags2&MF2_BOSS)) || !(leveltime&1)) { if(thing->type == MT_CENTAUR || thing->type == MT_CENTAURLEADER) { // Lightning does more damage to centaurs P_DamageMobj(thing, tmthing, tmthing->target, 9); } else { P_DamageMobj(thing, tmthing, tmthing->target, 3); } if(!(S_GetSoundPlayingInfo(tmthing, SFX_MAGE_LIGHTNING_ZAP))) { S_StartSound(tmthing, SFX_MAGE_LIGHTNING_ZAP); } if(thing->flags&MF_COUNTKILL && P_Random() < 64 && !S_GetSoundPlayingInfo(thing, SFX_PUPPYBEAT)) { if ((thing->type == MT_CENTAUR) || (thing->type == MT_CENTAURLEADER) || (thing->type == MT_ETTIN)) { S_StartSound(thing, SFX_PUPPYBEAT); } } } tmthing->health--; if(tmthing->health <= 0 || thing->health <= 0) { return false; } if(tmthing->type == MT_LIGHTNING_FLOOR) { if(tmthing->special2 && !((mobj_t *)tmthing->special2)->special1) { ((mobj_t *)tmthing->special2)->special1 = (int)thing; } } else if(!tmthing->special1) { tmthing->special1 = (int)thing; } } return true; // lightning zaps through all sprites } else if(tmthing->type == MT_LIGHTNING_ZAP) { mobj_t *lmo; if(thing->flags&MF_SHOOTABLE && thing != tmthing->target) { lmo = (mobj_t *)tmthing->special2; if(lmo) { if(lmo->type == MT_LIGHTNING_FLOOR) { if(lmo->special2 && !((mobj_t *)lmo->special2)->special1) { ((mobj_t *)lmo->special2)->special1 = (int)thing; } } else if(!lmo->special1) { lmo->special1 = (int)thing; } if(!(leveltime&3)) { lmo->health--; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -