mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-28 06:53:58 +00:00
- Added some pieces of MBF's friendly AI.
- Cleaned up A_LookEx code and merged most of it with the base functions. The major difference was a common piece of code that was repeated 5 times throughout the code so I moved it into a subfunction. - Changed P_BlockmapSearch to pass a user parameter to its callback so that A_LookEx does not need to store its info inside the actor itself. SVN r1846 (trunk)
This commit is contained in:
parent
c7a6b796f9
commit
dc292caaa3
15 changed files with 825 additions and 1417 deletions
|
@ -1,4 +1,10 @@
|
||||||
September 16, 2009 (Changes by Graf Zahl)
|
September 16, 2009 (Changes by Graf Zahl)
|
||||||
|
- Added some pieces of MBF's friendly AI.
|
||||||
|
- Cleaned up A_LookEx code and merged most of it with the base functions.
|
||||||
|
The major difference was a common piece of code that was repeated 5 times
|
||||||
|
throughout the code so I moved it into a subfunction.
|
||||||
|
- Changed P_BlockmapSearch to pass a user parameter to its callback so that
|
||||||
|
A_LookEx does not need to store its info inside the actor itself.
|
||||||
- fixed: The linetarget CCMD duplicated all of the info CCMD.
|
- fixed: The linetarget CCMD duplicated all of the info CCMD.
|
||||||
- fixed: PrintActorInfo crashed due to some incomplete implementation.
|
- fixed: PrintActorInfo crashed due to some incomplete implementation.
|
||||||
|
|
||||||
|
|
|
@ -589,7 +589,6 @@ add_executable( zdoom WIN32
|
||||||
p_doors.cpp
|
p_doors.cpp
|
||||||
p_effect.cpp
|
p_effect.cpp
|
||||||
p_enemy.cpp
|
p_enemy.cpp
|
||||||
p_enemy_a_lookex.cpp
|
|
||||||
p_floor.cpp
|
p_floor.cpp
|
||||||
p_interaction.cpp
|
p_interaction.cpp
|
||||||
p_lights.cpp
|
p_lights.cpp
|
||||||
|
|
10
src/actor.h
10
src/actor.h
|
@ -216,7 +216,7 @@ enum
|
||||||
MF3_NOBLOCKMONST = 0x00100000, // Can cross ML_BLOCKMONSTERS lines
|
MF3_NOBLOCKMONST = 0x00100000, // Can cross ML_BLOCKMONSTERS lines
|
||||||
MF3_CRASHED = 0x00200000, // Actor entered its crash state
|
MF3_CRASHED = 0x00200000, // Actor entered its crash state
|
||||||
MF3_FULLVOLDEATH = 0x00400000, // DeathSound is played full volume (for missiles)
|
MF3_FULLVOLDEATH = 0x00400000, // DeathSound is played full volume (for missiles)
|
||||||
/* = 0x00800000, */
|
MF3_AVOIDMELEE = 0x00800000, // Avoids melee attacks (same as MBF's monster_backing but must be explicitly set)
|
||||||
/* = 0x01000000, */
|
/* = 0x01000000, */
|
||||||
MF3_FOILINVUL = 0x02000000, // Actor can hurt MF2_INVULNERABLE things
|
MF3_FOILINVUL = 0x02000000, // Actor can hurt MF2_INVULNERABLE things
|
||||||
MF3_NOTELEOTHER = 0x04000000, // Monster is unaffected by teleport other artifact
|
MF3_NOTELEOTHER = 0x04000000, // Monster is unaffected by teleport other artifact
|
||||||
|
@ -810,14 +810,6 @@ public:
|
||||||
AActor *BlockingMobj; // Actor that blocked the last move
|
AActor *BlockingMobj; // Actor that blocked the last move
|
||||||
line_t *BlockingLine; // Line that blocked the last move
|
line_t *BlockingLine; // Line that blocked the last move
|
||||||
|
|
||||||
// [KS] These temporary-use properties are needed to allow A_LookEx to pass its parameters to
|
|
||||||
// LookFor*InBlock in P_BlockmapSearch so that friendly enemies and monsters that look for
|
|
||||||
// other monsters can find their targets properly. If there's a cleaner way of doing this,
|
|
||||||
// feel free to remove these and use that method instead.
|
|
||||||
fixed_t LookExMinDist; // Minimum sight distance
|
|
||||||
fixed_t LookExMaxDist; // Maximum sight distance
|
|
||||||
angle_t LookExFOV; // Field of Vision
|
|
||||||
|
|
||||||
// a linked list of sectors where this object appears
|
// a linked list of sectors where this object appears
|
||||||
struct msecnode_t *touching_sectorlist; // phares 3/14/98
|
struct msecnode_t *touching_sectorlist; // phares 3/14/98
|
||||||
|
|
||||||
|
|
|
@ -238,7 +238,7 @@ static void SpawnFly(AActor *self, const PClass *spawntype, FSoundID sound)
|
||||||
{
|
{
|
||||||
newmobj->CopyFriendliness (eye, false);
|
newmobj->CopyFriendliness (eye, false);
|
||||||
}
|
}
|
||||||
if (newmobj->SeeState != NULL && P_LookForPlayers (newmobj, true))
|
if (newmobj->SeeState != NULL && P_LookForPlayers (newmobj, true, NULL))
|
||||||
newmobj->SetState (newmobj->SeeState);
|
newmobj->SetState (newmobj->SeeState);
|
||||||
|
|
||||||
if (!(newmobj->ObjectFlags & OF_EuthanizeMe))
|
if (!(newmobj->ObjectFlags & OF_EuthanizeMe))
|
||||||
|
|
|
@ -168,7 +168,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_Refire)
|
||||||
{
|
{
|
||||||
if (self->MissileState && pr_m_refire() < 160)
|
if (self->MissileState && pr_m_refire() < 160)
|
||||||
{ // Look for a new target most of the time
|
{ // Look for a new target most of the time
|
||||||
if (P_LookForPlayers (self, true) && P_CheckMissileRange (self))
|
if (P_LookForPlayers (self, true, NULL) && P_CheckMissileRange (self))
|
||||||
{ // Found somebody new and in range, so don't stop shooting
|
{ // Found somebody new and in range, so don't stop shooting
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -213,7 +213,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DragonFlight)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
P_LookForPlayers (self, true);
|
P_LookForPlayers (self, true, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -145,7 +145,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FiredChase)
|
||||||
|
|
||||||
if(!self->target || !(self->target->flags&MF_SHOOTABLE))
|
if(!self->target || !(self->target->flags&MF_SHOOTABLE))
|
||||||
{ // Invalid target
|
{ // Invalid target
|
||||||
P_LookForPlayers (self,true);
|
P_LookForPlayers (self,true, NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ void A_DropBloodscourgePieces (AActor *);
|
||||||
void A_MStaffAttack (AActor *actor);
|
void A_MStaffAttack (AActor *actor);
|
||||||
void A_MStaffPalette (AActor *actor);
|
void A_MStaffPalette (AActor *actor);
|
||||||
|
|
||||||
static AActor *FrontBlockCheck (AActor *mo, int index);
|
static AActor *FrontBlockCheck (AActor *mo, int index, void *);
|
||||||
static divline_t BlockCheckLine;
|
static divline_t BlockCheckLine;
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -254,7 +254,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MStaffTrack)
|
||||||
//
|
//
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
static AActor *FrontBlockCheck (AActor *mo, int index)
|
static AActor *FrontBlockCheck (AActor *mo, int index, void *)
|
||||||
{
|
{
|
||||||
FBlockNode *link;
|
FBlockNode *link;
|
||||||
|
|
||||||
|
|
496
src/p_enemy.cpp
496
src/p_enemy.cpp
|
@ -62,6 +62,7 @@ static FRandom pr_look2 ("LookyLooky");
|
||||||
static FRandom pr_look3 ("IGotHooky");
|
static FRandom pr_look3 ("IGotHooky");
|
||||||
static FRandom pr_slook ("SlooK");
|
static FRandom pr_slook ("SlooK");
|
||||||
static FRandom pr_dropoff ("Dropoff");
|
static FRandom pr_dropoff ("Dropoff");
|
||||||
|
static FRandom pr_defect ("Defect");
|
||||||
|
|
||||||
static FRandom pr_skiptarget("SkipTarget");
|
static FRandom pr_skiptarget("SkipTarget");
|
||||||
|
|
||||||
|
@ -219,20 +220,20 @@ void P_NoiseAlert (AActor *target, AActor *emmiter, bool splash)
|
||||||
|
|
||||||
bool AActor::CheckMeleeRange ()
|
bool AActor::CheckMeleeRange ()
|
||||||
{
|
{
|
||||||
AActor *pl;
|
AActor *pl = target;
|
||||||
|
|
||||||
fixed_t dist;
|
fixed_t dist;
|
||||||
|
|
||||||
if (!target)
|
if (!pl)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
pl = target;
|
|
||||||
dist = P_AproxDistance (pl->x - x, pl->y - y);
|
dist = P_AproxDistance (pl->x - x, pl->y - y);
|
||||||
|
|
||||||
if (dist >= meleerange + pl->radius)
|
if (dist >= meleerange + pl->radius)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// [RH] If moving toward goal, then we've reached it.
|
// [RH] If moving toward goal, then we've reached it.
|
||||||
if (target == goal)
|
if (pl == goal)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// [RH] Don't melee things too far above or below actor.
|
// [RH] Don't melee things too far above or below actor.
|
||||||
|
@ -244,6 +245,10 @@ bool AActor::CheckMeleeRange ()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// killough 7/18/98: friendly monsters don't attack other friends
|
||||||
|
if (IsFriend(pl))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (!P_CheckSight (this, pl, 0))
|
if (!P_CheckSight (this, pl, 0))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -279,6 +284,12 @@ bool P_CheckMeleeRange2 (AActor *actor)
|
||||||
{ // Attacker is higher
|
{ // Attacker is higher
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
else if (actor->IsFriend(mo))
|
||||||
|
{
|
||||||
|
// killough 7/18/98: friendly monsters don't attack other friends
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!P_CheckSight(actor, mo))
|
if (!P_CheckSight(actor, mo))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -303,12 +314,34 @@ bool P_CheckMissileRange (AActor *actor)
|
||||||
{
|
{
|
||||||
// the target just hit the enemy, so fight back!
|
// the target just hit the enemy, so fight back!
|
||||||
actor->flags &= ~MF_JUSTHIT;
|
actor->flags &= ~MF_JUSTHIT;
|
||||||
return true;
|
|
||||||
|
// killough 7/18/98: no friendly fire at corpses
|
||||||
|
// killough 11/98: prevent too much infighting among friends
|
||||||
|
// Cleaned up and made readable
|
||||||
|
if (!(actor->flags & MF_FRIENDLY)) return true;
|
||||||
|
if (actor->target->health <= 0) return false;
|
||||||
|
if (!actor->IsFriend(actor->target)) return true;
|
||||||
|
if (actor->target->player != NULL)
|
||||||
|
{
|
||||||
|
return (pr_defect() >128);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return !(actor->target->flags & MF_JUSTHIT) && pr_defect() >128;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (actor->reactiontime)
|
if (actor->reactiontime)
|
||||||
return false; // do not attack yet
|
return false; // do not attack yet
|
||||||
|
|
||||||
|
// killough 7/18/98: friendly monsters don't attack other friendly
|
||||||
|
// monsters or players (except when attacked, and then only once)
|
||||||
|
if (actor->IsFriend(actor->target))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (actor->flags & MF_FRIENDLY && P_HitFriend(actor))
|
||||||
|
return false;
|
||||||
|
|
||||||
// OPTIMIZE: get this from a global checksight
|
// OPTIMIZE: get this from a global checksight
|
||||||
// [RH] What?
|
// [RH] What?
|
||||||
dist = P_AproxDistance (actor->x-actor->target->x,
|
dist = P_AproxDistance (actor->x-actor->target->x,
|
||||||
|
@ -357,7 +390,7 @@ bool P_HitFriend(AActor * self)
|
||||||
if (self->flags&MF_FRIENDLY && self->target != NULL)
|
if (self->flags&MF_FRIENDLY && self->target != NULL)
|
||||||
{
|
{
|
||||||
angle_t angle = R_PointToAngle2 (self->x, self->y, self->target->x, self->target->y);
|
angle_t angle = R_PointToAngle2 (self->x, self->y, self->target->x, self->target->y);
|
||||||
fixed_t dist = P_AproxDistance (self->x-self->target->x, self->y-self->target->y);
|
fixed_t dist = P_AproxDistance (self->x - self->target->x, self->y - self->target->y);
|
||||||
P_AimLineAttack (self, angle, dist, &linetarget, 0, true);
|
P_AimLineAttack (self, angle, dist, &linetarget, 0, true);
|
||||||
if (linetarget != NULL && linetarget != self->target)
|
if (linetarget != NULL && linetarget != self->target)
|
||||||
{
|
{
|
||||||
|
@ -739,6 +772,10 @@ void P_NewChaseDir(AActor * actor)
|
||||||
fixed_t deltax;
|
fixed_t deltax;
|
||||||
fixed_t deltay;
|
fixed_t deltay;
|
||||||
|
|
||||||
|
#ifdef MBF_STUFF
|
||||||
|
actor->strafecount = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
if ((actor->flags5&MF5_CHASEGOAL || actor->goal == actor->target) && actor->goal!=NULL)
|
if ((actor->flags5&MF5_CHASEGOAL || actor->goal == actor->target) && actor->goal!=NULL)
|
||||||
{
|
{
|
||||||
deltax = actor->goal->x - actor->x;
|
deltax = actor->goal->x - actor->x;
|
||||||
|
@ -831,7 +868,59 @@ void P_NewChaseDir(AActor * actor)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// Move away from friends when too close, except
|
||||||
|
// in certain situations (e.g. a crowded lift)
|
||||||
|
|
||||||
|
// MBF code for friends. Cannot be done in ZDoom but left here as a reminder for later implementation.
|
||||||
|
|
||||||
|
if (actor->flags & target->flags & MF_FRIEND &&
|
||||||
|
distfriend << FRACBITS > dist &&
|
||||||
|
!P_IsOnLift(target) && !P_IsUnderDamage(actor))
|
||||||
|
deltax = -deltax, deltay = -deltay;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MBF_STUFF
|
||||||
|
// MBF's monster_backing option. Made an actor flag instead. Also cleaned the code up to make it readable.
|
||||||
|
// Todo: implement the movement logic
|
||||||
|
if (target->health > 0 && !actor->IsFriend(target))
|
||||||
|
{ // Live enemy target
|
||||||
|
|
||||||
|
if (actor->flags3 & MF3_AVOIDMELEE)
|
||||||
|
{
|
||||||
|
bool ismeleeattacker = false;
|
||||||
|
if (target->player == NULL)
|
||||||
|
{
|
||||||
|
ismeleeattacker = (target->MissileState == NULL && dist < (target->meleerange + target->radius)*2);
|
||||||
|
}
|
||||||
|
else if (target->player->ReadyWeapon != NULL)
|
||||||
|
{
|
||||||
|
// melee range of player weapon is a parameter of the action function and cannot be checked here.
|
||||||
|
// Add a new weapon property?
|
||||||
|
ismeleeattacker = (target->player->ReadyWeapon->WeaponFlags & WIF_BOT_MELEE && dist < MELEERANGE*3);
|
||||||
|
}
|
||||||
|
if (ismeleeattacker)
|
||||||
|
{
|
||||||
|
actor->strafecount = pr_enemystrafe() & 15;
|
||||||
|
deltax = -deltax, deltay = -deltay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
P_DoNewChaseDir(actor, deltax, deltay);
|
P_DoNewChaseDir(actor, deltax, deltay);
|
||||||
|
|
||||||
|
#ifdef MBF_STUFF
|
||||||
|
// If strafing, set movecount to strafecount so that old Doom
|
||||||
|
// logic still works the same, except in the strafing part
|
||||||
|
|
||||||
|
if (actor->strafecount)
|
||||||
|
actor->movecount = actor->strafecount;
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -996,6 +1085,58 @@ void P_RandomChaseDir (AActor *actor)
|
||||||
actor->movedir = DI_NODIR; // cannot move
|
actor->movedir = DI_NODIR; // cannot move
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// P_IsVisible
|
||||||
|
//
|
||||||
|
// killough 9/9/98: whether a target is visible to a monster
|
||||||
|
// Extended to handle all A_LookEx related checking, too.
|
||||||
|
//
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool P_IsVisible(AActor *lookee, AActor *other, INTBOOL allaround, FLookExParams *params)
|
||||||
|
{
|
||||||
|
fixed_t maxdist;
|
||||||
|
fixed_t mindist;
|
||||||
|
angle_t fov;
|
||||||
|
|
||||||
|
if (params != NULL)
|
||||||
|
{
|
||||||
|
maxdist = params->maxdist;
|
||||||
|
mindist = params->mindist;
|
||||||
|
fov = params->fov;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mindist = maxdist = 0;
|
||||||
|
fov = allaround? 0 : ANGLE_180;
|
||||||
|
}
|
||||||
|
|
||||||
|
fixed_t dist = P_AproxDistance (other->x - lookee->x, other->y - lookee->y);
|
||||||
|
|
||||||
|
if (maxdist && dist > maxdist)
|
||||||
|
return false; // [KS] too far
|
||||||
|
|
||||||
|
if (mindist && dist < mindist)
|
||||||
|
return false; // [KS] too close
|
||||||
|
|
||||||
|
if (fov && fov < ANGLE_MAX)
|
||||||
|
{
|
||||||
|
angle_t an = R_PointToAngle2 (lookee->x, lookee->y, other->x, other->y) - lookee->angle;
|
||||||
|
|
||||||
|
if (an > (fov / 2) && an < (ANGLE_MAX - (fov / 2)))
|
||||||
|
{
|
||||||
|
// if real close, react anyway
|
||||||
|
// [KS] but respect minimum distance rules
|
||||||
|
if (mindist || dist > MELEERANGE)
|
||||||
|
return false; // outside of fov
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// P_CheckSight is by far the most expensive operation in here so let's do it last.
|
||||||
|
return P_CheckSight(lookee, other, 2);
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// FUNC P_LookForMonsters
|
// FUNC P_LookForMonsters
|
||||||
|
@ -1061,8 +1202,9 @@ bool P_LookForMonsters (AActor *actor)
|
||||||
//
|
//
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
AActor *LookForTIDinBlock (AActor *lookee, int index)
|
AActor *LookForTIDInBlock (AActor *lookee, int index, void *extparams)
|
||||||
{
|
{
|
||||||
|
FLookExParams *params = (FLookExParams *)extparams;
|
||||||
FBlockNode *block;
|
FBlockNode *block;
|
||||||
AActor *link;
|
AActor *link;
|
||||||
AActor *other;
|
AActor *other;
|
||||||
|
@ -1104,25 +1246,8 @@ AActor *LookForTIDinBlock (AActor *lookee, int index)
|
||||||
|
|
||||||
if (!(lookee->flags3 & MF3_NOSIGHTCHECK))
|
if (!(lookee->flags3 & MF3_NOSIGHTCHECK))
|
||||||
{
|
{
|
||||||
if (!P_CheckSight (lookee, other, 2))
|
if (!P_IsVisible(lookee, other, true, params))
|
||||||
continue; // out of sight
|
continue; // out of sight
|
||||||
/*
|
|
||||||
if (!allaround)
|
|
||||||
{
|
|
||||||
angle_t an = R_PointToAngle2 (actor->x, actor->y,
|
|
||||||
other->x, other->y)
|
|
||||||
- actor->angle;
|
|
||||||
|
|
||||||
if (an > ANG90 && an < ANG270)
|
|
||||||
{
|
|
||||||
fixed_t dist = P_AproxDistance (other->x - actor->x,
|
|
||||||
other->y - actor->y);
|
|
||||||
// if real close, react anyway
|
|
||||||
if (dist > MELEERANGE)
|
|
||||||
continue; // behind back
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return other;
|
return other;
|
||||||
|
@ -1138,12 +1263,13 @@ AActor *LookForTIDinBlock (AActor *lookee, int index)
|
||||||
//
|
//
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
bool P_LookForTID (AActor *actor, INTBOOL allaround)
|
bool P_LookForTID (AActor *actor, INTBOOL allaround, FLookExParams *params)
|
||||||
{
|
{
|
||||||
AActor *other;
|
AActor *other;
|
||||||
bool reachedend = false;
|
bool reachedend = false;
|
||||||
|
bool chasegoal = params? (!(params->flags & LOF_DONTCHASEGOAL)) : true;
|
||||||
|
|
||||||
other = P_BlockmapSearch (actor, 0, LookForTIDinBlock);
|
other = P_BlockmapSearch (actor, 0, LookForTIDInBlock, params);
|
||||||
|
|
||||||
if (other != NULL)
|
if (other != NULL)
|
||||||
{
|
{
|
||||||
|
@ -1198,24 +1324,8 @@ bool P_LookForTID (AActor *actor, INTBOOL allaround)
|
||||||
|
|
||||||
if (!(actor->flags3 & MF3_NOSIGHTCHECK))
|
if (!(actor->flags3 & MF3_NOSIGHTCHECK))
|
||||||
{
|
{
|
||||||
if (!P_CheckSight (actor, other, 2))
|
if (!P_IsVisible (actor, other, !!allaround, params))
|
||||||
continue; // out of sight
|
continue; // out of sight
|
||||||
|
|
||||||
if (!allaround)
|
|
||||||
{
|
|
||||||
angle_t an = R_PointToAngle2 (actor->x, actor->y,
|
|
||||||
other->x, other->y)
|
|
||||||
- actor->angle;
|
|
||||||
|
|
||||||
if (an > ANG90 && an < ANG270)
|
|
||||||
{
|
|
||||||
fixed_t dist = P_AproxDistance (other->x - actor->x,
|
|
||||||
other->y - actor->y);
|
|
||||||
// if real close, react anyway
|
|
||||||
if (dist > MELEERANGE)
|
|
||||||
continue; // behind back
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// [RH] Need to be sure the reactiontime is 0 if the monster is
|
// [RH] Need to be sure the reactiontime is 0 if the monster is
|
||||||
|
@ -1231,7 +1341,7 @@ bool P_LookForTID (AActor *actor, INTBOOL allaround)
|
||||||
if (actor->target == NULL)
|
if (actor->target == NULL)
|
||||||
{
|
{
|
||||||
// [RH] use goal as target
|
// [RH] use goal as target
|
||||||
if (actor->goal != NULL)
|
if (actor->goal != NULL && chasegoal)
|
||||||
{
|
{
|
||||||
actor->target = actor->goal;
|
actor->target = actor->goal;
|
||||||
return true;
|
return true;
|
||||||
|
@ -1256,18 +1366,19 @@ bool P_LookForTID (AActor *actor, INTBOOL allaround)
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
//
|
//
|
||||||
// LookForTIDinBlock
|
// LookForEnemiesinBlock
|
||||||
//
|
//
|
||||||
// Finds a non-friendly monster in a mapblock. It can also use targets of
|
// Finds a non-friendly monster in a mapblock. It can also use targets of
|
||||||
// friendlies in this mapblock to find non-friendlies in other mapblocks.
|
// friendlies in this mapblock to find non-friendlies in other mapblocks.
|
||||||
//
|
//
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
AActor *LookForEnemiesInBlock (AActor *lookee, int index)
|
AActor *LookForEnemiesInBlock (AActor *lookee, int index, void *extparam)
|
||||||
{
|
{
|
||||||
FBlockNode *block;
|
FBlockNode *block;
|
||||||
AActor *link;
|
AActor *link;
|
||||||
AActor *other;
|
AActor *other;
|
||||||
|
FLookExParams *params = (FLookExParams *)extparam;
|
||||||
|
|
||||||
for (block = blocklinks[index]; block != NULL; block = block->NextActor)
|
for (block = blocklinks[index]; block != NULL; block = block->NextActor)
|
||||||
{
|
{
|
||||||
|
@ -1330,25 +1441,11 @@ AActor *LookForEnemiesInBlock (AActor *lookee, int index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (other == NULL || !P_CheckSight (lookee, other, 2))
|
// [KS] Hey, shouldn't there be a check for MF3_NOSIGHTCHECK here?
|
||||||
continue; // out of sight
|
|
||||||
/*
|
if (other == NULL || !P_IsVisible (lookee, other, true, params))
|
||||||
if (!allaround)
|
continue; // out of sight
|
||||||
{
|
|
||||||
angle_t an = R_PointToAngle2 (actor->x, actor->y,
|
|
||||||
other->x, other->y)
|
|
||||||
- actor->angle;
|
|
||||||
|
|
||||||
if (an > ANG90 && an < ANG270)
|
|
||||||
{
|
|
||||||
fixed_t dist = P_AproxDistance (other->x - actor->x,
|
|
||||||
other->y - actor->y);
|
|
||||||
// if real close, react anyway
|
|
||||||
if (dist > MELEERANGE)
|
|
||||||
continue; // behind back
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
return other;
|
return other;
|
||||||
}
|
}
|
||||||
|
@ -1363,11 +1460,11 @@ AActor *LookForEnemiesInBlock (AActor *lookee, int index)
|
||||||
//
|
//
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
||||||
bool P_LookForEnemies (AActor *actor, INTBOOL allaround)
|
bool P_LookForEnemies (AActor *actor, INTBOOL allaround, FLookExParams *params)
|
||||||
{
|
{
|
||||||
AActor *other;
|
AActor *other;
|
||||||
|
|
||||||
other = P_BlockmapSearch (actor, 10, LookForEnemiesInBlock);
|
other = P_BlockmapSearch (actor, 10, LookForEnemiesInBlock, params);
|
||||||
|
|
||||||
if (other != NULL)
|
if (other != NULL)
|
||||||
{
|
{
|
||||||
|
@ -1415,18 +1512,17 @@ bool P_LookForEnemies (AActor *actor, INTBOOL allaround)
|
||||||
================
|
================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool P_LookForPlayers (AActor *actor, INTBOOL allaround)
|
bool P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params)
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
int stop;
|
int stop;
|
||||||
int pnum;
|
int pnum;
|
||||||
player_t* player;
|
player_t* player;
|
||||||
angle_t an;
|
bool chasegoal = params? (!(params->flags & LOF_DONTCHASEGOAL)) : true;
|
||||||
fixed_t dist;
|
|
||||||
|
|
||||||
if (actor->TIDtoHate != 0)
|
if (actor->TIDtoHate != 0)
|
||||||
{
|
{
|
||||||
if (P_LookForTID (actor, allaround))
|
if (P_LookForTID (actor, allaround, params))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1437,10 +1533,43 @@ bool P_LookForPlayers (AActor *actor, INTBOOL allaround)
|
||||||
}
|
}
|
||||||
else if (actor->flags & MF_FRIENDLY)
|
else if (actor->flags & MF_FRIENDLY)
|
||||||
{
|
{
|
||||||
if (!deathmatch) // [SP] If you don't see any enemies in deathmatch, look for players.
|
bool result = P_LookForEnemies (actor, allaround, params);
|
||||||
return P_LookForEnemies (actor, allaround);
|
|
||||||
else if ( P_LookForEnemies (actor, allaround) )
|
#ifdef MBF_FRIENDS
|
||||||
|
if (!result && (actor->flags & MF_FRIEND_MBF))
|
||||||
|
{ // killough 9/9/98: friendly monsters go about players differently
|
||||||
|
|
||||||
|
// Go back to a player, no matter whether it's visible or not
|
||||||
|
for (int anyone=0; anyone<=1; anyone++)
|
||||||
|
{
|
||||||
|
for (int c=0; c<MAXPLAYERS; c++)
|
||||||
|
{
|
||||||
|
if (playeringame[c] && players[c].playerstate==PST_LIVE &&
|
||||||
|
actor->IsFriend(players[c].mo) &&
|
||||||
|
(anyone || P_IsVisible(actor, players[c].mo, allaround)))
|
||||||
|
{
|
||||||
|
actor->target = players[c].mo;
|
||||||
|
|
||||||
|
// killough 12/98:
|
||||||
|
// get out of refiring loop, to avoid hitting player accidentally
|
||||||
|
|
||||||
|
if (actor->MissileState != NULL)
|
||||||
|
{
|
||||||
|
actor->SetStateNF(actor->SeeState);
|
||||||
|
actor->flags &= ~MF_JUSTHIT;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// [SP] If you don't see any enemies in deathmatch, look for players (but only when friend to a specific player.)
|
||||||
|
if (actor->FriendPlayer == 0) return false;
|
||||||
|
if (result || !deathmatch) return true;
|
||||||
|
|
||||||
|
|
||||||
} // [SP] if false, and in deathmatch, intentional fall-through
|
} // [SP] if false, and in deathmatch, intentional fall-through
|
||||||
|
|
||||||
if (!(gameinfo.gametype & (GAME_DoomStrifeChex)) &&
|
if (!(gameinfo.gametype & (GAME_DoomStrifeChex)) &&
|
||||||
|
@ -1478,7 +1607,8 @@ bool P_LookForPlayers (AActor *actor, INTBOOL allaround)
|
||||||
if (actor->target == NULL)
|
if (actor->target == NULL)
|
||||||
{
|
{
|
||||||
// [RH] use goal as target
|
// [RH] use goal as target
|
||||||
if (actor->goal != NULL)
|
// [KS] ...unless we're ignoring goals and we don't already have one
|
||||||
|
if (actor->goal != NULL && chasegoal)
|
||||||
{
|
{
|
||||||
actor->target = actor->goal;
|
actor->target = actor->goal;
|
||||||
return true;
|
return true;
|
||||||
|
@ -1512,7 +1642,7 @@ bool P_LookForPlayers (AActor *actor, INTBOOL allaround)
|
||||||
if (player->health <= 0)
|
if (player->health <= 0)
|
||||||
continue; // dead
|
continue; // dead
|
||||||
|
|
||||||
if (!P_CheckSight (actor, player->mo, 2))
|
if (!P_IsVisible (actor, player->mo, allaround, params))
|
||||||
continue; // out of sight
|
continue; // out of sight
|
||||||
|
|
||||||
// [SP] Deathmatch fixes - if we have MF_FRIENDLY we're definitely in deathmatch
|
// [SP] Deathmatch fixes - if we have MF_FRIENDLY we're definitely in deathmatch
|
||||||
|
@ -1525,23 +1655,6 @@ bool P_LookForPlayers (AActor *actor, INTBOOL allaround)
|
||||||
continue; // This is my master.
|
continue; // This is my master.
|
||||||
}
|
}
|
||||||
|
|
||||||
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 && !(i_compatflags & COMPATF_INVISIBILITY)) ||
|
if ((player->mo->flags & MF_SHADOW && !(i_compatflags & COMPATF_INVISIBILITY)) ||
|
||||||
player->mo->flags3 & MF3_GHOST)
|
player->mo->flags3 & MF3_GHOST)
|
||||||
{
|
{
|
||||||
|
@ -1630,7 +1743,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look)
|
||||||
{
|
{
|
||||||
// If we find a valid target here, the wandering logic should *not*
|
// If we find a valid target here, the wandering logic should *not*
|
||||||
// be activated! It would cause the seestate to be set twice.
|
// be activated! It would cause the seestate to be set twice.
|
||||||
if (P_LookForPlayers (self, self->flags4 & MF4_LOOKALLAROUND))
|
if (P_LookForPlayers (self, self->flags4 & MF4_LOOKALLAROUND, NULL))
|
||||||
goto seeyou;
|
goto seeyou;
|
||||||
|
|
||||||
// Let the self wander around aimlessly looking for a fight
|
// Let the self wander around aimlessly looking for a fight
|
||||||
|
@ -1657,7 +1770,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!P_LookForPlayers (self, self->flags4 & MF4_LOOKALLAROUND))
|
if (!P_LookForPlayers (self, self->flags4 & MF4_LOOKALLAROUND, NULL))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// go into chase state
|
// go into chase state
|
||||||
|
@ -1687,6 +1800,193 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// A_LookEx (int flags, fixed minseedist, fixed maxseedist, fixed maxheardist, fixed fov, state wakestate)
|
||||||
|
// [KS] Borrowed the A_Look code to make a parameterized version.
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LookEx)
|
||||||
|
{
|
||||||
|
ACTION_PARAM_START(6);
|
||||||
|
ACTION_PARAM_INT(flags, 0);
|
||||||
|
ACTION_PARAM_FIXED(minseedist, 1);
|
||||||
|
ACTION_PARAM_FIXED(maxseedist, 2);
|
||||||
|
ACTION_PARAM_FIXED(maxheardist, 3);
|
||||||
|
ACTION_PARAM_ANGLE(fov, 4);
|
||||||
|
ACTION_PARAM_STATE(seestate, 5);
|
||||||
|
|
||||||
|
AActor *targ = NULL; // Shuts up gcc
|
||||||
|
fixed_t dist;
|
||||||
|
FLookExParams params = {fov, minseedist, maxseedist, maxheardist, flags, seestate };
|
||||||
|
|
||||||
|
if (self->flags5 & MF5_INCONVERSATION)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// [RH] Set goal now if appropriate
|
||||||
|
if (self->special == Thing_SetGoal && self->args[0] == 0)
|
||||||
|
{
|
||||||
|
NActorIterator iterator (NAME_PatrolPoint, self->args[1]);
|
||||||
|
self->special = 0;
|
||||||
|
self->goal = iterator.Next ();
|
||||||
|
self->reactiontime = self->args[2] * TICRATE + level.maptime;
|
||||||
|
if (self->args[3] == 0) self->flags5 &=~ MF5_CHASEGOAL;
|
||||||
|
else self->flags5 |= MF5_CHASEGOAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->threshold = 0; // any shot will wake up
|
||||||
|
|
||||||
|
if (self->TIDtoHate != 0)
|
||||||
|
{
|
||||||
|
targ = self->target;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!(flags & LOF_NOSOUNDCHECK))
|
||||||
|
{
|
||||||
|
targ = self->LastHeard;
|
||||||
|
if (targ != NULL)
|
||||||
|
{
|
||||||
|
// [RH] If the soundtarget is dead, don't chase it
|
||||||
|
if (targ->health <= 0)
|
||||||
|
{
|
||||||
|
targ = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dist = P_AproxDistance (targ->x - self->x,
|
||||||
|
targ->y - self->y);
|
||||||
|
|
||||||
|
// [KS] If the target is too far away, don't respond to the sound.
|
||||||
|
if (maxheardist && dist > maxheardist)
|
||||||
|
{
|
||||||
|
targ = NULL;
|
||||||
|
self->LastHeard = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targ && targ->player && (targ->player->cheats & CF_NOTARGET))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// [RH] Andy Baker's stealth monsters
|
||||||
|
if (self->flags & MF_STEALTH)
|
||||||
|
{
|
||||||
|
self->visdir = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targ && (targ->flags & MF_SHOOTABLE))
|
||||||
|
{
|
||||||
|
if (self->IsFriend (targ)) // be a little more precise!
|
||||||
|
{
|
||||||
|
if (!(self->flags4 & MF4_STANDSTILL))
|
||||||
|
{
|
||||||
|
if (!(flags & LOF_NOSIGHTCHECK))
|
||||||
|
{
|
||||||
|
// If we find a valid target here, the wandering logic should *not*
|
||||||
|
// be activated! If would cause the seestate to be set twice.
|
||||||
|
if (P_LookForPlayers(self, true, ¶ms))
|
||||||
|
goto seeyou;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let the self wander around aimlessly looking for a fight
|
||||||
|
if (!(self->flags & MF_INCHASE))
|
||||||
|
{
|
||||||
|
if (seestate)
|
||||||
|
{
|
||||||
|
self->SetState (seestate);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (self->SeeState != NULL)
|
||||||
|
{
|
||||||
|
self->SetState (self->SeeState);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CALL_ACTION(A_Wander, self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
self->target = targ; //We already have a target?
|
||||||
|
|
||||||
|
// [KS] The target can become ourselves in rare circumstances (like
|
||||||
|
// if we committed suicide), so if that's the case, just ignore it.
|
||||||
|
if (self->target == self) self->target = NULL;
|
||||||
|
|
||||||
|
if (self->target != NULL)
|
||||||
|
{
|
||||||
|
if (self->flags & MF_AMBUSH)
|
||||||
|
{
|
||||||
|
dist = P_AproxDistance (self->target->x - self->x,
|
||||||
|
self->target->y - self->y);
|
||||||
|
if (P_CheckSight (self, self->target, 2) &&
|
||||||
|
(!minseedist || dist > minseedist) &&
|
||||||
|
(!maxseedist || dist < maxseedist))
|
||||||
|
{
|
||||||
|
goto seeyou;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
goto seeyou;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(flags & LOF_NOSIGHTCHECK))
|
||||||
|
{
|
||||||
|
if (!P_LookForPlayers(self, true, ¶ms))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// go into chase state
|
||||||
|
seeyou:
|
||||||
|
// [RH] Don't start chasing after a goal if it isn't time yet.
|
||||||
|
if (self->target == self->goal)
|
||||||
|
{
|
||||||
|
if (self->reactiontime > level.maptime)
|
||||||
|
self->target = NULL;
|
||||||
|
}
|
||||||
|
else if (self->SeeSound && !(flags & LOF_NOSEESOUND))
|
||||||
|
{
|
||||||
|
if (flags & LOF_FULLVOLSEESOUND)
|
||||||
|
{ // full volume
|
||||||
|
S_Sound (self, CHAN_VOICE, self->SeeSound, 1, ATTN_NONE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
S_Sound (self, CHAN_VOICE, self->SeeSound, 1, ATTN_NORM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->target && !(self->flags & MF_INCHASE))
|
||||||
|
{
|
||||||
|
if (seestate)
|
||||||
|
{
|
||||||
|
self->SetState (seestate);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
self->SetState (self->SeeState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// [KS] *** End additions by me ***
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// A_Wander
|
// A_Wander
|
||||||
|
@ -1770,7 +2070,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look2)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!P_LookForPlayers (self, self->flags4 & MF4_LOOKALLAROUND))
|
if (!P_LookForPlayers (self, self->flags4 & MF4_LOOKALLAROUND, NULL))
|
||||||
goto nosee;
|
goto nosee;
|
||||||
self->SetState (self->SeeState);
|
self->SetState (self->SeeState);
|
||||||
self->flags4 |= MF4_INCOMBAT;
|
self->flags4 |= MF4_INCOMBAT;
|
||||||
|
@ -1916,7 +2216,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi
|
||||||
// hurt our old one temporarily.
|
// hurt our old one temporarily.
|
||||||
actor->threshold = 0;
|
actor->threshold = 0;
|
||||||
}
|
}
|
||||||
if (P_LookForPlayers (actor, true) && actor->target != actor->goal)
|
if (P_LookForPlayers (actor, true, NULL) && actor->target != actor->goal)
|
||||||
{ // got a new target
|
{ // got a new target
|
||||||
actor->flags &= ~MF_INCHASE;
|
actor->flags &= ~MF_INCHASE;
|
||||||
return;
|
return;
|
||||||
|
@ -2088,7 +2388,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi
|
||||||
lookForBetter = true;
|
lookForBetter = true;
|
||||||
}
|
}
|
||||||
AActor * oldtarget = actor->target;
|
AActor * oldtarget = actor->target;
|
||||||
gotNew = P_LookForPlayers (actor, true);
|
gotNew = P_LookForPlayers (actor, true, NULL);
|
||||||
if (lookForBetter)
|
if (lookForBetter)
|
||||||
{
|
{
|
||||||
actor->flags3 |= MF3_NOSIGHTCHECK;
|
actor->flags3 |= MF3_NOSIGHTCHECK;
|
||||||
|
|
|
@ -25,6 +25,25 @@ enum dirtype_t
|
||||||
|
|
||||||
extern fixed_t xspeed[8], yspeed[8];
|
extern fixed_t xspeed[8], yspeed[8];
|
||||||
|
|
||||||
|
enum LO_Flags
|
||||||
|
{
|
||||||
|
LOF_NOSIGHTCHECK = 1,
|
||||||
|
LOF_NOSOUNDCHECK = 2,
|
||||||
|
LOF_DONTCHASEGOAL = 4,
|
||||||
|
LOF_NOSEESOUND = 8,
|
||||||
|
LOF_FULLVOLSEESOUND = 16,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FLookExParams
|
||||||
|
{
|
||||||
|
angle_t fov;
|
||||||
|
fixed_t mindist;
|
||||||
|
fixed_t maxdist;
|
||||||
|
fixed_t maxheardist;
|
||||||
|
int flags;
|
||||||
|
FState *seestate;
|
||||||
|
};
|
||||||
|
|
||||||
void P_RecursiveSound (sector_t *sec, AActor *soundtarget, bool splash, int soundblocks);
|
void P_RecursiveSound (sector_t *sec, AActor *soundtarget, bool splash, int soundblocks);
|
||||||
bool P_HitFriend (AActor *self);
|
bool P_HitFriend (AActor *self);
|
||||||
void P_NoiseAlert (AActor *target, AActor *emmiter, bool splash=false);
|
void P_NoiseAlert (AActor *target, AActor *emmiter, bool splash=false);
|
||||||
|
@ -32,9 +51,9 @@ bool P_CheckMeleeRange2 (AActor *actor);
|
||||||
bool P_Move (AActor *actor);
|
bool P_Move (AActor *actor);
|
||||||
bool P_TryWalk (AActor *actor);
|
bool P_TryWalk (AActor *actor);
|
||||||
void P_NewChaseDir (AActor *actor);
|
void P_NewChaseDir (AActor *actor);
|
||||||
bool P_LookForPlayers (AActor *actor, INTBOOL allaround);
|
|
||||||
AInventory *P_DropItem (AActor *source, const PClass *type, int special, int chance);
|
AInventory *P_DropItem (AActor *source, const PClass *type, int special, int chance);
|
||||||
void P_TossItem (AActor *item);
|
void P_TossItem (AActor *item);
|
||||||
|
bool P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params);
|
||||||
|
|
||||||
DECLARE_ACTION(A_Look)
|
DECLARE_ACTION(A_Look)
|
||||||
DECLARE_ACTION(A_Wander)
|
DECLARE_ACTION(A_Wander)
|
||||||
|
|
|
@ -1,904 +0,0 @@
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "templates.h"
|
|
||||||
#include "m_random.h"
|
|
||||||
#include "i_system.h"
|
|
||||||
#include "doomdef.h"
|
|
||||||
#include "p_local.h"
|
|
||||||
#include "p_lnspec.h"
|
|
||||||
#include "s_sound.h"
|
|
||||||
#include "g_game.h"
|
|
||||||
#include "doomstat.h"
|
|
||||||
#include "r_state.h"
|
|
||||||
#include "c_cvars.h"
|
|
||||||
#include "p_enemy.h"
|
|
||||||
#include "a_sharedglobal.h"
|
|
||||||
#include "a_action.h"
|
|
||||||
#include "thingdef/thingdef.h"
|
|
||||||
#include "g_level.h"
|
|
||||||
|
|
||||||
#include "gi.h"
|
|
||||||
|
|
||||||
bool P_LookForMonsters (AActor *actor);
|
|
||||||
|
|
||||||
static FRandom pr_look2 ("LookyLookyEx");
|
|
||||||
static FRandom pr_look3 ("IGotHookyEx");
|
|
||||||
static FRandom pr_lookforplayers ("LookForPlayersEx");
|
|
||||||
static FRandom pr_skiptarget("SkipTargetEx");
|
|
||||||
|
|
||||||
|
|
||||||
// [KS] *** Start additions by me - p_enemy.cpp ***
|
|
||||||
|
|
||||||
// LookForTIDinBlockEx
|
|
||||||
// LookForEnemiesInBlockEx
|
|
||||||
// P_NewLookTID (copied from P_LookForTID)
|
|
||||||
// P_NewLookPlayers (copied from P_LookForPlayers)
|
|
||||||
// Takes FOV and sight distances into account when acquiring a target.
|
|
||||||
// TODO: Not sure if using actor properties to pass parameters around indirectly is such a good idea. If there's a cleaner method, do it that way instead.
|
|
||||||
// ~Kate S. Last updated on 12/23/2007
|
|
||||||
|
|
||||||
AActor *LookForTIDinBlockEx (AActor *lookee, int index)
|
|
||||||
{
|
|
||||||
FBlockNode *block;
|
|
||||||
AActor *link;
|
|
||||||
AActor *other;
|
|
||||||
fixed_t dist;
|
|
||||||
angle_t an;
|
|
||||||
|
|
||||||
for (block = blocklinks[index]; block != NULL; block = block->NextActor)
|
|
||||||
{
|
|
||||||
link = block->Me;
|
|
||||||
|
|
||||||
if (!(link->flags & MF_SHOOTABLE))
|
|
||||||
continue; // not shootable (observer or dead)
|
|
||||||
|
|
||||||
if (link == lookee)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (link->health <= 0)
|
|
||||||
continue; // dead
|
|
||||||
|
|
||||||
if (link->flags2 & MF2_DORMANT)
|
|
||||||
continue; // don't target dormant things
|
|
||||||
|
|
||||||
if (link->tid == lookee->TIDtoHate)
|
|
||||||
{
|
|
||||||
other = link;
|
|
||||||
}
|
|
||||||
else if (link->target != NULL && link->target->tid == lookee->TIDtoHate)
|
|
||||||
{
|
|
||||||
other = link->target;
|
|
||||||
if (!(other->flags & MF_SHOOTABLE) ||
|
|
||||||
other->health <= 0 ||
|
|
||||||
(other->flags2 & MF2_DORMANT))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(lookee->flags3 & MF3_NOSIGHTCHECK))
|
|
||||||
{
|
|
||||||
if (!P_CheckSight (lookee, other, 2))
|
|
||||||
continue; // out of sight
|
|
||||||
|
|
||||||
dist = P_AproxDistance (other->x - lookee->x,
|
|
||||||
other->y - lookee->y);
|
|
||||||
|
|
||||||
if (lookee->LookExMaxDist && dist > lookee->LookExMaxDist)
|
|
||||||
continue; // [KS] too far
|
|
||||||
|
|
||||||
if (lookee->LookExMinDist && dist < lookee->LookExMinDist)
|
|
||||||
continue; // [KS] too close
|
|
||||||
|
|
||||||
if (lookee->LookExFOV && lookee->LookExFOV < ANGLE_MAX)
|
|
||||||
{
|
|
||||||
an = R_PointToAngle2 (lookee->x,
|
|
||||||
lookee->y,
|
|
||||||
other->x,
|
|
||||||
other->y)
|
|
||||||
- lookee->angle;
|
|
||||||
|
|
||||||
if (an > (lookee->LookExFOV / 2) && an < (ANGLE_MAX - (lookee->LookExFOV / 2)))
|
|
||||||
{
|
|
||||||
// if real close, react anyway
|
|
||||||
// [KS] but respect minimum distance rules
|
|
||||||
if (lookee->LookExMinDist || dist > MELEERANGE)
|
|
||||||
continue; // outside of fov
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(!(lookee->flags4 & MF4_LOOKALLAROUND) || (lookee->LookExFOV >= ANGLE_MAX)) // Just in case angle_t doesn't clamp stuff, because I can't be too sure.
|
|
||||||
{
|
|
||||||
an = R_PointToAngle2 (lookee->x,
|
|
||||||
lookee->y,
|
|
||||||
other->x,
|
|
||||||
other->y)
|
|
||||||
- lookee->angle;
|
|
||||||
|
|
||||||
if (an > ANG90 && an < ANG270)
|
|
||||||
{
|
|
||||||
// if real close, react anyway
|
|
||||||
// [KS] but respect minimum distance rules
|
|
||||||
if (lookee->LookExMinDist || dist > MELEERANGE)
|
|
||||||
continue; // behind back
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return other;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
AActor *LookForEnemiesInBlockEx (AActor *lookee, int index)
|
|
||||||
{
|
|
||||||
FBlockNode *block;
|
|
||||||
AActor *link;
|
|
||||||
AActor *other;
|
|
||||||
fixed_t dist;
|
|
||||||
angle_t an;
|
|
||||||
|
|
||||||
for (block = blocklinks[index]; block != NULL; block = block->NextActor)
|
|
||||||
{
|
|
||||||
link = block->Me;
|
|
||||||
|
|
||||||
if (!(link->flags & MF_SHOOTABLE))
|
|
||||||
continue; // not shootable (observer or dead)
|
|
||||||
|
|
||||||
if (link == lookee)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (link->health <= 0)
|
|
||||||
continue; // dead
|
|
||||||
|
|
||||||
if (link->flags2 & MF2_DORMANT)
|
|
||||||
continue; // don't target dormant things
|
|
||||||
|
|
||||||
if (!(link->flags3 & MF3_ISMONSTER))
|
|
||||||
continue; // don't target it if it isn't a monster (could be a barrel)
|
|
||||||
|
|
||||||
other = NULL;
|
|
||||||
if (link->flags & MF_FRIENDLY)
|
|
||||||
{
|
|
||||||
if (deathmatch &&
|
|
||||||
lookee->FriendPlayer != 0 && link->FriendPlayer != 0 &&
|
|
||||||
lookee->FriendPlayer != link->FriendPlayer)
|
|
||||||
{
|
|
||||||
// This is somebody else's friend, so go after it
|
|
||||||
other = link;
|
|
||||||
}
|
|
||||||
else if (link->target != NULL && !(link->target->flags & MF_FRIENDLY))
|
|
||||||
{
|
|
||||||
other = link->target;
|
|
||||||
if (!(other->flags & MF_SHOOTABLE) ||
|
|
||||||
other->health <= 0 ||
|
|
||||||
(other->flags2 & MF2_DORMANT))
|
|
||||||
{
|
|
||||||
other = NULL;;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
other = link;
|
|
||||||
}
|
|
||||||
|
|
||||||
// [MBF] If the monster is already engaged in a one-on-one attack
|
|
||||||
// with a healthy friend, don't attack around 60% the time.
|
|
||||||
|
|
||||||
// [GrafZahl] This prevents friendlies from attacking all the same
|
|
||||||
// target.
|
|
||||||
|
|
||||||
if (other)
|
|
||||||
{
|
|
||||||
AActor *targ = other->target;
|
|
||||||
if (targ && targ->target == other && pr_skiptarget() > 100 && lookee->IsFriend (targ) &&
|
|
||||||
targ->health*2 >= targ->SpawnHealth())
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// [KS] Hey, shouldn't there be a check for MF3_NOSIGHTCHECK here?
|
|
||||||
|
|
||||||
if (other == NULL || !P_CheckSight (lookee, other, 2))
|
|
||||||
continue; // out of sight
|
|
||||||
|
|
||||||
dist = P_AproxDistance (other->x - lookee->x,
|
|
||||||
other->y - lookee->y);
|
|
||||||
|
|
||||||
if (lookee->LookExMaxDist && dist > lookee->LookExMaxDist)
|
|
||||||
continue; // [KS] too far
|
|
||||||
|
|
||||||
if (lookee->LookExMinDist && dist < lookee->LookExMinDist)
|
|
||||||
continue; // [KS] too close
|
|
||||||
|
|
||||||
if (lookee->LookExFOV && lookee->LookExFOV < ANGLE_MAX)
|
|
||||||
{
|
|
||||||
an = R_PointToAngle2 (lookee->x,
|
|
||||||
lookee->y,
|
|
||||||
other->x,
|
|
||||||
other->y)
|
|
||||||
- lookee->angle;
|
|
||||||
|
|
||||||
if (an > (lookee->LookExFOV / 2) && an < (ANGLE_MAX - (lookee->LookExFOV / 2)))
|
|
||||||
{
|
|
||||||
// if real close, react anyway
|
|
||||||
// [KS] but respect minimum distance rules
|
|
||||||
if (lookee->LookExMinDist || dist > MELEERANGE)
|
|
||||||
continue; // outside of fov
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(!(lookee->flags4 & MF4_LOOKALLAROUND) || (lookee->LookExFOV >= ANGLE_MAX)) // Just in case angle_t doesn't clamp stuff, because I can't be too sure.
|
|
||||||
{
|
|
||||||
an = R_PointToAngle2 (lookee->x,
|
|
||||||
lookee->y,
|
|
||||||
other->x,
|
|
||||||
other->y)
|
|
||||||
- lookee->angle;
|
|
||||||
|
|
||||||
if (an > ANG90 && an < ANG270)
|
|
||||||
{
|
|
||||||
// if real close, react anyway
|
|
||||||
// [KS] but respect minimum distance rules
|
|
||||||
if (lookee->LookExMinDist || dist > MELEERANGE)
|
|
||||||
continue; // behind back
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return other;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool P_NewLookTID (AActor *actor, angle_t fov, fixed_t mindist, fixed_t maxdist, bool chasegoal)
|
|
||||||
{
|
|
||||||
AActor *other;
|
|
||||||
|
|
||||||
actor->LookExMinDist = mindist;
|
|
||||||
actor->LookExMaxDist = maxdist;
|
|
||||||
actor->LookExFOV = fov;
|
|
||||||
other = P_BlockmapSearch (actor, 0, LookForTIDinBlockEx);
|
|
||||||
|
|
||||||
bool reachedend = false;
|
|
||||||
fixed_t dist;
|
|
||||||
angle_t an;
|
|
||||||
|
|
||||||
if (other != NULL)
|
|
||||||
{
|
|
||||||
if (!(actor->flags3 & MF3_NOSIGHTCHECK))
|
|
||||||
{
|
|
||||||
dist = P_AproxDistance (other->x - actor->x,
|
|
||||||
other->y - actor->y);
|
|
||||||
|
|
||||||
if (maxdist && dist > maxdist)
|
|
||||||
{
|
|
||||||
other = NULL; // [KS] too far
|
|
||||||
goto endcheck;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mindist && dist < mindist)
|
|
||||||
{
|
|
||||||
other = NULL; // [KS] too close
|
|
||||||
goto endcheck;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fov && fov < ANGLE_MAX)
|
|
||||||
{
|
|
||||||
an = R_PointToAngle2 (actor->x,
|
|
||||||
actor->y,
|
|
||||||
other->x,
|
|
||||||
other->y)
|
|
||||||
- actor->angle;
|
|
||||||
|
|
||||||
if (an > (fov / 2) && an < (ANGLE_MAX - (fov / 2)))
|
|
||||||
{
|
|
||||||
// if real close, react anyway
|
|
||||||
// [KS] but respect minimum distance rules
|
|
||||||
if (mindist || dist > MELEERANGE)
|
|
||||||
{
|
|
||||||
other = NULL; // outside of fov
|
|
||||||
goto endcheck;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(!((actor->flags4 & MF4_LOOKALLAROUND) || (fov >= ANGLE_MAX))) // Just in case angle_t doesn't clamp stuff, because I can't be too sure.
|
|
||||||
{
|
|
||||||
an = R_PointToAngle2 (actor->x,
|
|
||||||
actor->y,
|
|
||||||
other->x,
|
|
||||||
other->y)
|
|
||||||
- actor->angle;
|
|
||||||
|
|
||||||
if (an > ANG90 && an < ANG270)
|
|
||||||
{
|
|
||||||
// if real close, react anyway
|
|
||||||
// [KS] but respect minimum distance rules
|
|
||||||
if (mindist || dist > MELEERANGE)
|
|
||||||
{
|
|
||||||
other = NULL; // behind back
|
|
||||||
goto endcheck;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
endcheck:
|
|
||||||
|
|
||||||
if (other != NULL)
|
|
||||||
{
|
|
||||||
if (actor->goal && actor->target == actor->goal)
|
|
||||||
actor->reactiontime = 0;
|
|
||||||
|
|
||||||
actor->target = other;
|
|
||||||
actor->LastLookActor = other;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The actor's TID could change because of death or because of
|
|
||||||
// Thing_ChangeTID. If it's not what we expect, then don't use
|
|
||||||
// it as a base for the iterator.
|
|
||||||
if (actor->LastLookActor != NULL &&
|
|
||||||
actor->LastLookActor->tid != actor->TIDtoHate)
|
|
||||||
{
|
|
||||||
actor->LastLookActor = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
FActorIterator iterator (actor->TIDtoHate, actor->LastLookActor);
|
|
||||||
int c = (pr_look3() & 31) + 7; // Look for between 7 and 38 hatees at a time
|
|
||||||
while ((other = iterator.Next()) != actor->LastLookActor)
|
|
||||||
{
|
|
||||||
if (other == NULL)
|
|
||||||
{
|
|
||||||
if (reachedend)
|
|
||||||
{
|
|
||||||
// we have cycled through the entire list at least once
|
|
||||||
// so let's abort because even if we continue nothing can
|
|
||||||
// be found.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
reachedend = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(other->flags & MF_SHOOTABLE))
|
|
||||||
continue; // not shootable (observer or dead)
|
|
||||||
|
|
||||||
if (other == actor)
|
|
||||||
continue; // don't hate self
|
|
||||||
|
|
||||||
if (other->health <= 0)
|
|
||||||
continue; // dead
|
|
||||||
|
|
||||||
if (other->flags2 & MF2_DORMANT)
|
|
||||||
continue; // don't target dormant things
|
|
||||||
|
|
||||||
if (--c == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (!(actor->flags3 & MF3_NOSIGHTCHECK))
|
|
||||||
{
|
|
||||||
if (!P_CheckSight (actor, other, 2))
|
|
||||||
continue; // out of sight
|
|
||||||
|
|
||||||
dist = P_AproxDistance (other->x - actor->x,
|
|
||||||
other->y - actor->y);
|
|
||||||
|
|
||||||
if (maxdist && dist > maxdist)
|
|
||||||
continue; // [KS] too far
|
|
||||||
|
|
||||||
if (mindist && dist < mindist)
|
|
||||||
continue; // [KS] too close
|
|
||||||
|
|
||||||
if (fov && fov < ANGLE_MAX)
|
|
||||||
{
|
|
||||||
an = R_PointToAngle2 (actor->x,
|
|
||||||
actor->y,
|
|
||||||
other->x,
|
|
||||||
other->y)
|
|
||||||
- actor->angle;
|
|
||||||
|
|
||||||
if (an > (fov / 2) && an < (ANGLE_MAX - (fov / 2)))
|
|
||||||
{
|
|
||||||
// if real close, react anyway
|
|
||||||
// [KS] but respect minimum distance rules
|
|
||||||
if (mindist || dist > MELEERANGE)
|
|
||||||
continue; // outside of fov
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(!((actor->flags4 & MF4_LOOKALLAROUND) || (fov >= ANGLE_MAX))) // Just in case angle_t doesn't clamp stuff, because I can't be too sure.
|
|
||||||
{
|
|
||||||
an = R_PointToAngle2 (actor->x,
|
|
||||||
actor->y,
|
|
||||||
other->x,
|
|
||||||
other->y)
|
|
||||||
- actor->angle;
|
|
||||||
|
|
||||||
if (an > ANG90 && an < ANG270)
|
|
||||||
{
|
|
||||||
// if real close, react anyway
|
|
||||||
// [KS] but respect minimum distance rules
|
|
||||||
if (mindist || dist > MELEERANGE)
|
|
||||||
continue; // behind back
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// [RH] Need to be sure the reactiontime is 0 if the monster is
|
|
||||||
// leaving its goal to go after something else.
|
|
||||||
if (actor->goal && actor->target == actor->goal)
|
|
||||||
actor->reactiontime = 0;
|
|
||||||
|
|
||||||
actor->target = other;
|
|
||||||
actor->LastLookActor = other;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
actor->LastLookActor = other;
|
|
||||||
if (actor->target == NULL)
|
|
||||||
{
|
|
||||||
// [RH] use goal as target
|
|
||||||
if (actor->goal != NULL && chasegoal)
|
|
||||||
{
|
|
||||||
actor->target = actor->goal;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// Use last known enemy if no hatee sighted -- killough 2/15/98:
|
|
||||||
if (actor->lastenemy != NULL && actor->lastenemy->health > 0)
|
|
||||||
{
|
|
||||||
if (!actor->IsFriend(actor->lastenemy))
|
|
||||||
{
|
|
||||||
actor->target = actor->lastenemy;
|
|
||||||
actor->lastenemy = NULL;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
actor->lastenemy = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool P_NewLookEnemies (AActor *actor, angle_t fov, fixed_t mindist, fixed_t maxdist, bool chasegoal)
|
|
||||||
{
|
|
||||||
AActor *other;
|
|
||||||
|
|
||||||
actor->LookExMinDist = mindist;
|
|
||||||
actor->LookExMaxDist = maxdist;
|
|
||||||
actor->LookExFOV = fov;
|
|
||||||
other = P_BlockmapSearch (actor, 10, LookForEnemiesInBlockEx);
|
|
||||||
|
|
||||||
if (other != NULL)
|
|
||||||
{
|
|
||||||
if (actor->goal && actor->target == actor->goal)
|
|
||||||
actor->reactiontime = 0;
|
|
||||||
|
|
||||||
actor->target = other;
|
|
||||||
// actor->LastLook.Actor = other;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (actor->target == NULL)
|
|
||||||
{
|
|
||||||
// [RH] use goal as target
|
|
||||||
if (actor->goal != NULL)
|
|
||||||
{
|
|
||||||
actor->target = actor->goal;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// Use last known enemy if no hatee sighted -- killough 2/15/98:
|
|
||||||
if (actor->lastenemy != NULL && actor->lastenemy->health > 0)
|
|
||||||
{
|
|
||||||
if (!actor->IsFriend(actor->lastenemy))
|
|
||||||
{
|
|
||||||
actor->target = actor->lastenemy;
|
|
||||||
actor->lastenemy = NULL;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
actor->lastenemy = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool P_NewLookPlayers (AActor *actor, angle_t fov, fixed_t mindist, fixed_t maxdist, bool chasegoal)
|
|
||||||
{
|
|
||||||
int c;
|
|
||||||
int stop;
|
|
||||||
int pnum;
|
|
||||||
player_t* player;
|
|
||||||
angle_t an;
|
|
||||||
fixed_t dist;
|
|
||||||
|
|
||||||
if (actor->TIDtoHate != 0)
|
|
||||||
{
|
|
||||||
if (P_NewLookTID (actor, fov, mindist, maxdist, chasegoal))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!(actor->flags3 & MF3_HUNTPLAYERS))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (actor->flags & MF_FRIENDLY)
|
|
||||||
{
|
|
||||||
if (!deathmatch) // [SP] If you don't see any enemies in deathmatch, look for players.
|
|
||||||
return P_NewLookEnemies (actor, fov, mindist, maxdist, chasegoal);
|
|
||||||
else if ( P_NewLookEnemies (actor, fov, mindist, maxdist, chasegoal) )
|
|
||||||
return true;
|
|
||||||
} // [SP] if false, and in deathmatch, intentional fall-through
|
|
||||||
|
|
||||||
if (!(gameinfo.gametype & (GAME_DoomStrifeChex)) &&
|
|
||||||
!multiplayer &&
|
|
||||||
players[0].health <= 0)
|
|
||||||
{ // Single player game and player is dead; look for monsters
|
|
||||||
return P_LookForMonsters (actor);
|
|
||||||
}
|
|
||||||
|
|
||||||
c = 0;
|
|
||||||
if (actor->TIDtoHate != 0)
|
|
||||||
{
|
|
||||||
pnum = pr_look2() & (MAXPLAYERS-1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pnum = actor->LastLookPlayerNumber;
|
|
||||||
}
|
|
||||||
stop = (pnum - 1) & (MAXPLAYERS-1);
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
pnum = (pnum + 1) & (MAXPLAYERS-1);
|
|
||||||
if (!playeringame[pnum])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (actor->TIDtoHate == 0)
|
|
||||||
{
|
|
||||||
actor->LastLookPlayerNumber = pnum;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (++c == MAXPLAYERS-1 || pnum == stop)
|
|
||||||
{
|
|
||||||
// done looking
|
|
||||||
if (actor->target == NULL)
|
|
||||||
{
|
|
||||||
// [RH] use goal as target
|
|
||||||
// [KS] ...unless we're ignoring goals and we don't already have one
|
|
||||||
if (actor->goal != NULL && chasegoal)
|
|
||||||
{
|
|
||||||
actor->target = actor->goal;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// Use last known enemy if no players sighted -- killough 2/15/98:
|
|
||||||
if (actor->lastenemy != NULL && actor->lastenemy->health > 0)
|
|
||||||
{
|
|
||||||
if (!actor->IsFriend(actor->lastenemy))
|
|
||||||
{
|
|
||||||
actor->target = actor->lastenemy;
|
|
||||||
actor->lastenemy = NULL;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
actor->lastenemy = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return actor->target == actor->goal && actor->goal != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
player = &players[pnum];
|
|
||||||
|
|
||||||
if (!(player->mo->flags & MF_SHOOTABLE))
|
|
||||||
continue; // not shootable (observer or dead)
|
|
||||||
|
|
||||||
if (player->cheats & CF_NOTARGET)
|
|
||||||
continue; // no target
|
|
||||||
|
|
||||||
if (player->health <= 0)
|
|
||||||
continue; // dead
|
|
||||||
|
|
||||||
if (!P_CheckSight (actor, player->mo, 2))
|
|
||||||
continue; // out of sight
|
|
||||||
|
|
||||||
dist = P_AproxDistance (player->mo->x - actor->x,
|
|
||||||
player->mo->y - actor->y);
|
|
||||||
|
|
||||||
if (maxdist && dist > maxdist)
|
|
||||||
continue; // [KS] too far
|
|
||||||
|
|
||||||
if (mindist && dist < mindist)
|
|
||||||
continue; // [KS] too close
|
|
||||||
|
|
||||||
// [SP] Deathmatch fixes - if we have MF_FRIENDLY we're definitely in deathmatch
|
|
||||||
// We're going to ignore our master, but go after his enemies.
|
|
||||||
if ( actor->flags & MF_FRIENDLY )
|
|
||||||
{
|
|
||||||
if ( actor->FriendPlayer == 0 )
|
|
||||||
continue; // I have no friends, I will ignore players.
|
|
||||||
if ( actor->FriendPlayer == player->mo->FriendPlayer )
|
|
||||||
continue; // This is my master.
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fov)
|
|
||||||
{
|
|
||||||
an = R_PointToAngle2 (actor->x,
|
|
||||||
actor->y,
|
|
||||||
player->mo->x,
|
|
||||||
player->mo->y)
|
|
||||||
- actor->angle;
|
|
||||||
|
|
||||||
if (an > (fov / 2) && an < (ANGLE_MAX - (fov / 2)))
|
|
||||||
{
|
|
||||||
// if real close, react anyway
|
|
||||||
// [KS] but respect minimum distance rules
|
|
||||||
if (mindist || dist > MELEERANGE)
|
|
||||||
continue; // outside of fov
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(!((actor->flags4 & MF4_LOOKALLAROUND) || (fov >= ANGLE_MAX)))
|
|
||||||
{
|
|
||||||
an = R_PointToAngle2 (actor->x,
|
|
||||||
actor->y,
|
|
||||||
player->mo->x,
|
|
||||||
player->mo->y)
|
|
||||||
- actor->angle;
|
|
||||||
|
|
||||||
if (an > ANG90 && an < ANG270)
|
|
||||||
{
|
|
||||||
// if real close, react anyway
|
|
||||||
// [KS] but respect minimum distance rules
|
|
||||||
if (mindist || dist > MELEERANGE)
|
|
||||||
continue; // behind back
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((player->mo->flags & MF_SHADOW && !(i_compatflags & COMPATF_INVISIBILITY)) ||
|
|
||||||
player->mo->flags3 & MF3_GHOST)
|
|
||||||
{
|
|
||||||
if ((P_AproxDistance (player->mo->x - actor->x,
|
|
||||||
player->mo->y - actor->y) > 2*MELEERANGE)
|
|
||||||
&& P_AproxDistance (player->mo->velx, player->mo->vely)
|
|
||||||
< 5*FRACUNIT)
|
|
||||||
{ // Player is sneaking - can't detect
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (pr_lookforplayers() < 225)
|
|
||||||
{ // Player isn't sneaking, but still didn't detect
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// [RH] Need to be sure the reactiontime is 0 if the monster is
|
|
||||||
// leaving its goal to go after a player.
|
|
||||||
if (actor->goal && actor->target == actor->goal)
|
|
||||||
actor->reactiontime = 0;
|
|
||||||
|
|
||||||
actor->target = player->mo;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// ACTION ROUTINES
|
|
||||||
//
|
|
||||||
|
|
||||||
//
|
|
||||||
// A_Look
|
|
||||||
// Stay in state until a player is sighted.
|
|
||||||
// [RH] Will also leave state to move to goal.
|
|
||||||
//
|
|
||||||
// A_LookEx (int flags, fixed minseedist, fixed maxseedist, fixed maxheardist, fixed fov, state wakestate)
|
|
||||||
// [KS] Borrowed the A_Look code to make a parameterized version.
|
|
||||||
//
|
|
||||||
|
|
||||||
enum LO_Flags
|
|
||||||
{
|
|
||||||
LOF_NOSIGHTCHECK = 1,
|
|
||||||
LOF_NOSOUNDCHECK = 2,
|
|
||||||
LOF_DONTCHASEGOAL = 4,
|
|
||||||
LOF_NOSEESOUND = 8,
|
|
||||||
LOF_FULLVOLSEESOUND = 16,
|
|
||||||
};
|
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LookEx)
|
|
||||||
{
|
|
||||||
ACTION_PARAM_START(6);
|
|
||||||
ACTION_PARAM_INT(flags, 0);
|
|
||||||
ACTION_PARAM_FIXED(minseedist, 1);
|
|
||||||
ACTION_PARAM_FIXED(maxseedist, 2);
|
|
||||||
ACTION_PARAM_FIXED(maxheardist, 3);
|
|
||||||
ACTION_PARAM_ANGLE(fov, 4);
|
|
||||||
ACTION_PARAM_STATE(seestate, 5);
|
|
||||||
|
|
||||||
AActor *targ = NULL; // Shuts up gcc
|
|
||||||
fixed_t dist;
|
|
||||||
|
|
||||||
if (self->flags5 & MF5_INCONVERSATION)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// [RH] Set goal now if appropriate
|
|
||||||
if (self->special == Thing_SetGoal && self->args[0] == 0)
|
|
||||||
{
|
|
||||||
NActorIterator iterator (NAME_PatrolPoint, self->args[1]);
|
|
||||||
self->special = 0;
|
|
||||||
self->goal = iterator.Next ();
|
|
||||||
self->reactiontime = self->args[2] * TICRATE + level.maptime;
|
|
||||||
if (self->args[3] == 0) self->flags5 &=~ MF5_CHASEGOAL;
|
|
||||||
else self->flags5 |= MF5_CHASEGOAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
self->threshold = 0; // any shot will wake up
|
|
||||||
|
|
||||||
if (self->TIDtoHate != 0)
|
|
||||||
{
|
|
||||||
targ = self->target;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!(flags & LOF_NOSOUNDCHECK))
|
|
||||||
{
|
|
||||||
targ = self->LastHeard;
|
|
||||||
if (targ != NULL)
|
|
||||||
{
|
|
||||||
// [RH] If the soundtarget is dead, don't chase it
|
|
||||||
if (targ->health <= 0)
|
|
||||||
{
|
|
||||||
targ = NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dist = P_AproxDistance (targ->x - self->x,
|
|
||||||
targ->y - self->y);
|
|
||||||
|
|
||||||
// [KS] If the target is too far away, don't respond to the sound.
|
|
||||||
if (maxheardist && dist > maxheardist)
|
|
||||||
{
|
|
||||||
targ = NULL;
|
|
||||||
self->LastHeard = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (targ && targ->player && (targ->player->cheats & CF_NOTARGET))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// [RH] Andy Baker's stealth monsters
|
|
||||||
if (self->flags & MF_STEALTH)
|
|
||||||
{
|
|
||||||
self->visdir = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (targ && (targ->flags & MF_SHOOTABLE))
|
|
||||||
{
|
|
||||||
if (self->IsFriend (targ)) // be a little more precise!
|
|
||||||
{
|
|
||||||
if (!(self->flags4 & MF4_STANDSTILL))
|
|
||||||
{
|
|
||||||
if (!(flags & LOF_NOSIGHTCHECK))
|
|
||||||
{
|
|
||||||
// If we find a valid target here, the wandering logic should *not*
|
|
||||||
// be activated! If would cause the seestate to be set twice.
|
|
||||||
if (P_NewLookPlayers(self, fov, minseedist, maxseedist, !(flags & LOF_DONTCHASEGOAL)))
|
|
||||||
goto seeyou;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Let the self wander around aimlessly looking for a fight
|
|
||||||
if (!(self->flags & MF_INCHASE))
|
|
||||||
{
|
|
||||||
if (seestate)
|
|
||||||
{
|
|
||||||
self->SetState (seestate);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (self->SeeState != NULL)
|
|
||||||
{
|
|
||||||
self->SetState (self->SeeState);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CALL_ACTION(A_Wander, self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
self->target = targ; //We already have a target?
|
|
||||||
|
|
||||||
// [KS] The target can become ourselves in rare circumstances (like
|
|
||||||
// if we committed suicide), so if that's the case, just ignore it.
|
|
||||||
if (self->target == self) self->target = NULL;
|
|
||||||
|
|
||||||
if (self->target != NULL)
|
|
||||||
{
|
|
||||||
if (self->flags & MF_AMBUSH)
|
|
||||||
{
|
|
||||||
dist = P_AproxDistance (self->target->x - self->x,
|
|
||||||
self->target->y - self->y);
|
|
||||||
if (P_CheckSight (self, self->target, 2) &&
|
|
||||||
(!minseedist || dist > minseedist) &&
|
|
||||||
(!maxseedist || dist < maxseedist))
|
|
||||||
{
|
|
||||||
goto seeyou;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
goto seeyou;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(flags & LOF_NOSIGHTCHECK))
|
|
||||||
{
|
|
||||||
if (!P_NewLookPlayers(self, fov, minseedist, maxseedist, !(flags & LOF_DONTCHASEGOAL)))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// go into chase state
|
|
||||||
seeyou:
|
|
||||||
// [RH] Don't start chasing after a goal if it isn't time yet.
|
|
||||||
if (self->target == self->goal)
|
|
||||||
{
|
|
||||||
if (self->reactiontime > level.maptime)
|
|
||||||
self->target = NULL;
|
|
||||||
}
|
|
||||||
else if (self->SeeSound && !(flags & LOF_NOSEESOUND))
|
|
||||||
{
|
|
||||||
if (flags & LOF_FULLVOLSEESOUND)
|
|
||||||
{ // full volume
|
|
||||||
S_Sound (self, CHAN_VOICE, self->SeeSound, 1, ATTN_NONE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
S_Sound (self, CHAN_VOICE, self->SeeSound, 1, ATTN_NORM);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self->target && !(self->flags & MF_INCHASE))
|
|
||||||
{
|
|
||||||
if (seestate)
|
|
||||||
{
|
|
||||||
self->SetState (seestate);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
self->SetState (self->SeeState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// [KS] *** End additions by me ***
|
|
|
@ -882,6 +882,7 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage
|
||||||
int painchance = 0;
|
int painchance = 0;
|
||||||
FState * woundstate = NULL;
|
FState * woundstate = NULL;
|
||||||
PainChanceList * pc = NULL;
|
PainChanceList * pc = NULL;
|
||||||
|
bool justhit = false;
|
||||||
|
|
||||||
if (target == NULL || !((target->flags & MF_SHOOTABLE) || (target->flags6 & MF6_VULNERABLE)))
|
if (target == NULL || !((target->flags & MF_SHOOTABLE) || (target->flags6 & MF6_VULNERABLE)))
|
||||||
{ // Shouldn't happen
|
{ // Shouldn't happen
|
||||||
|
@ -893,12 +894,6 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage
|
||||||
{
|
{
|
||||||
if (inflictor == NULL || !(inflictor->flags4 & MF4_SPECTRAL))
|
if (inflictor == NULL || !(inflictor->flags4 & MF4_SPECTRAL))
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
if (target->MissileState != NULL)
|
|
||||||
{
|
|
||||||
target->SetState (target->MissileState);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1285,7 +1280,7 @@ dopain:
|
||||||
{
|
{
|
||||||
if (pr_lightning() < 96)
|
if (pr_lightning() < 96)
|
||||||
{
|
{
|
||||||
target->flags |= MF_JUSTHIT; // fight back!
|
justhit = true;
|
||||||
FState * painstate = target->FindState(NAME_Pain, mod);
|
FState * painstate = target->FindState(NAME_Pain, mod);
|
||||||
if (painstate != NULL) target->SetState (painstate);
|
if (painstate != NULL) target->SetState (painstate);
|
||||||
}
|
}
|
||||||
|
@ -1300,7 +1295,7 @@ dopain:
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
target->flags |= MF_JUSTHIT; // fight back!
|
justhit = true;
|
||||||
FState * painstate = target->FindState(NAME_Pain, mod);
|
FState * painstate = target->FindState(NAME_Pain, mod);
|
||||||
if (painstate != NULL) target->SetState (painstate);
|
if (painstate != NULL) target->SetState (painstate);
|
||||||
if (mod == NAME_PoisonCloud)
|
if (mod == NAME_PoisonCloud)
|
||||||
|
@ -1345,6 +1340,11 @@ dopain:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// killough 11/98: Don't attack a friend, unless hit by that friend.
|
||||||
|
if (justhit && (target->target == source || !target->target || !target->IsFriend(target->target)))
|
||||||
|
target->flags |= MF_JUSTHIT; // fight back!
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AActor::OkayToSwitchTarget (AActor *other)
|
bool AActor::OkayToSwitchTarget (AActor *other)
|
||||||
|
|
|
@ -320,7 +320,7 @@ public:
|
||||||
#define PT_ADDLINES 1
|
#define PT_ADDLINES 1
|
||||||
#define PT_ADDTHINGS 2
|
#define PT_ADDTHINGS 2
|
||||||
|
|
||||||
AActor *P_BlockmapSearch (AActor *origin, int distance, AActor *(*func)(AActor *, int));
|
AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, int, void *), void *params = NULL);
|
||||||
AActor *P_RoughMonsterSearch (AActor *mo, int distance);
|
AActor *P_RoughMonsterSearch (AActor *mo, int distance);
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
#include "r_state.h"
|
#include "r_state.h"
|
||||||
#include "templates.h"
|
#include "templates.h"
|
||||||
|
|
||||||
static AActor *RoughBlockCheck (AActor *mo, int index);
|
static AActor *RoughBlockCheck (AActor *mo, int index, void *);
|
||||||
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -1278,7 +1278,7 @@ AActor *P_RoughMonsterSearch (AActor *mo, int distance)
|
||||||
return P_BlockmapSearch (mo, distance, RoughBlockCheck);
|
return P_BlockmapSearch (mo, distance, RoughBlockCheck);
|
||||||
}
|
}
|
||||||
|
|
||||||
AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, int))
|
AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, int, void *), void *params)
|
||||||
{
|
{
|
||||||
int blockX;
|
int blockX;
|
||||||
int blockY;
|
int blockY;
|
||||||
|
@ -1297,7 +1297,7 @@ AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, in
|
||||||
|
|
||||||
if (startX >= 0 && startX < bmapwidth && startY >= 0 && startY < bmapheight)
|
if (startX >= 0 && startX < bmapwidth && startY >= 0 && startY < bmapheight)
|
||||||
{
|
{
|
||||||
if ( (target = check (mo, startY*bmapwidth+startX)) )
|
if ( (target = check (mo, startY*bmapwidth+startX, params)) )
|
||||||
{ // found a target right away
|
{ // found a target right away
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
@ -1334,7 +1334,7 @@ AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, in
|
||||||
// Trace the first block section (along the top)
|
// Trace the first block section (along the top)
|
||||||
for (; blockIndex <= firstStop; blockIndex++)
|
for (; blockIndex <= firstStop; blockIndex++)
|
||||||
{
|
{
|
||||||
if ( (target = check (mo, blockIndex)) )
|
if ( (target = check (mo, blockIndex, params)) )
|
||||||
{
|
{
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
@ -1342,7 +1342,7 @@ AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, in
|
||||||
// Trace the second block section (right edge)
|
// Trace the second block section (right edge)
|
||||||
for (blockIndex--; blockIndex <= secondStop; blockIndex += bmapwidth)
|
for (blockIndex--; blockIndex <= secondStop; blockIndex += bmapwidth)
|
||||||
{
|
{
|
||||||
if ( (target = check (mo, blockIndex)) )
|
if ( (target = check (mo, blockIndex, params)) )
|
||||||
{
|
{
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
@ -1350,7 +1350,7 @@ AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, in
|
||||||
// Trace the third block section (bottom edge)
|
// Trace the third block section (bottom edge)
|
||||||
for (blockIndex -= bmapwidth; blockIndex >= thirdStop; blockIndex--)
|
for (blockIndex -= bmapwidth; blockIndex >= thirdStop; blockIndex--)
|
||||||
{
|
{
|
||||||
if ( (target = check (mo, blockIndex)) )
|
if ( (target = check (mo, blockIndex, params)) )
|
||||||
{
|
{
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
@ -1358,7 +1358,7 @@ AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, in
|
||||||
// Trace the final block section (left edge)
|
// Trace the final block section (left edge)
|
||||||
for (blockIndex++; blockIndex > finalStop; blockIndex -= bmapwidth)
|
for (blockIndex++; blockIndex > finalStop; blockIndex -= bmapwidth)
|
||||||
{
|
{
|
||||||
if ( (target = check (mo, blockIndex)) )
|
if ( (target = check (mo, blockIndex, params)) )
|
||||||
{
|
{
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
|
@ -1373,7 +1373,7 @@ AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, in
|
||||||
//
|
//
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
||||||
static AActor *RoughBlockCheck (AActor *mo, int index)
|
static AActor *RoughBlockCheck (AActor *mo, int index, void *)
|
||||||
{
|
{
|
||||||
FBlockNode *link;
|
FBlockNode *link;
|
||||||
|
|
||||||
|
|
754
zdoom.vcproj
754
zdoom.vcproj
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue