📄 p_enemy.c
字号:
// Emacs style mode select -*- C++ -*-//-----------------------------------------------------------------------------//// $Id: p_enemy.c,v 1.12 2001/04/04 20:24:21 judgecutor Exp $//// Copyright (C) 1993-1996 by id Software, Inc.// Portions Copyright (C) 1998-2000 by DooM Legacy Team.//// This program is free software; you can redistribute it and/or// modify it under the terms of the GNU General Public License// as published by the Free Software Foundation; either version 2// of the License, or (at your option) any later version.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.////// $Log: p_enemy.c,v $// Revision 1.12 2001/04/04 20:24:21 judgecutor// Added support for the 3D Sound//// Revision 1.11 2001/03/30 17:12:50 bpereira// no message//// Revision 1.10 2001/03/19 21:18:48 metzgermeister// * missing textures in HW mode are replaced by default texture// * fixed crash bug with P_SpawnMissile(.) returning NULL// * deep water trick and other nasty thing work now in HW mode (tested with tnt/map02 eternal/map02)// * added cvar gr_correcttricks//// Revision 1.9 2001/01/25 22:15:43 bpereira// added heretic support//// Revision 1.8 2000/10/21 08:43:30 bpereira// no message//// Revision 1.7 2000/10/08 13:30:01 bpereira// no message//// Revision 1.6 2000/10/01 10:18:17 bpereira// no message//// Revision 1.5 2000/04/30 10:30:10 bpereira// no message//// Revision 1.4 2000/04/11 19:07:24 stroggonmeth// Finished my logs, fixed a crashing bug.//// Revision 1.3 2000/04/04 00:32:46 stroggonmeth// Initial Boom compatability plus few misc changes all around.//// Revision 1.2 2000/02/27 00:42:10 hurdler// fix CR+LF problem//// Revision 1.1.1.1 2000/02/22 20:32:32 hurdler// Initial import into CVS (v1.29 pr3)////// DESCRIPTION:// Enemy thinking, AI.// Action Pointer Functions// that are associated with states/frames.////-----------------------------------------------------------------------------#include "doomdef.h"#include "g_game.h"#include "p_local.h"#include "r_main.h"#include "r_state.h"#include "s_sound.h"#include "m_random.h"#ifdef HW3SOUND#include "hardware/hw3sound.h"#endifvoid FastMonster_OnChange(void);// enable the solid corpses option : still not finishedconsvar_t cv_solidcorpse = {"solidcorpse","0",CV_NETVAR | CV_SAVE,CV_OnOff};consvar_t cv_fastmonsters = {"fastmonsters","0",CV_NETVAR | CV_CALL,CV_OnOff,FastMonster_OnChange};typedef enum{ DI_EAST, DI_NORTHEAST, DI_NORTH, DI_NORTHWEST, DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST, DI_NODIR, NUMDIRS} dirtype_t;//// P_NewChaseDir related LUT.//static dirtype_t opposite[] ={ DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST, DI_EAST, DI_NORTHEAST, DI_NORTH, DI_NORTHWEST, DI_NODIR};static dirtype_t diags[] ={ DI_NORTHWEST, DI_NORTHEAST, DI_SOUTHWEST, DI_SOUTHEAST};void A_Fall (mobj_t *actor);void FastMonster_OnChange(void){static boolean fast=false;static const struct { mobjtype_t type; int speed[2]; } MonsterMissileInfo[] = { // doom { MT_BRUISERSHOT, {15, 20}}, { MT_HEADSHOT, {10, 20}}, { MT_TROOPSHOT, {10, 20}}, // heretic { MT_IMPBALL, {10, 20}}, { MT_MUMMYFX1, { 9, 18}}, { MT_KNIGHTAXE, { 9, 18}}, { MT_REDAXE, { 9, 18}}, { MT_BEASTBALL, {12, 20}}, { MT_WIZFX1, {18, 24}}, { MT_SNAKEPRO_A, {14, 20}}, { MT_SNAKEPRO_B, {14, 20}}, { MT_HEADFX1, {13, 20}}, { MT_HEADFX3, {10, 18}}, { MT_MNTRFX1, {20, 26}}, { MT_MNTRFX2, {14, 20}}, { MT_SRCRFX1, {20, 28}}, { MT_SOR2FX1, {20, 28}}, { -1, {-1, -1} } // Terminator }; int i; if (cv_fastmonsters.value && !fast) { for (i=S_SARG_RUN1 ; i<=S_SARG_PAIN2 ; i++) states[i].tics >>= 1; fast=true; } else if(!cv_fastmonsters.value && fast) { for (i=S_SARG_RUN1 ; i<=S_SARG_PAIN2 ; i++) states[i].tics <<= 1; fast=false; } for(i = 0; MonsterMissileInfo[i].type != -1; i++) { mobjinfo[MonsterMissileInfo[i].type].speed = MonsterMissileInfo[i].speed[cv_fastmonsters.value]<<FRACBITS; }}//// ENEMY THINKING// Enemies are allways spawned// with targetplayer = -1, threshold = 0// Most monsters are spawned unaware of all players,// but some can be made preaware////// Called by P_NoiseAlert.// Recursively traverse adjacent sectors,// sound blocking lines cut off traversal.//static mobj_t* soundtarget;static 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) { return; // already flooded } 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) continue; // closed door 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); }}//// 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);}//// P_CheckMeleeRange//static boolean P_CheckMeleeRange (mobj_t* actor){ mobj_t* pl; fixed_t dist; if (!actor->target) return false; pl = actor->target; dist = P_AproxDistance (pl->x-actor->x, pl->y-actor->y); if (dist >= MELEERANGE-20*FRACUNIT+pl->info->radius) return false; //added:19-03-98: check height now, so that damn imps cant attack // you if you stand on a higher ledge. if ( demoversion>111 && ((pl->z > actor->z+actor->height) || (actor->z > pl->z + pl->height) )) return false; if (! P_CheckSight (actor, actor->target) ) return false; return true;}//// P_CheckMissileRange//static 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) return false; // do not attack yet // OPTIMIZE: get this from a global checksight dist = P_AproxDistance ( actor->x-actor->target->x, actor->y-actor->target->y) - 64*FRACUNIT; if (!actor->info->meleestate) dist -= 128*FRACUNIT; // no melee attack, so fire more dist >>= 16; if (actor->type == MT_VILE) { if (dist > 14*64) return false; // too far away } if (actor->type == MT_UNDEAD) { if (dist < 196) return false; // close for fist attack dist >>= 1; } if (actor->type == MT_CYBORG || actor->type == MT_SPIDER || actor->type == MT_SKULL || actor->type == MT_IMP) // heretic monster { dist >>= 1; } if (dist > 200) dist = 200; if (actor->type == MT_CYBORG && dist > 160) dist = 160; if (P_Random () < dist) return false; return true;}//// P_Move// Move in the current direction,// returns false if the move is blocked.//static const fixed_t xspeed[8] = {FRACUNIT,47000,0,-47000,-FRACUNIT,-47000,0,47000};static const fixed_t yspeed[8] = {0,47000,FRACUNIT,47000,0,-47000,-FRACUNIT,-47000};static boolean P_Move (mobj_t* actor){ fixed_t tryx; fixed_t tryy; line_t* ld; boolean good; if (actor->movedir == DI_NODIR) return false;#ifdef PARANOIA if ((unsigned)actor->movedir >= 8) I_Error ("Weird actor->movedir!");#endif tryx = actor->x + actor->info->speed*xspeed[actor->movedir]; tryy = actor->y + actor->info->speed*yspeed[actor->movedir]; if (!P_TryMove (actor, tryx, tryy, false)) { // 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 = lines + spechit[numspechit]; // if the special is not a door // that can be opened, // return false if (P_UseSpecialLine (actor, ld,0)) 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;}//// TryWalk// Attempts to move actor on// in its current (ob->moveangle) direction.// If blocked by either a wall or an actor// returns FALSE// If move is either clear or blocked only by a door,// returns TRUE and sets...// If a door is in the way,// an OpenDoor call is made to start it opening.//static boolean P_TryWalk (mobj_t* actor){ if (!P_Move (actor)) { return false; } actor->movecount = P_Random()&15; return true;}static void P_NewChaseDir (mobj_t* actor){ fixed_t deltax; fixed_t deltay; dirtype_t d[3]; int tdir; dirtype_t olddir; dirtype_t 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)) { // either moved forward or attacked return; } } 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; } // randomly determine direction of search if (P_Random()&1) { 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) )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -