2008-09-15 14:11:05 +00:00
|
|
|
/*
|
2006-02-24 04:48:15 +00:00
|
|
|
#include "actor.h"
|
|
|
|
#include "info.h"
|
|
|
|
#include "p_local.h"
|
|
|
|
#include "m_random.h"
|
|
|
|
#include "s_sound.h"
|
|
|
|
#include "a_hexenglobal.h"
|
|
|
|
#include "gstrings.h"
|
2008-08-08 10:24:08 +00:00
|
|
|
#include "a_weaponpiece.h"
|
2008-08-10 20:48:55 +00:00
|
|
|
#include "thingdef/thingdef.h"
|
2008-09-14 23:54:38 +00:00
|
|
|
#include "g_level.h"
|
|
|
|
#include "doomstat.h"
|
2008-09-15 14:11:05 +00:00
|
|
|
*/
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
#define BLAST_FULLSTRENGTH 255
|
|
|
|
|
|
|
|
static FRandom pr_holyatk2 ("CHolyAtk2");
|
|
|
|
static FRandom pr_holyseeker ("CHolySeeker");
|
|
|
|
static FRandom pr_holyweave ("CHolyWeave");
|
|
|
|
static FRandom pr_holyseek ("CHolySeek");
|
|
|
|
static FRandom pr_checkscream ("CCheckScream");
|
|
|
|
static FRandom pr_spiritslam ("CHolySlam");
|
|
|
|
static FRandom pr_wraithvergedrop ("WraithvergeDrop");
|
|
|
|
|
|
|
|
void SpawnSpiritTail (AActor *spirit);
|
|
|
|
|
2006-06-17 20:29:41 +00:00
|
|
|
//==========================================================================
|
2006-02-24 04:48:15 +00:00
|
|
|
// Cleric's Wraithverge (Holy Symbol?) --------------------------------------
|
|
|
|
|
|
|
|
class ACWeapWraithverge : public AClericWeapon
|
|
|
|
{
|
2008-08-07 15:46:52 +00:00
|
|
|
DECLARE_CLASS (ACWeapWraithverge, AClericWeapon)
|
2006-02-24 04:48:15 +00:00
|
|
|
public:
|
|
|
|
void Serialize (FArchive &arc)
|
|
|
|
{
|
|
|
|
Super::Serialize (arc);
|
|
|
|
arc << CHolyCount;
|
|
|
|
}
|
|
|
|
PalEntry GetBlend ()
|
|
|
|
{
|
2012-04-22 07:58:04 +00:00
|
|
|
if (paletteflash & PF_HEXENWEAPONS)
|
|
|
|
{
|
|
|
|
if (CHolyCount == 3)
|
|
|
|
return PalEntry(128, 70, 70, 70);
|
|
|
|
else if (CHolyCount == 2)
|
|
|
|
return PalEntry(128, 100, 100, 100);
|
|
|
|
else if (CHolyCount == 1)
|
|
|
|
return PalEntry(128, 130, 130, 130);
|
|
|
|
else
|
|
|
|
return PalEntry(0, 0, 0, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return PalEntry (CHolyCount * 128 / 3, 131, 131, 131);
|
|
|
|
}
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
BYTE CHolyCount;
|
|
|
|
};
|
|
|
|
|
2008-08-05 16:04:37 +00:00
|
|
|
IMPLEMENT_CLASS (ACWeapWraithverge)
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
// Holy Spirit --------------------------------------------------------------
|
|
|
|
|
2008-08-05 16:04:37 +00:00
|
|
|
IMPLEMENT_CLASS (AHolySpirit)
|
2006-02-24 04:48:15 +00:00
|
|
|
|
|
|
|
bool AHolySpirit::Slam (AActor *thing)
|
|
|
|
{
|
|
|
|
if (thing->flags&MF_SHOOTABLE && thing != target)
|
|
|
|
{
|
|
|
|
if (multiplayer && !deathmatch && thing->player && target->player)
|
|
|
|
{ // don't attack other co-op players
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (thing->flags2&MF2_REFLECTIVE
|
|
|
|
&& (thing->player || thing->flags2&MF2_BOSS))
|
|
|
|
{
|
|
|
|
tracer = target;
|
|
|
|
target = thing;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (thing->flags3&MF3_ISMONSTER || thing->player)
|
|
|
|
{
|
|
|
|
tracer = thing;
|
|
|
|
}
|
|
|
|
if (pr_spiritslam() < 96)
|
|
|
|
{
|
|
|
|
int dam = 12;
|
|
|
|
if (thing->player || thing->flags2&MF2_BOSS)
|
|
|
|
{
|
|
|
|
dam = 3;
|
|
|
|
// ghost burns out faster when attacking players/bosses
|
|
|
|
health -= 6;
|
|
|
|
}
|
2006-10-31 14:53:21 +00:00
|
|
|
P_DamageMobj (thing, this, target, dam, NAME_Melee);
|
2006-02-24 04:48:15 +00:00
|
|
|
if (pr_spiritslam() < 128)
|
|
|
|
{
|
2008-08-05 16:04:37 +00:00
|
|
|
Spawn ("HolyPuff", x, y, z, ALLOW_REPLACE);
|
2006-02-24 04:48:15 +00:00
|
|
|
S_Sound (this, CHAN_WEAPON, "SpiritAttack", 1, ATTN_NORM);
|
|
|
|
if (thing->flags3&MF3_ISMONSTER && pr_spiritslam() < 128)
|
|
|
|
{
|
|
|
|
thing->Howl ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (thing->health <= 0)
|
|
|
|
{
|
|
|
|
tracer = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AHolySpirit::SpecialBlastHandling (AActor *source, fixed_t strength)
|
|
|
|
{
|
2012-06-17 10:28:55 +00:00
|
|
|
if (tracer == source)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
tracer = target;
|
|
|
|
target = source;
|
2008-03-12 02:56:11 +00:00
|
|
|
GC::WriteBarrier(this, source);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// A_CHolyAttack2
|
|
|
|
//
|
|
|
|
// Spawns the spirits
|
|
|
|
//============================================================================
|
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
DEFINE_ACTION_FUNCTION(AActor, A_CHolyAttack2)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
int j;
|
|
|
|
int i;
|
|
|
|
AActor *mo;
|
|
|
|
|
|
|
|
for (j = 0; j < 4; j++)
|
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
mo = Spawn<AHolySpirit> (self->x, self->y, self->z, ALLOW_REPLACE);
|
2006-02-24 04:48:15 +00:00
|
|
|
if (!mo)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
switch (j)
|
|
|
|
{ // float bob index
|
|
|
|
case 0:
|
2012-07-11 02:50:13 +00:00
|
|
|
mo->special2 = pr_holyatk2(8 << BOBTOFINESHIFT); // upper-left
|
2006-02-24 04:48:15 +00:00
|
|
|
break;
|
|
|
|
case 1:
|
2012-07-11 02:50:13 +00:00
|
|
|
mo->special2 = FINEANGLES/2 + pr_holyatk2(8 << BOBTOFINESHIFT); // upper-right
|
2006-02-24 04:48:15 +00:00
|
|
|
break;
|
|
|
|
case 2:
|
2012-07-11 02:50:13 +00:00
|
|
|
mo->special2 = (FINEANGLES/2 + pr_holyatk2(8 << BOBTOFINESHIFT)) << 16; // lower-left
|
2006-02-24 04:48:15 +00:00
|
|
|
break;
|
|
|
|
case 3:
|
2012-07-11 02:50:13 +00:00
|
|
|
i = pr_holyatk2(8 << BOBTOFINESHIFT);
|
|
|
|
mo->special2 = ((FINEANGLES/2 + i) << 16) + FINEANGLES/2 + pr_holyatk2(8 << BOBTOFINESHIFT);
|
2006-02-24 04:48:15 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-08-10 20:48:55 +00:00
|
|
|
mo->z = self->z;
|
|
|
|
mo->angle = self->angle+(ANGLE_45+ANGLE_45/2)-ANGLE_45*j;
|
2006-02-24 04:48:15 +00:00
|
|
|
P_ThrustMobj(mo, mo->angle, mo->Speed);
|
2008-08-10 20:48:55 +00:00
|
|
|
mo->target = self->target;
|
2006-02-24 04:48:15 +00:00
|
|
|
mo->args[0] = 10; // initial turn value
|
|
|
|
mo->args[1] = 0; // initial look angle
|
|
|
|
if (deathmatch)
|
|
|
|
{ // Ghosts last slightly less longer in DeathMatch
|
|
|
|
mo->health = 85;
|
|
|
|
}
|
2008-08-10 20:48:55 +00:00
|
|
|
if (self->tracer)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
mo->tracer = self->tracer;
|
2006-02-24 04:48:15 +00:00
|
|
|
mo->flags |= MF_NOCLIP|MF_SKULLFLY;
|
|
|
|
mo->flags &= ~MF_MISSILE;
|
|
|
|
}
|
|
|
|
SpawnSpiritTail (mo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// SpawnSpiritTail
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
|
|
|
void SpawnSpiritTail (AActor *spirit)
|
|
|
|
{
|
|
|
|
AActor *tail, *next;
|
|
|
|
int i;
|
|
|
|
|
2008-08-05 16:04:37 +00:00
|
|
|
tail = Spawn ("HolyTail", spirit->x, spirit->y, spirit->z, ALLOW_REPLACE);
|
2006-02-24 04:48:15 +00:00
|
|
|
tail->target = spirit; // parent
|
|
|
|
for (i = 1; i < 3; i++)
|
|
|
|
{
|
2008-08-05 16:04:37 +00:00
|
|
|
next = Spawn ("HolyTailTrail", spirit->x, spirit->y, spirit->z, ALLOW_REPLACE);
|
2006-02-24 04:48:15 +00:00
|
|
|
tail->tracer = next;
|
|
|
|
tail = next;
|
|
|
|
}
|
|
|
|
tail->tracer = NULL; // last tail bit
|
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// A_CHolyAttack
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
DEFINE_ACTION_FUNCTION(AActor, A_CHolyAttack)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
player_t *player;
|
2008-04-10 14:38:43 +00:00
|
|
|
AActor *linetarget;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
if (NULL == (player = self->player))
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2008-08-10 20:48:55 +00:00
|
|
|
ACWeapWraithverge *weapon = static_cast<ACWeapWraithverge *> (self->player->ReadyWeapon);
|
2006-02-24 04:48:15 +00:00
|
|
|
if (weapon != NULL)
|
|
|
|
{
|
|
|
|
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
|
|
|
return;
|
|
|
|
}
|
2008-08-10 20:48:55 +00:00
|
|
|
AActor * missile = P_SpawnPlayerMissile (self, 0,0,0, PClass::FindClass ("HolyMissile"), self->angle, &linetarget);
|
2006-04-18 22:15:05 +00:00
|
|
|
if (missile != NULL) missile->tracer = linetarget;
|
|
|
|
|
2006-02-24 04:48:15 +00:00
|
|
|
weapon->CHolyCount = 3;
|
2008-08-10 20:48:55 +00:00
|
|
|
S_Sound (self, CHAN_WEAPON, "HolySymbolFire", 1, ATTN_NORM);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// A_CHolyPalette
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
DEFINE_ACTION_FUNCTION(AActor, A_CHolyPalette)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
if (self->player != NULL)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
ACWeapWraithverge *weapon = static_cast<ACWeapWraithverge *> (self->player->ReadyWeapon);
|
2006-02-24 04:48:15 +00:00
|
|
|
if (weapon != NULL && weapon->CHolyCount != 0)
|
|
|
|
{
|
|
|
|
weapon->CHolyCount--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// CHolyTailFollow
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
|
|
|
static void CHolyTailFollow (AActor *actor, fixed_t dist)
|
|
|
|
{
|
|
|
|
AActor *child;
|
|
|
|
int an;
|
|
|
|
fixed_t oldDistance, newDistance;
|
|
|
|
|
|
|
|
while (actor)
|
|
|
|
{
|
|
|
|
child = actor->tracer;
|
|
|
|
if (child)
|
|
|
|
{
|
|
|
|
an = R_PointToAngle2(actor->x, actor->y, child->x,
|
|
|
|
child->y)>>ANGLETOFINESHIFT;
|
2016-01-10 16:52:41 +00:00
|
|
|
oldDistance = child->AproxDistance (actor);
|
2006-02-24 04:48:15 +00:00
|
|
|
if (P_TryMove (child, actor->x+FixedMul(dist, finecosine[an]),
|
|
|
|
actor->y+FixedMul(dist, finesine[an]), true))
|
|
|
|
{
|
2016-01-10 16:52:41 +00:00
|
|
|
newDistance = child->AproxDistance (actor)-FRACUNIT;
|
2006-02-24 04:48:15 +00:00
|
|
|
if (oldDistance < FRACUNIT)
|
|
|
|
{
|
|
|
|
if (child->z < actor->z)
|
|
|
|
{
|
|
|
|
child->z = actor->z-dist;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
child->z = actor->z+dist;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
child->z = actor->z + Scale (newDistance, child->z-actor->z, oldDistance);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
actor = child;
|
|
|
|
dist -= FRACUNIT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// CHolyTailRemove
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
|
|
|
static void CHolyTailRemove (AActor *actor)
|
|
|
|
{
|
|
|
|
AActor *next;
|
|
|
|
|
|
|
|
while (actor)
|
|
|
|
{
|
|
|
|
next = actor->tracer;
|
|
|
|
actor->Destroy ();
|
|
|
|
actor = next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// A_CHolyTail
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
DEFINE_ACTION_FUNCTION(AActor, A_CHolyTail)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
AActor *parent;
|
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
parent = self->target;
|
2006-02-24 04:48:15 +00:00
|
|
|
|
2006-10-31 14:53:21 +00:00
|
|
|
if (parent == NULL || parent->health <= 0) // better check for health than current state - it's safer!
|
2006-02-24 04:48:15 +00:00
|
|
|
{ // Ghost removed, so remove all tail parts
|
2008-08-10 20:48:55 +00:00
|
|
|
CHolyTailRemove (self);
|
2006-02-24 04:48:15 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
if (P_TryMove (self,
|
2006-02-24 04:48:15 +00:00
|
|
|
parent->x - 14*finecosine[parent->angle>>ANGLETOFINESHIFT],
|
|
|
|
parent->y - 14*finesine[parent->angle>>ANGLETOFINESHIFT], true))
|
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
self->z = parent->z-5*FRACUNIT;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2008-08-10 20:48:55 +00:00
|
|
|
CHolyTailFollow (self, 10*FRACUNIT);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// CHolyFindTarget
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
|
|
|
static void CHolyFindTarget (AActor *actor)
|
|
|
|
{
|
|
|
|
AActor *target;
|
|
|
|
|
2012-04-19 03:22:06 +00:00
|
|
|
if ( (target = P_RoughMonsterSearch (actor, 6, true)) )
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
actor->tracer = target;
|
|
|
|
actor->flags |= MF_NOCLIP|MF_SKULLFLY;
|
|
|
|
actor->flags &= ~MF_MISSILE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// CHolySeekerMissile
|
|
|
|
//
|
|
|
|
// Similar to P_SeekerMissile, but seeks to a random Z on the target
|
|
|
|
//============================================================================
|
|
|
|
|
|
|
|
static void CHolySeekerMissile (AActor *actor, angle_t thresh, angle_t turnMax)
|
|
|
|
{
|
|
|
|
int dir;
|
|
|
|
int dist;
|
|
|
|
angle_t delta;
|
|
|
|
angle_t angle;
|
|
|
|
AActor *target;
|
|
|
|
fixed_t newZ;
|
|
|
|
fixed_t deltaZ;
|
|
|
|
|
|
|
|
target = actor->tracer;
|
|
|
|
if (target == NULL)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(!(target->flags&MF_SHOOTABLE)
|
|
|
|
|| (!(target->flags3&MF3_ISMONSTER) && !target->player))
|
|
|
|
{ // Target died/target isn't a player or creature
|
|
|
|
actor->tracer = NULL;
|
|
|
|
actor->flags &= ~(MF_NOCLIP|MF_SKULLFLY);
|
|
|
|
actor->flags |= MF_MISSILE;
|
|
|
|
CHolyFindTarget (actor);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
dir = P_FaceMobj (actor, target, &delta);
|
|
|
|
if (delta > thresh)
|
|
|
|
{
|
|
|
|
delta >>= 1;
|
|
|
|
if (delta > turnMax)
|
|
|
|
{
|
|
|
|
delta = turnMax;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (dir)
|
|
|
|
{ // Turn clockwise
|
|
|
|
actor->angle += delta;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // Turn counter clockwise
|
|
|
|
actor->angle -= delta;
|
|
|
|
}
|
|
|
|
angle = actor->angle>>ANGLETOFINESHIFT;
|
2009-06-30 20:57:51 +00:00
|
|
|
actor->velx = FixedMul (actor->Speed, finecosine[angle]);
|
|
|
|
actor->vely = FixedMul (actor->Speed, finesine[angle]);
|
2006-02-24 04:48:15 +00:00
|
|
|
if (!(level.time&15)
|
|
|
|
|| actor->z > target->z+(target->height)
|
|
|
|
|| actor->z+actor->height < target->z)
|
|
|
|
{
|
|
|
|
newZ = target->z+((pr_holyseeker()*target->height)>>8);
|
|
|
|
deltaZ = newZ-actor->z;
|
|
|
|
if (abs(deltaZ) > 15*FRACUNIT)
|
|
|
|
{
|
|
|
|
if (deltaZ > 0)
|
|
|
|
{
|
|
|
|
deltaZ = 15*FRACUNIT;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
deltaZ = -15*FRACUNIT;
|
|
|
|
}
|
|
|
|
}
|
2016-01-10 16:52:41 +00:00
|
|
|
dist = actor->AproxDistance (target);
|
2006-02-24 04:48:15 +00:00
|
|
|
dist = dist / actor->Speed;
|
|
|
|
if (dist < 1)
|
|
|
|
{
|
|
|
|
dist = 1;
|
|
|
|
}
|
2009-06-30 20:57:51 +00:00
|
|
|
actor->velz = deltaZ / dist;
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// A_CHolyWeave
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
2012-05-07 06:14:48 +00:00
|
|
|
void CHolyWeave (AActor *actor, FRandom &pr_random)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
|
|
|
fixed_t newX, newY;
|
|
|
|
int weaveXY, weaveZ;
|
|
|
|
int angle;
|
|
|
|
|
2012-07-11 02:50:13 +00:00
|
|
|
weaveXY = actor->special2 >> 16;
|
|
|
|
weaveZ = actor->special2 & FINEMASK;
|
|
|
|
angle = (actor->angle + ANG90) >> ANGLETOFINESHIFT;
|
|
|
|
newX = actor->x - FixedMul(finecosine[angle], finesine[weaveXY] * 32);
|
|
|
|
newY = actor->y - FixedMul(finesine[angle], finesine[weaveXY] * 32);
|
|
|
|
weaveXY = (weaveXY + pr_random(5 << BOBTOFINESHIFT)) & FINEMASK;
|
|
|
|
newX += FixedMul(finecosine[angle], finesine[weaveXY] * 32);
|
|
|
|
newY += FixedMul(finesine[angle], finesine[weaveXY] * 32);
|
2006-02-24 04:48:15 +00:00
|
|
|
P_TryMove(actor, newX, newY, true);
|
2012-07-11 02:50:13 +00:00
|
|
|
actor->z -= finesine[weaveZ] * 16;
|
|
|
|
weaveZ = (weaveZ + pr_random(5 << BOBTOFINESHIFT)) & FINEMASK;
|
|
|
|
actor->z += finesine[weaveZ] * 16;
|
|
|
|
actor->special2 = weaveZ + (weaveXY << 16);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// A_CHolySeek
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
DEFINE_ACTION_FUNCTION(AActor, A_CHolySeek)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
self->health--;
|
|
|
|
if (self->health <= 0)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2009-06-30 20:57:51 +00:00
|
|
|
self->velx >>= 2;
|
|
|
|
self->vely >>= 2;
|
|
|
|
self->velz = 0;
|
2008-08-10 20:48:55 +00:00
|
|
|
self->SetState (self->FindState(NAME_Death));
|
|
|
|
self->tics -= pr_holyseek()&3;
|
2006-02-24 04:48:15 +00:00
|
|
|
return;
|
|
|
|
}
|
2008-08-10 20:48:55 +00:00
|
|
|
if (self->tracer)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
CHolySeekerMissile (self, self->args[0]*ANGLE_1,
|
|
|
|
self->args[0]*ANGLE_1*2);
|
2006-02-24 04:48:15 +00:00
|
|
|
if (!((level.time+7)&15))
|
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
self->args[0] = 5+(pr_holyseek()/20);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
2012-05-07 06:14:48 +00:00
|
|
|
CHolyWeave (self, pr_holyweave);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// A_CHolyCheckScream
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
DEFINE_ACTION_FUNCTION(AActor, A_CHolyCheckScream)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-08-10 22:48:37 +00:00
|
|
|
CALL_ACTION(A_CHolySeek, self);
|
2006-02-24 04:48:15 +00:00
|
|
|
if (pr_checkscream() < 20)
|
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
S_Sound (self, CHAN_VOICE, "SpiritActive", 1, ATTN_NORM);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
2008-08-10 20:48:55 +00:00
|
|
|
if (!self->tracer)
|
2006-02-24 04:48:15 +00:00
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
CHolyFindTarget(self);
|
2006-02-24 04:48:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-03 16:13:23 +00:00
|
|
|
//============================================================================
|
|
|
|
//
|
|
|
|
// A_ClericAttack
|
|
|
|
// (for the ClericBoss)
|
|
|
|
//
|
|
|
|
//============================================================================
|
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
DEFINE_ACTION_FUNCTION(AActor, A_ClericAttack)
|
2008-08-03 16:13:23 +00:00
|
|
|
{
|
2008-08-10 20:48:55 +00:00
|
|
|
if (!self->target) return;
|
2008-08-03 16:13:23 +00:00
|
|
|
|
2008-08-10 20:48:55 +00:00
|
|
|
AActor * missile = P_SpawnMissileZ (self, self->z + 40*FRACUNIT, self->target, PClass::FindClass ("HolyMissile"));
|
|
|
|
if (missile != NULL) missile->tracer = NULL; // No initial target
|
|
|
|
S_Sound (self, CHAN_WEAPON, "HolySymbolFire", 1, ATTN_NORM);
|
2008-08-05 23:45:03 +00:00
|
|
|
}
|
2008-08-10 20:48:55 +00:00
|
|
|
|