- refactored most of Heretic's game code.

This commit is contained in:
Christoph Oelckers 2016-01-18 20:13:20 +01:00
parent 57ab1387f2
commit 460751653d
8 changed files with 93 additions and 87 deletions

View File

@ -847,7 +847,7 @@ public:
bool intersects(AActor *other) const
{
fixed_t blockdist = radius + other->radius;
return ( abs(x - other->x) < blockdist && abs(y - other->y) < blockdist);
return ( abs(pos.x - other->pos.x) < blockdist && abs(pos.y - other->pos.y) < blockdist);
}
PalEntry GetBloodColor() const
@ -888,99 +888,99 @@ public:
// to distinguish between portal-aware and portal-unaware distance calculation.
fixed_t AproxDistance(AActor *other, bool absolute = false)
{
return P_AproxDistance(x - other->x, y - other->y);
return P_AproxDistance(pos.x - other->pos.x, pos.y - other->pos.y);
}
// same with 'ref' here.
fixed_t AproxDistance(fixed_t otherx, fixed_t othery, AActor *ref = NULL)
{
return P_AproxDistance(x - otherx, y - othery);
return P_AproxDistance(pos.x - otherx, pos.y - othery);
}
fixed_t AproxDistance(AActor *other, fixed_t xadd, fixed_t yadd, bool absolute = false)
{
return P_AproxDistance(x - other->x + xadd, y - other->y + yadd);
return P_AproxDistance(pos.x - other->pos.x + xadd, pos.y - other->pos.y + yadd);
}
fixed_t AproxDistance3D(AActor *other, bool absolute = false)
{
return P_AproxDistance(AproxDistance(other), z - other->z);
return P_AproxDistance(AproxDistance(other), pos.z - other->pos.z);
}
// more precise, but slower version, being used in a few places
fixed_t Distance2D(AActor *other, bool absolute = false)
{
return xs_RoundToInt(FVector2(x - other->x, y - other->y).Length());
return xs_RoundToInt(FVector2(pos.x - other->pos.x, pos.y - other->pos.y).Length());
}
// a full 3D version of the above
fixed_t Distance3D(AActor *other, bool absolute = false)
{
return xs_RoundToInt(FVector3(x - other->x, y - other->y, z - other->z).Length());
return xs_RoundToInt(FVector3(pos.x - other->pos.x, pos.y - other->pos.y, pos.z - other->pos.z).Length());
}
angle_t AngleTo(AActor *other, bool absolute = false) const
{
return R_PointToAngle2(x, y, other->x, other->y);
return R_PointToAngle2(pos.x, pos.y, other->pos.x, other->pos.y);
}
angle_t AngleTo(AActor *other, fixed_t oxofs, fixed_t oyofs, bool absolute = false) const
{
return R_PointToAngle2(x, y, other->x + oxofs, other->y + oyofs);
return R_PointToAngle2(pos.x, pos.y, other->pos.x + oxofs, other->pos.y + oyofs);
}
fixed_t AngleTo(fixed_t otherx, fixed_t othery, AActor *ref = NULL)
{
return R_PointToAngle2(x, y, otherx, othery);
return R_PointToAngle2(pos.x, pos.y, otherx, othery);
}
fixed_t AngleXYTo(fixed_t myx, fixed_t myy, AActor *other, bool absolute = false)
{
return R_PointToAngle2(myx, myy, other->x, other->y);
return R_PointToAngle2(myx, myy, other->pos.x, other->pos.y);
}
fixedvec2 Vec2To(AActor *other) const
{
fixedvec2 ret = { other->x - x, other->y - y };
fixedvec2 ret = { other->pos.x - pos.x, other->pos.y - pos.y };
return ret;
}
fixedvec3 Vec3To(AActor *other) const
{
fixedvec3 ret = { other->x - x, other->y - y, other->z - z };
fixedvec3 ret = { other->pos.x - pos.x, other->pos.y - pos.y, other->pos.z - pos.z };
return ret;
}
fixedvec2 Vec2Offset(fixed_t dx, fixed_t dy, bool absolute = false) const
{
fixedvec2 ret = { x + dx, y + dy };
fixedvec2 ret = { pos.x + dx, pos.y + dy };
return ret;
}
fixedvec2 Vec2Angle(fixed_t length, angle_t angle, bool absolute = false) const
{
fixedvec2 ret = { x + FixedMul(length, finecosine[angle >> ANGLETOFINESHIFT]),
y + FixedMul(length, finesine[angle >> ANGLETOFINESHIFT]) };
fixedvec2 ret = { pos.x + FixedMul(length, finecosine[angle >> ANGLETOFINESHIFT]),
pos.y + FixedMul(length, finesine[angle >> ANGLETOFINESHIFT]) };
return ret;
}
fixedvec3 Vec3Offset(fixed_t dx, fixed_t dy, fixed_t dz, bool absolute = false) const
{
fixedvec3 ret = { x + dx, y + dy, z + dz };
fixedvec3 ret = { pos.x + dx, pos.y + dy, pos.z + dz };
return ret;
}
fixedvec3 Vec3Angle(fixed_t length, angle_t angle, fixed_t dz, bool absolute = false) const
{
fixedvec3 ret = { x + FixedMul(length, finecosine[angle >> ANGLETOFINESHIFT]),
y + FixedMul(length, finesine[angle >> ANGLETOFINESHIFT]), z + dz };
fixedvec3 ret = { pos.x + FixedMul(length, finecosine[angle >> ANGLETOFINESHIFT]),
pos.y + FixedMul(length, finesine[angle >> ANGLETOFINESHIFT]), pos.z + dz };
return ret;
}
void Move(fixed_t dx, fixed_t dy, fixed_t dz)
{
SetOrigin(x + dx, y + dy, z + dz, true);
SetOrigin(pos.x + dx, pos.y + dy, pos.z + dz, true);
}
void SetOrigin(const fixedvec3 & npos, bool moving)
@ -1007,7 +1007,10 @@ public:
// info for drawing
// NOTE: The first member variable *must* be x.
fixed_t x,y,z;
private:
fixedvec3 pos;
public:
//fixed_t x,y,z;
AActor *snext, **sprev; // links in sector (if needed)
angle_t angle;
WORD sprite; // used to find patch_t and flip value
@ -1205,7 +1208,7 @@ public:
void LinkToWorld (sector_t *sector);
void UnlinkFromWorld ();
void AdjustFloorClip ();
void SetOrigin (fixed_t x, fixed_t y, fixed_t z, bool moving = false);
void SetOrigin (fixed_t x, fixed_t y, fixed_t z, bool moving);
bool InStateSequence(FState * newstate, FState * basestate);
int GetTics(FState * newstate);
bool SetState (FState *newstate, bool nofunction=false);
@ -1237,15 +1240,15 @@ public:
fixed_t X() const
{
return x;
return pos.x;
}
fixed_t Y() const
{
return y;
return pos.y;
}
fixed_t Z() const
{
return z;
return pos.z;
}
fixedvec3 Pos() const
{
@ -1254,24 +1257,24 @@ public:
}
fixed_t Top() const
{
return z + height;
return pos.z + height;
}
void SetZ(fixed_t newz, bool moving = true)
{
z = newz;
pos.z = newz;
}
// These are not for general use as they do not link the actor into the world!
void SetXY(fixed_t xx, fixed_t yy)
void SetXY(fixed_t x, fixed_t y)
{
x = xx;
y = yy;
pos.x = x;
pos.y = y;
}
void SetXYZ(fixed_t xx, fixed_t yy, fixed_t zz)
void SetXYZ(fixed_t x, fixed_t y, fixed_t z)
{
x = xx;
y = yy;
z = zz;
pos.x = x;
pos.y = y;
pos.z = z;
}
};

View File

@ -45,7 +45,7 @@ void AChickenPlayer::MorphPlayerThink ()
{ // Twitch view angle
angle += pr_chickenplayerthink.Random2 () << 19;
}
if ((z <= floorz) && (pr_chickenplayerthink() < 32))
if ((Z() <= floorz) && (pr_chickenplayerthink() < 32))
{ // Jump and noise
velz += JumpZ;
@ -100,7 +100,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Feathers)
}
for (i = 0; i < count; i++)
{
mo = Spawn("Feather", self->x, self->y, self->z+20*FRACUNIT, NO_REPLACE);
mo = Spawn("Feather", self->X(), self->Y(), self->Z()+20*FRACUNIT, NO_REPLACE);
mo->target = self;
mo->velx = pr_feathers.Random2() << 8;
mo->vely = pr_feathers.Random2() << 8;

View File

@ -78,17 +78,17 @@ DEFINE_ACTION_FUNCTION(AActor, A_Srcr1Attack)
const PClass *fx = PClass::FindClass("SorcererFX1");
if (self->health > (self->SpawnHealth()/3)*2)
{ // Spit one fireball
P_SpawnMissileZ (self, self->z + 48*FRACUNIT, self->target, fx );
P_SpawnMissileZ (self, self->Z() + 48*FRACUNIT, self->target, fx );
}
else
{ // Spit three fireballs
mo = P_SpawnMissileZ (self, self->z + 48*FRACUNIT, self->target, fx);
mo = P_SpawnMissileZ (self, self->Z() + 48*FRACUNIT, self->target, fx);
if (mo != NULL)
{
velz = mo->velz;
angle = mo->angle;
P_SpawnMissileAngleZ (self, self->z + 48*FRACUNIT, fx, angle-ANGLE_1*3, velz);
P_SpawnMissileAngleZ (self, self->z + 48*FRACUNIT, fx, angle+ANGLE_1*3, velz);
P_SpawnMissileAngleZ (self, self->Z() + 48*FRACUNIT, fx, angle-ANGLE_1*3, velz);
P_SpawnMissileAngleZ (self, self->Z() + 48*FRACUNIT, fx, angle+ANGLE_1*3, velz);
}
if (self->health < self->SpawnHealth()/3)
{ // Maybe attack again
@ -116,7 +116,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SorcererRise)
AActor *mo;
self->flags &= ~MF_SOLID;
mo = Spawn("Sorcerer2", self->x, self->y, self->z, ALLOW_REPLACE);
mo = Spawn("Sorcerer2", self->Pos(), ALLOW_REPLACE);
mo->Translation = self->Translation;
mo->SetState (mo->FindState("Rise"));
mo->angle = self->angle;

View File

@ -41,12 +41,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_ImpExplode)
self->flags &= ~MF_NOGRAVITY;
chunk = Spawn("HereticImpChunk1", self->x, self->y, self->z, ALLOW_REPLACE);
chunk = Spawn("HereticImpChunk1", self->Pos(), ALLOW_REPLACE);
chunk->velx = pr_imp.Random2 () << 10;
chunk->vely = pr_imp.Random2 () << 10;
chunk->velz = 9*FRACUNIT;
chunk = Spawn("HereticImpChunk2", self->x, self->y, self->z, ALLOW_REPLACE);
chunk = Spawn("HereticImpChunk2", self->Pos(), ALLOW_REPLACE);
chunk->velx = pr_imp.Random2 () << 10;
chunk->vely = pr_imp.Random2 () << 10;
chunk->velz = 9*FRACUNIT;

View File

@ -57,7 +57,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_PodPain)
}
for (count = chance > 240 ? 2 : 1; count; count--)
{
goo = Spawn(gootype, self->x, self->y, self->z + 48*FRACUNIT, ALLOW_REPLACE);
goo = Spawn(gootype, self->X(), self->Y(), self->Z() + 48*FRACUNIT, ALLOW_REPLACE);
goo->target = self;
goo->velx = pr_podpain.Random2() << 9;
goo->vely = pr_podpain.Random2() << 9;

View File

@ -382,14 +382,13 @@ void FireMacePL1B (AActor *actor)
if (!weapon->DepleteAmmo (weapon->bAltFire))
return;
}
ball = Spawn("MaceFX2", actor->x, actor->y, actor->z + 28*FRACUNIT
- actor->floorclip, ALLOW_REPLACE);
ball = Spawn("MaceFX2", actor->X(), actor->Y(), actor->Z() + 28*FRACUNIT - actor->floorclip, ALLOW_REPLACE);
ball->velz = 2*FRACUNIT+/*((player->lookdir)<<(FRACBITS-5))*/
finetangent[FINEANGLES/4-(actor->pitch>>ANGLETOFINESHIFT)];
angle = actor->angle;
ball->target = actor;
ball->angle = angle;
ball->z += 2*finetangent[FINEANGLES/4-(actor->pitch>>ANGLETOFINESHIFT)];
ball->SetZ(ball->Z() + 2*finetangent[FINEANGLES/4-(actor->pitch>>ANGLETOFINESHIFT)]);
angle >>= ANGLETOFINESHIFT;
ball->velx = (actor->velx>>1) + FixedMul(ball->Speed, finecosine[angle]);
ball->vely = (actor->vely>>1) + FixedMul(ball->Speed, finesine[angle]);
@ -508,10 +507,12 @@ DEFINE_ACTION_FUNCTION(AActor, A_MaceBallImpact2)
if (self->flags & MF_INBOUNCE)
{
fixed_t floordist = self->z - self->floorz;
fixed_t ceildist = self->ceilingz - self->z;
fixed_t floordist = self->Z() - self->floorz;
fixed_t ceildist = self->ceilingz - self->Z();
fixed_t vel;
// NOTE: The assumptions being made here about the plane to use for bouncing off are dead wrong.
// http://forum.zdoom.org/viewtopic.php?f=2&t=50449
if (floordist <= ceildist)
{
vel = MulScale32 (self->velz, self->Sector->floorplane.c);
@ -529,7 +530,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MaceBallImpact2)
self->velz = (self->velz * 192) >> 8;
self->SetState (self->SpawnState);
tiny = Spawn("MaceFX3", self->x, self->y, self->z, ALLOW_REPLACE);
tiny = Spawn("MaceFX3", self->Pos(), ALLOW_REPLACE);
angle = self->angle+ANG90;
tiny->target = self->target;
tiny->angle = angle;
@ -539,7 +540,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MaceBallImpact2)
tiny->velz = self->velz;
P_CheckMissileSpawn (tiny, self->radius);
tiny = Spawn("MaceFX3", self->x, self->y, self->z, ALLOW_REPLACE);
tiny = Spawn("MaceFX3", self->Pos(), ALLOW_REPLACE);
angle = self->angle-ANG90;
tiny->target = self->target;
tiny->angle = angle;
@ -611,17 +612,19 @@ DEFINE_ACTION_FUNCTION(AActor, A_DeathBallImpact)
bool newAngle;
AActor *linetarget;
if ((self->z <= self->floorz) && P_HitFloor (self))
if ((self->Z() <= self->floorz) && P_HitFloor (self))
{ // Landed in some sort of liquid
self->Destroy ();
return;
}
if (self->flags & MF_INBOUNCE)
{
fixed_t floordist = self->z - self->floorz;
fixed_t ceildist = self->ceilingz - self->z;
fixed_t floordist = self->Z() - self->floorz;
fixed_t ceildist = self->ceilingz - self->Z();
fixed_t vel;
// NOTE: The assumptions being made here about the plane to use for bouncing off are dead wrong.
// http://forum.zdoom.org/viewtopic.php?f=2&t=50449
if (floordist <= ceildist)
{
vel = MulScale32 (self->velz, self->Sector->floorplane.c);
@ -720,7 +723,7 @@ void ABlasterFX1::Effect ()
{
if (pr_bfx1t() < 64)
{
Spawn("BlasterSmoke", x, y, MAX<fixed_t> (z - 8 * FRACUNIT, floorz), ALLOW_REPLACE);
Spawn("BlasterSmoke", X(), Y(), MAX<fixed_t> (Z() - 8 * FRACUNIT, floorz), ALLOW_REPLACE);
}
}
@ -799,7 +802,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnRippers)
for(i = 0; i < 8; i++)
{
ripper = Spawn<ARipper> (self->x, self->y, self->z, ALLOW_REPLACE);
ripper = Spawn<ARipper> (self->Pos(), ALLOW_REPLACE);
angle = i*ANG45;
ripper->target = self->target;
ripper->angle = angle;
@ -1007,8 +1010,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_AddPlayerRain)
DEFINE_ACTION_FUNCTION(AActor, A_SkullRodStorm)
{
fixed_t x;
fixed_t y;
AActor *mo;
ARainTracker *tracker;
@ -1039,20 +1040,21 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkullRodStorm)
{ // Fudge rain frequency
return;
}
x = self->x + ((pr_storm()&127) - 64) * FRACUNIT;
y = self->y + ((pr_storm()&127) - 64) * FRACUNIT;
mo = Spawn<ARainPillar> (x, y, ONCEILINGZ, ALLOW_REPLACE);
fixedvec2 pos = self->Vec2Offset(
((pr_storm()&127) - 64) * FRACUNIT,
((pr_storm()&127) - 64) * FRACUNIT);
mo = Spawn<ARainPillar> (pos.x, pos.y, ONCEILINGZ, ALLOW_REPLACE);
// We used bouncecount to store the 3D floor index in A_HideInCeiling
if (!mo) return;
fixed_t newz;
if (self->bouncecount >= 0
&& (unsigned)self->bouncecount < self->Sector->e->XFloor.ffloors.Size())
newz = self->Sector->e->XFloor.ffloors[self->bouncecount]->bottom.plane->ZatPoint(x, y);// - 40 * FRACUNIT;
newz = self->Sector->e->XFloor.ffloors[self->bouncecount]->bottom.plane->ZatPoint(pos.x, pos.y);// - 40 * FRACUNIT;
else
newz = self->Sector->ceilingplane.ZatPoint(x, y);
int moceiling = P_Find3DFloor(NULL, x, y, newz, false, false, newz);
newz = self->Sector->ceilingplane.ZatPoint(pos.x, pos.y);
int moceiling = P_Find3DFloor(NULL, pos.x, pos.y, newz, false, false, newz);
if (moceiling >= 0)
mo->z = newz - mo->height;
mo->SetZ(newz - mo->height, false);
mo->Translation = multiplayer ?
TRANSLATION(TRANSLATION_PlayersExtra,self->special2) : 0;
mo->target = self->target;
@ -1074,7 +1076,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SkullRodStorm)
DEFINE_ACTION_FUNCTION(AActor, A_RainImpact)
{
if (self->z > self->floorz)
if (self->Z() > self->floorz)
{
self->SetState (self->FindState("NotFloor"));
}
@ -1099,15 +1101,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_HideInCeiling)
F3DFloor * rover = self->Sector->e->XFloor.ffloors[i];
if(!(rover->flags & FF_SOLID) || !(rover->flags & FF_EXISTS)) continue;
if ((foo = rover->bottom.plane->ZatPoint(self)) >= (self->z + self->height))
if ((foo = rover->bottom.plane->ZatPoint(self)) >= (self->Top()))
{
self->z = foo + 4*FRACUNIT;
self->SetZ(foo + 4*FRACUNIT, false);
self->bouncecount = i;
return;
}
}
self->bouncecount = -1;
self->z = self->ceilingz + 4*FRACUNIT;
self->SetZ(self->ceilingz + 4*FRACUNIT, false);
}
// --- Phoenix Rod ----------------------------------------------------------
@ -1225,13 +1227,13 @@ DEFINE_ACTION_FUNCTION(AActor, A_PhoenixPuff)
//[RH] Heretic never sets the target for seeking
//P_SeekerMissile (self, ANGLE_1*5, ANGLE_1*10);
puff = Spawn("PhoenixPuff", self->x, self->y, self->z, ALLOW_REPLACE);
puff = Spawn("PhoenixPuff", self->Pos(), ALLOW_REPLACE);
angle = self->angle + ANG90;
angle >>= ANGLETOFINESHIFT;
puff->velx = FixedMul (FRACUNIT*13/10, finecosine[angle]);
puff->vely = FixedMul (FRACUNIT*13/10, finesine[angle]);
puff->velz = 0;
puff = Spawn("PhoenixPuff", self->x, self->y, self->z, ALLOW_REPLACE);
puff = Spawn("PhoenixPuff", self->Pos(), ALLOW_REPLACE);
angle = self->angle - ANG90;
angle >>= ANGLETOFINESHIFT;
puff->velx = FixedMul (FRACUNIT*13/10, finecosine[angle]);
@ -1269,7 +1271,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePhoenixPL2)
{
AActor *mo;
angle_t angle;
fixed_t x, y, z;
fixed_t slope;
FSoundID soundid;
@ -1292,12 +1293,14 @@ DEFINE_ACTION_FUNCTION(AActor, A_FirePhoenixPL2)
return;
}
angle = self->angle;
x = self->x + (pr_fp2.Random2() << 9);
y = self->y + (pr_fp2.Random2() << 9);
z = self->z + 26*FRACUNIT + finetangent[FINEANGLES/4-(self->pitch>>ANGLETOFINESHIFT)];
z -= self->floorclip;
fixedvec3 pos = self->Vec3Offset(
(pr_fp2.Random2() << 9),
(pr_fp2.Random2() << 9),
26*FRACUNIT + finetangent[FINEANGLES/4-(self->pitch>>ANGLETOFINESHIFT)] - self->floorclip);
slope = finetangent[FINEANGLES/4-(self->pitch>>ANGLETOFINESHIFT)] + (FRACUNIT/10);
mo = Spawn("PhoenixFX2", x, y, z, ALLOW_REPLACE);
mo = Spawn("PhoenixFX2", pos, ALLOW_REPLACE);
mo->target = self;
mo->angle = angle;
mo->velx = self->velx + FixedMul (mo->Speed, finecosine[angle>>ANGLETOFINESHIFT]);

View File

@ -106,8 +106,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichAttack)
baseFire->SetState (baseFire->FindState("NoGrow"));
for (i = 0; i < 5; i++)
{
fire = Spawn("HeadFX3", baseFire->x, baseFire->y,
baseFire->z, ALLOW_REPLACE);
fire = Spawn("HeadFX3", baseFire->Pos(), ALLOW_REPLACE);
if (i == 0)
{
S_Sound (self, CHAN_BODY, "ironlich/attack1", 1, ATTN_NORM);
@ -128,7 +127,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichAttack)
mo = P_SpawnMissile (self, target, RUNTIME_CLASS(AWhirlwind));
if (mo != NULL)
{
mo->z -= 32*FRACUNIT;
mo->SetZ(mo->Z() - 32*FRACUNIT, false);
mo->tracer = target;
mo->special1 = 60;
mo->special2 = 50; // Timer for active sound
@ -180,7 +179,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichIceImpact)
for (i = 0; i < 8; i++)
{
shard = Spawn("HeadFX2", self->x, self->y, self->z, ALLOW_REPLACE);
shard = Spawn("HeadFX2", self->Pos(), ALLOW_REPLACE);
angle = i*ANG45;
shard->target = self->target;
shard->angle = angle;
@ -201,7 +200,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LichIceImpact)
DEFINE_ACTION_FUNCTION(AActor, A_LichFireGrow)
{
self->health--;
self->z += 9*FRACUNIT;
self->SetZ(self->Z + 9*FRACUNIT);
if (self->health == 0)
{
self->Damage = self->GetDefault()->Damage;

View File

@ -24,9 +24,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_DripBlood)
AActor *mo;
fixed_t x, y;
x = self->x + (pr_dripblood.Random2 () << 11);
y = self->y + (pr_dripblood.Random2 () << 11);
mo = Spawn ("Blood", x, y, self->z, ALLOW_REPLACE);
fixedvec3 pos = self->Vec3Offset(
(pr_dripblood.Random2 () << 11),
(pr_dripblood.Random2 () << 11), 0);
mo = Spawn ("Blood", pos, ALLOW_REPLACE);
mo->velx = pr_dripblood.Random2 () << 10;
mo->vely = pr_dripblood.Random2 () << 10;
mo->gravity = FRACUNIT/8;
@ -56,10 +57,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_KnightAttack)
S_Sound (self, CHAN_BODY, self->AttackSound, 1, ATTN_NORM);
if (self->flags & MF_SHADOW || pr_knightatk () < 40)
{ // Red axe
P_SpawnMissileZ (self, self->z + 36*FRACUNIT, self->target, PClass::FindClass("RedAxe"));
P_SpawnMissileZ (self, self->Z() + 36*FRACUNIT, self->target, PClass::FindClass("RedAxe"));
return;
}
// Green axe
P_SpawnMissileZ (self, self->z + 36*FRACUNIT, self->target, PClass::FindClass("KnightAxe"));
P_SpawnMissileZ (self, self->Z() + 36*FRACUNIT, self->target, PClass::FindClass("KnightAxe"));
}