- Added customizable border textures. They will be defined with the

MAPINFO keyword 'bordertexture' and are settable per map.
- Fixed: When used in DECORATE A_Explode must use A_ExplodeParms.
- Added custom label support to A_Chase. To enable resurrection from the
  customizable version I also moved all A_VileChase stuff into p_enemy.cpp.


SVN r437 (trunk)
This commit is contained in:
Christoph Oelckers 2007-01-05 22:08:57 +00:00
commit ec2e63c6d3
15 changed files with 294 additions and 213 deletions

View file

@ -43,6 +43,7 @@
#include "a_sharedglobal.h"
#include "a_doomglobal.h"
#include "a_action.h"
#include "thingdef.h"
#include "gi.h"
@ -1753,14 +1754,12 @@ nosee:
}
}
/*
==============
=
= A_Chase
=
= Actor has a melee attack, so it tries to close as fast as possible
=
*/
//=============================================================================
//
// A_Chase
//
// Actor has a melee attack, so it tries to close as fast as possible
//
// [GrafZahl] integrated A_FastChase, A_SerpentChase and A_SerpentWalk into this
// to allow the monsters using those functions to take advantage of the
// enhancements.
@ -2097,9 +2096,206 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi
actor->flags &= ~MF_INCHASE;
}
//==========================================================================
//
// PIT_VileCheck
//
//==========================================================================
static AActor *corpsehit;
static AActor *vileobj;
static fixed_t viletryx;
static fixed_t viletryy;
static FState *raisestate;
static bool PIT_VileCheck (AActor *thing)
{
int maxdist;
bool check;
if (!(thing->flags & MF_CORPSE) )
return true; // not a monster
if (thing->tics != -1)
return true; // not lying still yet
raisestate = thing->FindState(NAME_Raise);
if (raisestate == NULL)
return true; // monster doesn't have a raise state
// This may be a potential problem if this is used by something other
// than an Arch Vile.
//maxdist = thing->GetDefault()->radius + GetDefault<AArchvile>()->radius;
// use the current actor's radius instead of the Arch Vile's default.
maxdist = thing->GetDefault()->radius + vileobj->radius;
if ( abs(thing->x - viletryx) > maxdist
|| abs(thing->y - viletryy) > maxdist )
return true; // not actually touching
corpsehit = thing;
corpsehit->momx = corpsehit->momy = 0;
// [RH] Check against real height and radius
fixed_t oldheight = corpsehit->height;
fixed_t oldradius = corpsehit->radius;
int oldflags = corpsehit->flags;
corpsehit->flags |= MF_SOLID;
corpsehit->height = corpsehit->GetDefault()->height;
check = P_CheckPosition (corpsehit, corpsehit->x, corpsehit->y);
corpsehit->flags = oldflags;
corpsehit->radius = oldradius;
corpsehit->height = oldheight;
return !check;
}
//==========================================================================
//
// P_CheckForResurrection (formerly part of A_VileChase)
// Check for ressurecting a body
//
//==========================================================================
static bool P_CheckForResurrection(AActor *self, bool usevilestates)
{
static TArray<AActor *> vilebt;
int xl, xh, yl, yh;
int bx, by;
const AActor *info;
AActor *temp;
if (self->movedir != DI_NODIR)
{
const fixed_t absSpeed = abs (self->Speed);
// check for corpses to raise
viletryx = self->x + FixedMul (absSpeed, xspeed[self->movedir]);
viletryy = self->y + FixedMul (absSpeed, yspeed[self->movedir]);
xl = (viletryx - bmaporgx - MAXRADIUS*2)>>MAPBLOCKSHIFT;
xh = (viletryx - bmaporgx + MAXRADIUS*2)>>MAPBLOCKSHIFT;
yl = (viletryy - bmaporgy - MAXRADIUS*2)>>MAPBLOCKSHIFT;
yh = (viletryy - bmaporgy + MAXRADIUS*2)>>MAPBLOCKSHIFT;
vileobj = self;
validcount++;
vilebt.Clear();
for (bx = xl; bx <= xh; bx++)
{
for (by = yl; by <= yh; by++)
{
// Call PIT_VileCheck to check
// whether object is a corpse
// that can be raised.
if (!P_BlockThingsIterator (bx, by, PIT_VileCheck, vilebt))
{
// got one!
temp = self->target;
self->target = corpsehit;
A_FaceTarget (self);
if (self->flags & MF_FRIENDLY)
{
// If this is a friendly Arch-Vile (which is turning the resurrected monster into its friend)
// and the Arch-Vile is currently targetting the resurrected monster the target must be cleared.
if (self->lastenemy == temp) self->lastenemy = NULL;
if (temp == self->target) temp = NULL;
}
self->target = temp;
// Make the state the monster enters customizable.
FState * state = self->FindState(NAME_Heal);
if (state != NULL)
{
self->SetState (state);
}
else if (usevilestates)
{
// For Dehacked compatibility this has to use the Arch Vile's
// heal state as a default if the actor doesn't define one itself.
const PClass *archvile = PClass::FindClass("Archvile");
if (archvile != NULL)
{
self->SetState (archvile->ActorInfo->FindState(NAME_Heal));
}
}
S_Sound (corpsehit, CHAN_BODY, "vile/raise", 1, ATTN_IDLE);
info = corpsehit->GetDefault ();
corpsehit->SetState (raisestate);
corpsehit->height = info->height; // [RH] Use real mobj height
corpsehit->radius = info->radius; // [RH] Use real radius
/*
// Make raised corpses look ghostly
if (corpsehit->alpha > TRANSLUC50)
corpsehit->alpha /= 2;
*/
corpsehit->flags = info->flags;
corpsehit->flags2 = info->flags2;
corpsehit->flags3 = info->flags3;
corpsehit->flags4 = info->flags4;
corpsehit->health = info->health;
corpsehit->target = NULL;
corpsehit->lastenemy = NULL;
// [RH] If it's a monster, it gets to count as another kill
if (corpsehit->CountsAsKill())
{
level.total_monsters++;
}
// You are the Archvile's minion now, so hate what it hates
corpsehit->CopyFriendliness (self, false);
return true;
}
}
}
}
return false;
}
//==========================================================================
//
// A_Chase and variations
//
//==========================================================================
enum ChaseFlags
{
CHF_FASTCHASE = 1,
CHF_NOPLAYACTIVE = 2,
CHF_NIGHTMAREFAST = 4,
CHF_RESURRECT = 8
};
void A_Chase (AActor *actor)
{
A_DoChase (actor, false, actor->MeleeState, actor->MissileState, true, !!(gameinfo.gametype & GAME_Raven));
int index=CheckIndex(3, &CallingState);
if (index>=0)
{
int flags = EvalExpressionI (StateParameters[index+2], actor);
if (flags & CHF_RESURRECT && P_CheckForResurrection(actor, false)) return;
FState *melee = StateParameters[index]==0? NULL : P_GetState(actor, CallingState, StateParameters[index]);
FState *missile = StateParameters[index+1]==0? NULL : P_GetState(actor, CallingState, StateParameters[index+1]);
A_DoChase(actor, !!(flags&CHF_FASTCHASE), melee, missile, !(flags&CHF_NOPLAYACTIVE),
!!(flags&CHF_NIGHTMAREFAST));
}
else // this is the old default A_Chase
{
A_DoChase (actor, false, actor->MeleeState, actor->MissileState, true, !!(gameinfo.gametype & GAME_Raven));
}
}
void A_FastChase (AActor *actor)
@ -2107,6 +2303,25 @@ void A_FastChase (AActor *actor)
A_DoChase (actor, true, actor->MeleeState, actor->MissileState, true, true);
}
void A_VileChase (AActor *actor)
{
if (!P_CheckForResurrection(actor, true))
A_DoChase (actor, false, actor->MeleeState, actor->MissileState, true, !!(gameinfo.gametype & GAME_Raven));
}
void A_ExtChase(AActor * self)
{
// Now that A_Chase can handle state label parameters, this function has become rather useless...
int index=CheckIndex(4, &CallingState);
if (index<0) return;
A_DoChase(self, false,
EvalExpressionI (StateParameters[index], self) ? self->MeleeState:NULL,
EvalExpressionI (StateParameters[index+1], self) ? self->MissileState:NULL,
EvalExpressionN (StateParameters[index+2], self),
!!EvalExpressionI (StateParameters[index+3], self));
}
//=============================================================================
//
// A_FaceTarget