mirror of
https://github.com/ZDoom/qzdoom-gpl.git
synced 2024-11-24 04:41:53 +00:00
3d61d2c1f4
Nothing should ever assume that spawning an actor is unconditionally successful. There can always be some edge cases where this is not the case.
248 lines
4.7 KiB
Text
248 lines
4.7 KiB
Text
//===========================================================================
|
|
//
|
|
// Revenant
|
|
//
|
|
//===========================================================================
|
|
class Revenant : Actor
|
|
{
|
|
Default
|
|
{
|
|
Health 300;
|
|
Radius 20;
|
|
Height 56;
|
|
Mass 500;
|
|
Speed 10;
|
|
PainChance 100;
|
|
Monster;
|
|
MeleeThreshold 196;
|
|
+MISSILEMORE
|
|
+FLOORCLIP
|
|
SeeSound "skeleton/sight";
|
|
PainSound "skeleton/pain";
|
|
DeathSound "skeleton/death";
|
|
ActiveSound "skeleton/active";
|
|
MeleeSound "skeleton/melee";
|
|
HitObituary "$OB_UNDEADHIT";
|
|
Obituary "$OB_UNDEAD";
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
SKEL AB 10 A_Look;
|
|
Loop;
|
|
See:
|
|
SKEL AABBCCDDEEFF 2 A_Chase;
|
|
Loop;
|
|
Melee:
|
|
SKEL G 0 A_FaceTarget;
|
|
SKEL G 6 A_SkelWhoosh;
|
|
SKEL H 6 A_FaceTarget;
|
|
SKEL I 6 A_SkelFist;
|
|
Goto See;
|
|
Missile:
|
|
SKEL J 0 BRIGHT A_FaceTarget;
|
|
SKEL J 10 BRIGHT A_FaceTarget;
|
|
SKEL K 10 A_SkelMissile;
|
|
SKEL K 10 A_FaceTarget;
|
|
Goto See;
|
|
Pain:
|
|
SKEL L 5;
|
|
SKEL L 5 A_Pain;
|
|
Goto See;
|
|
Death:
|
|
SKEL LM 7;
|
|
SKEL N 7 A_Scream;
|
|
SKEL O 7 A_NoBlocking;
|
|
SKEL P 7;
|
|
SKEL Q -1;
|
|
Stop;
|
|
Raise:
|
|
SKEL Q 5;
|
|
SKEL PONML 5;
|
|
Goto See;
|
|
}
|
|
}
|
|
|
|
|
|
//===========================================================================
|
|
//
|
|
// Revenant Tracer
|
|
//
|
|
//===========================================================================
|
|
class RevenantTracer : Actor
|
|
{
|
|
Default
|
|
{
|
|
Radius 11;
|
|
Height 8;
|
|
Speed 10;
|
|
Damage 10;
|
|
Projectile;
|
|
+SEEKERMISSILE
|
|
+RANDOMIZE
|
|
SeeSound "skeleton/attack";
|
|
DeathSound "skeleton/tracex";
|
|
RenderStyle "Add";
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
FATB AB 2 BRIGHT A_Tracer;
|
|
Loop;
|
|
Death:
|
|
FBXP A 8 BRIGHT;
|
|
FBXP B 6 BRIGHT;
|
|
FBXP C 4 BRIGHT;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
|
|
//===========================================================================
|
|
//
|
|
// Revenant Tracer Smoke
|
|
//
|
|
//===========================================================================
|
|
class RevenantTracerSmoke : Actor
|
|
{
|
|
Default
|
|
{
|
|
+NOBLOCKMAP
|
|
+NOGRAVITY
|
|
+NOTELEPORT
|
|
RenderStyle "Translucent";
|
|
Alpha 0.5;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
PUFF ABABC 4;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
//===========================================================================
|
|
//
|
|
// Code (must be attached to Actor)
|
|
//
|
|
//===========================================================================
|
|
|
|
extend class Actor
|
|
{
|
|
void A_SkelMissile()
|
|
{
|
|
if (target == null) return;
|
|
A_FaceTarget();
|
|
AddZ(16);
|
|
Actor missile = SpawnMissile(target, "RevenantTracer");
|
|
AddZ(-16);
|
|
if (missile != null)
|
|
{
|
|
missile.SetOrigin(missile.Vec3Offset(missile.Vel.X, missile.Vel.Y, 0.), false);
|
|
missile.tracer = target;
|
|
}
|
|
}
|
|
|
|
void A_SkelWhoosh()
|
|
{
|
|
if (target == null) return;
|
|
A_FaceTarget();
|
|
A_PlaySound("skeleton/swing", CHAN_WEAPON);
|
|
}
|
|
|
|
void A_SkelFist()
|
|
{
|
|
if (target == null) return;
|
|
A_FaceTarget();
|
|
|
|
if (CheckMeleeRange ())
|
|
{
|
|
int damage = random[SkelFist](1, 10) * 6;
|
|
A_PlaySound("skeleton/melee", CHAN_WEAPON);
|
|
int newdam = target.DamageMobj (self, self, damage, 'Melee');
|
|
target.TraceBleed (newdam > 0 ? newdam : damage, self);
|
|
}
|
|
}
|
|
|
|
void A_Tracer2(double traceang = 19.6875)
|
|
{
|
|
double dist;
|
|
double slope;
|
|
Actor dest;
|
|
|
|
// adjust direction
|
|
dest = tracer;
|
|
|
|
if (!dest || dest.health <= 0 || Speed == 0 || !CanSeek(dest))
|
|
return;
|
|
|
|
// change angle
|
|
double exact = AngleTo(dest);
|
|
double diff = deltaangle(angle, exact);
|
|
|
|
if (diff < 0)
|
|
{
|
|
angle -= traceang;
|
|
if (deltaangle(angle, exact) > 0)
|
|
angle = exact;
|
|
}
|
|
else if (diff > 0)
|
|
{
|
|
angle += traceang;
|
|
if (deltaangle(angle, exact) < 0.)
|
|
angle = exact;
|
|
}
|
|
|
|
VelFromAngle();
|
|
|
|
if (!bFloorHugger && !bCeilingHugger)
|
|
{
|
|
// change slope
|
|
dist = DistanceBySpeed(dest, Speed);
|
|
|
|
if (dest.Height >= 56.)
|
|
{
|
|
slope = (dest.pos.z + 40. - pos.z) / dist;
|
|
}
|
|
else
|
|
{
|
|
slope = (dest.pos.z + Height*(2./3) - pos.z) / dist;
|
|
}
|
|
|
|
if (slope < Vel.Z)
|
|
Vel.Z -= 1. / 8;
|
|
else
|
|
Vel.Z += 1. / 8;
|
|
}
|
|
}
|
|
|
|
void A_Tracer()
|
|
{
|
|
// killough 1/18/98: this is why some missiles do not have smoke
|
|
// and some do. Also, internal demos start at random gametics, thus
|
|
// the bug in which revenants cause internal demos to go out of sync.
|
|
//
|
|
// killough 3/6/98: fix revenant internal demo bug by subtracting
|
|
// levelstarttic from gametic:
|
|
//
|
|
// [RH] level.time is always 0-based, so nothing special to do here.
|
|
|
|
if (level.time & 3) return;
|
|
|
|
// spawn a puff of smoke behind the rocket
|
|
SpawnPuff ("BulletPuff", pos, angle, angle, 3);
|
|
Actor smoke = Spawn ("RevenantTracerSmoke", Vec3Offset(-Vel.X, -Vel.Y, 0.), ALLOW_REPLACE);
|
|
|
|
if (smoke != null)
|
|
{
|
|
smoke.Vel.Z = 1.;
|
|
smoke.tics -= random[Tracer](0, 3);
|
|
if (smoke.tics < 1)
|
|
smoke.tics = 1;
|
|
}
|
|
|
|
// The rest of this function was identical with Strife's version, except for the angle being used.
|
|
A_Tracer2(16.875);
|
|
}
|
|
}
|
|
|