⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 p_enemy.c

📁 PIXIL is a small footprint operating environment, complete with PDA PIM applications, a browser and
💻 C
📖 第 1 页 / 共 3 页
字号:
// Emacs style mode select   -*- C++ -*- //-----------------------------------------------------------------------------//// $Id: p_enemy.c,v 1.2 2003/09/08 22:34:29 jasonk Exp $//// Copyright (C) 1993-1996 by id Software, Inc.//// This source is available for distribution and/or modification// only under the terms of the DOOM Source Code License as// published by id Software. All rights reserved.//// The source is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License// for more details.//// $Log: p_enemy.c,v $// Revision 1.2  2003/09/08 22:34:29  jasonk// Updated files because this fucker won't build for no fucking good reason.//// Revision 1.1.1.1  2003/09/04 21:08:13  jasonk// Initial import//// Revision 1.1  2000/12/08 21:07:53  jeffw// nxdoom initial entry -- No nxdoom/Makefile so it won't build automatically////// DESCRIPTION://	Enemy thinking, AI.//	Action Pointer Functions//	that are associated with states/frames. ////-----------------------------------------------------------------------------static const charrcsid[] = "$Id: p_enemy.c,v 1.2 2003/09/08 22:34:29 jasonk Exp $";#include <stdlib.h>#include "m_random.h"#include "i_system.h"#include "doomdef.h"#include "p_local.h"#include "s_sound.h"#include "g_game.h"// State.#include "doomstat.h"#include "r_state.h"// Data.#include "sounds.h"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.//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 A_Fall (mobj_t *actor);//// 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.//mobj_t*		soundtarget;voidP_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.//voidP_NoiseAlert( mobj_t*	target,  mobj_t*	emmiter ){    soundtarget = target;    validcount++;    P_RecursiveSound (emmiter->subsector->sector, 0);}//// P_CheckMeleeRange//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;	    if (! P_CheckSight (actor, actor->target) )	return false;							    return true;		}//// 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)	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)    {	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.//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;    fixed_t	tryy;        line_t*	ld;        // warning: 'catch', 'throw', and 'try'    // are all C++ reserved words    boolean	try_ok;    boolean	good;		    if (actor->movedir == DI_NODIR)	return false;		    if ((unsigned)actor->movedir >= 8)	I_Error ("Weird actor->movedir!");		    tryx = actor->x + actor->info->speed*xspeed[actor->movedir];    tryy = actor->y + actor->info->speed*yspeed[actor->movedir];    try_ok = P_TryMove (actor, tryx, tryy);    if (!try_ok)    {	// 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 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) )		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.//boolean P_TryWalk (mobj_t* actor){	    if (!P_Move (actor))    {	return false;    }    actor->movecount = P_Random()&15;    return true;}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-1);	      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 not move}//// P_LookForPlayers// If allaround is false, only look 180 degrees in front.// Returns true if a player is targeted.//booleanP_LookForPlayers( mobj_t*	actor,  boolean	allaround ){    int		c;    int		stop;    player_t*	player;    sector_t*	sector;    angle_t	an;    fixed_t	dist;		    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)	{	    // done looking	    return false;		}		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	    }	}			actor->target = player->mo;	return true;    }    return false;}//// A_KeenDie// DOOM II special, map 32.// Uses special tag 666.//void A_KeenDie (mobj_t* mo){    thinker_t*	th;    mobj_t*	mo2;    line_t	junk;    A_Fall (mo);        // scan the remaining thinkers    // to see if all Keens are dead    for (th = thinkercap.next ; th != &thinkercap ; th=th->next)    {	if (th->function.acp1 != (actionf_p1)P_MobjThinker)	    continue;	mo2 = (mobj_t *)th;	if (mo2 != mo	    && mo2->type == mo->type	    && mo2->health > 0)	{	    // other Keen not dead	    return;			}    }    junk.tag = 666;    EV_DoDoor(&junk,open);}//// 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;		    // go into chase state  seeyou:    if (actor->info->seesound)    {	int		sound;			switch (actor->info->seesound)	{	  case sfx_posit1:	  case sfx_posit2:	  case sfx_posit3:	    sound = sfx_posit1+P_Random()%3;	    break;	  case sfx_bgsit1:	  case sfx_bgsit2:	    sound = sfx_bgsit1+P_Random()%2;	    break;	  default:	    sound = actor->info->seesound;	    break;	}	if (actor->type==MT_SPIDER	    || actor->type == MT_CYBORG)	{	    // full volume	    S_StartSound (NULL, sound);	}	else	    S_StartSound (actor, sound);    }    P_SetMobjState (actor, actor->info->seestate);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -