📄 p_enemy.c
字号:
//**************************************************************************//**//** p_enemy.c : Heretic 2 : Raven Software, Corp.//**//** $RCSfile: p_enemy.c,v $//** $Revision: 1.170 $//** $Date: 96/01/06 03:23:28 $//** $Author: bgokey $//**//**************************************************************************#include "h2def.h"#include "p_local.h"#include "soundst.h"// Macros// Types// Private Data// External Dataextern fixed_t FloatBobOffsets[64];//----------------------------------------------------------------------------//// PROC P_RecursiveSound////----------------------------------------------------------------------------mobj_t *soundtarget;void P_RecursiveSound(sector_t *sec, int soundblocks){ int i; line_t *check; sector_t *other; // Wake up all monsters in this sector if(sec->validcount == validcount && sec->soundtraversed <= soundblocks+1) { // Already flooded return; } sec->validcount = validcount; sec->soundtraversed = soundblocks+1; sec->soundtarget = soundtarget; for(i = 0; i < sec->linecount; i++) { check = sec->lines[i]; if(!(check->flags&ML_TWOSIDED)) { continue; } P_LineOpening(check); if(openrange <= 0) { // Closed door continue; } if(sides[check->sidenum[0]].sector == sec) { other = sides[check->sidenum[1]].sector; } else { other = sides[check->sidenum[0]].sector; } if(check->flags&ML_SOUNDBLOCK) { if(!soundblocks) { P_RecursiveSound(other, 1); } } else { P_RecursiveSound(other, soundblocks); } }}//----------------------------------------------------------------------------//// PROC P_NoiseAlert//// If a monster yells at a player, it will alert other monsters to the// player.////----------------------------------------------------------------------------void P_NoiseAlert(mobj_t *target, mobj_t *emmiter){ soundtarget = target; validcount++; P_RecursiveSound(emmiter->subsector->sector, 0);}//----------------------------------------------------------------------------//// FUNC P_CheckMeleeRange////----------------------------------------------------------------------------boolean P_CheckMeleeRange(mobj_t *actor){ mobj_t *mo; fixed_t dist; if(!actor->target) { return(false); } mo = actor->target; dist = P_AproxDistance(mo->x-actor->x, mo->y-actor->y); if(dist >= MELEERANGE) { return(false); } if(!P_CheckSight(actor, mo)) { return(false); } if(mo->z > actor->z+actor->height) { // Target is higher than the attacker return(false); } else if(actor->z > mo->z+mo->height) { // Attacker is higher return(false); } return(true);}//----------------------------------------------------------------------------//// FUNC P_CheckMeleeRange2////----------------------------------------------------------------------------boolean P_CheckMeleeRange2(mobj_t *actor){ mobj_t *mo; fixed_t dist; if(!actor->target) { return(false); } mo = actor->target; dist = P_AproxDistance(mo->x-actor->x, mo->y-actor->y); if(dist >= MELEERANGE*2 || dist < MELEERANGE) { return(false); } if(!P_CheckSight(actor, mo)) { return(false); } if(mo->z > actor->z+actor->height) { // Target is higher than the attacker return(false); } else if(actor->z > mo->z+mo->height) { // Attacker is higher return(false); } return(true);}//----------------------------------------------------------------------------//// FUNC P_CheckMissileRange////----------------------------------------------------------------------------boolean P_CheckMissileRange(mobj_t *actor){ fixed_t dist; if(!P_CheckSight(actor, actor->target)) { return(false); } if(actor->flags&MF_JUSTHIT) { // The target just hit the enemy, so fight back! actor->flags &= ~MF_JUSTHIT; return(true); } if(actor->reactiontime) { // Don't attack yet return(false); } dist = (P_AproxDistance(actor->x-actor->target->x, actor->y-actor->target->y)>>FRACBITS)-64; if(!actor->info->meleestate) { // No melee attack, so fire more frequently dist -= 128; } if(dist > 200) { dist = 200; } if(P_Random() < dist) { return(false); } return(true);}/*================== P_Move== Move in the current direction= returns false if the move is blocked================*/fixed_t xspeed[8] = {FRACUNIT,47000,0,-47000,-FRACUNIT,-47000,0,47000};fixed_t yspeed[8] = {0,47000,FRACUNIT,47000,0,-47000,-FRACUNIT,-47000};#define MAXSPECIALCROSS 8extern line_t *spechit[MAXSPECIALCROSS];extern int numspechit;boolean P_Move(mobj_t *actor){ fixed_t tryx, tryy; line_t *ld; boolean good; if(actor->flags2&MF2_BLASTED) return(true); if(actor->movedir == DI_NODIR) { return(false); } tryx = actor->x+actor->info->speed*xspeed[actor->movedir]; tryy = actor->y+actor->info->speed*yspeed[actor->movedir]; if(!P_TryMove(actor, tryx, tryy)) { // open any specials if(actor->flags&MF_FLOAT && floatok) { // must adjust height if(actor->z < tmfloorz) { actor->z += FLOATSPEED; } else { actor->z -= FLOATSPEED; } actor->flags |= MF_INFLOAT; return(true); } if(!numspechit) { return false; } actor->movedir = DI_NODIR; good = false; while(numspechit--) { ld = spechit[numspechit]; // if the special isn't a door that can be opened, return false if(P_ActivateLine(ld, actor, 0, SPAC_USE)) { good = true; }/* Old version before use/cross/impact specials were combined if(P_UseSpecialLine(actor, ld)) { good = true; }*/ } return(good); } else { actor->flags &= ~MF_INFLOAT; } if(!(actor->flags&MF_FLOAT)) { if(actor->z > actor->floorz) { P_HitFloor(actor); } actor->z = actor->floorz; } return(true);}//----------------------------------------------------------------------------//// FUNC P_TryWalk//// Attempts to move actor in its current (ob->moveangle) direction.// If blocked by either a wall or an actor returns FALSE.// If move is either clear of block only by a door, returns TRUE and sets.// If a door is in the way, an OpenDoor call is made to start it opening.////----------------------------------------------------------------------------boolean P_TryWalk(mobj_t *actor){ if(!P_Move(actor)) { return(false); } actor->movecount = P_Random()&15; return(true);}/*================== P_NewChaseDir=================*/dirtype_t opposite[] ={DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST, DI_EAST, DI_NORTHEAST,DI_NORTH, DI_NORTHWEST, DI_NODIR};dirtype_t diags[] = {DI_NORTHWEST,DI_NORTHEAST,DI_SOUTHWEST,DI_SOUTHEAST};void P_NewChaseDir (mobj_t *actor){ fixed_t deltax,deltay; dirtype_t d[3]; dirtype_t tdir, olddir, turnaround; if (!actor->target) I_Error ("P_NewChaseDir: called with no target"); olddir = actor->movedir; turnaround=opposite[olddir]; deltax = actor->target->x - actor->x; deltay = actor->target->y - actor->y; if (deltax>10*FRACUNIT) d[1]= DI_EAST; else if (deltax<-10*FRACUNIT) d[1]= DI_WEST; else d[1]=DI_NODIR; if (deltay<-10*FRACUNIT) d[2]= DI_SOUTH; else if (deltay>10*FRACUNIT) d[2]= DI_NORTH; else d[2]=DI_NODIR;// try direct route if (d[1] != DI_NODIR && d[2] != DI_NODIR) { actor->movedir = diags[((deltay<0)<<1)+(deltax>0)]; if (actor->movedir != turnaround && P_TryWalk(actor)) return; }// try other directions if (P_Random() > 200 || abs(deltay)>abs(deltax)) { tdir=d[1]; d[1]=d[2]; d[2]=tdir; } if (d[1]==turnaround) d[1]=DI_NODIR; if (d[2]==turnaround) d[2]=DI_NODIR; if (d[1]!=DI_NODIR) { actor->movedir = d[1]; if (P_TryWalk(actor)) return; /*either moved forward or attacked*/ } if (d[2]!=DI_NODIR) { actor->movedir =d[2]; if (P_TryWalk(actor)) return; }/* there is no direct path to the player, so pick another direction */ if (olddir!=DI_NODIR) { actor->movedir =olddir; if (P_TryWalk(actor)) return; } if (P_Random()&1) /*randomly determine direction of search*/ { for (tdir=DI_EAST ; tdir<=DI_SOUTHEAST ; tdir++) { if (tdir!=turnaround) { actor->movedir =tdir; if ( P_TryWalk(actor) ) return; } } } else { for (tdir=DI_SOUTHEAST ; tdir >= DI_EAST;tdir--) { if (tdir!=turnaround) { actor->movedir =tdir; if ( P_TryWalk(actor) ) return; } } } if (turnaround != DI_NODIR) { actor->movedir =turnaround; if ( P_TryWalk(actor) ) return; } actor->movedir = DI_NODIR; // can't move}//---------------------------------------------------------------------------//// FUNC P_LookForMonsters////---------------------------------------------------------------------------#define MONS_LOOK_RANGE (16*64*FRACUNIT)#define MONS_LOOK_LIMIT 64boolean P_LookForMonsters(mobj_t *actor){ int count; mobj_t *mo; thinker_t *think; if(!P_CheckSight(players[0].mo, actor)) { // Player can't see monster return(false); } count = 0; for(think = thinkercap.next; think != &thinkercap; think = think->next) { if(think->function != P_MobjThinker) { // Not a mobj thinker continue; } mo = (mobj_t *)think; if(!(mo->flags&MF_COUNTKILL) || (mo == actor) || (mo->health <= 0)) { // Not a valid monster continue; } if(P_AproxDistance(actor->x-mo->x, actor->y-mo->y) > MONS_LOOK_RANGE) { // Out of range continue; } if(P_Random() < 16) { // Skip continue; } if(count++ > MONS_LOOK_LIMIT) { // Stop searching return(false); } if(!P_CheckSight(actor, mo)) { // Out of sight continue; } if (actor->type == MT_MINOTAUR) { if ((mo->type == MT_MINOTAUR) && (mo->target != ((player_t *)actor->special1)->mo)) { continue; } } // Found a target monster actor->target = mo; return(true); } return(false);}/*================== P_LookForPlayers== If allaround is false, only look 180 degrees in front= returns true if a player is targeted================*/boolean P_LookForPlayers(mobj_t *actor, boolean allaround){ int c; int stop; player_t *player; sector_t *sector; angle_t an; fixed_t dist; if(!netgame && players[0].health <= 0) { // Single player game and player is dead, look for monsters return(P_LookForMonsters(actor)); } sector = actor->subsector->sector; c = 0; stop = (actor->lastlook-1)&3; for( ; ; actor->lastlook = (actor->lastlook+1)&3 ) { if (!playeringame[actor->lastlook]) continue; if (c++ == 2 || actor->lastlook == stop) return false; // done looking player = &players[actor->lastlook]; if (player->health <= 0) continue; // dead if (!P_CheckSight (actor, player->mo)) continue; // out of sight if (!allaround) { an = R_PointToAngle2 (actor->x, actor->y, player->mo->x, player->mo->y) - actor->angle; if (an > ANG90 && an < ANG270) { dist = P_AproxDistance (player->mo->x - actor->x, player->mo->y - actor->y); // if real close, react anyway if (dist > MELEERANGE) continue; // behind back } } if(player->mo->flags&MF_SHADOW) { // Player is invisible if((P_AproxDistance(player->mo->x-actor->x, player->mo->y-actor->y) > 2*MELEERANGE) && P_AproxDistance(player->mo->momx, player->mo->momy) < 5*FRACUNIT) { // Player is sneaking - can't detect return(false); } if(P_Random() < 225) { // Player isn't sneaking, but still didn't detect return(false); } } if (actor->type == MT_MINOTAUR) { if(((player_t *)(actor->special1)) == player) { continue; // Don't target master } } actor->target = player->mo; return(true); } return(false);}/*=============================================================================== ACTION ROUTINES===============================================================================*//*================ A_Look== Stay in state until a player is sighted===============*/void A_Look (mobj_t *actor){ mobj_t *targ; actor->threshold = 0; // any shot will wake up targ = actor->subsector->sector->soundtarget; if (targ && (targ->flags & MF_SHOOTABLE) ) { actor->target = targ; if ( actor->flags & MF_AMBUSH ) { if (P_CheckSight (actor, actor->target)) goto seeyou; } else goto seeyou; } if (!P_LookForPlayers (actor, false) ) return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -