mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-10 23:02:08 +00:00
- scriptified Hexen's Dragon.
- fixed several places in the code generator that did not consider locked registers for local variables: array indices, abs and floating point builtin functions. - added some debug aids to the bounds opcode. Just triggering an exception here which loses all relevant info is perfectly useless in a debug situation.
This commit is contained in:
parent
633da6e5d8
commit
76a74e0364
5 changed files with 327 additions and 347 deletions
|
@ -1,311 +0,0 @@
|
|||
/*
|
||||
#include "actor.h"
|
||||
#include "info.h"
|
||||
#include "p_enemy.h"
|
||||
#include "p_local.h"
|
||||
#include "a_action.h"
|
||||
#include "m_random.h"
|
||||
#include "s_sound.h"
|
||||
#include "vm.h"
|
||||
*/
|
||||
|
||||
static FRandom pr_dragonseek ("DragonSeek");
|
||||
static FRandom pr_dragonflight ("DragonFlight");
|
||||
static FRandom pr_dragonflap ("DragonFlap");
|
||||
static FRandom pr_dragonfx2 ("DragonFX2");
|
||||
|
||||
DECLARE_ACTION(A_DragonFlight)
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// DragonSeek
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
static void DragonSeek (AActor *actor, DAngle thresh, DAngle turnMax)
|
||||
{
|
||||
int dir;
|
||||
double dist;
|
||||
DAngle delta;
|
||||
AActor *target;
|
||||
int i;
|
||||
DAngle bestAngle;
|
||||
DAngle angleToSpot, angleToTarget;
|
||||
AActor *mo;
|
||||
|
||||
target = actor->tracer;
|
||||
if(target == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
dir = P_FaceMobj (actor, target, &delta);
|
||||
if (delta > thresh)
|
||||
{
|
||||
delta /= 2;
|
||||
if (delta > turnMax)
|
||||
{
|
||||
delta = turnMax;
|
||||
}
|
||||
}
|
||||
if (dir)
|
||||
{ // Turn clockwise
|
||||
actor->Angles.Yaw += delta;
|
||||
}
|
||||
else
|
||||
{ // Turn counter clockwise
|
||||
actor->Angles.Yaw -= delta;
|
||||
}
|
||||
actor->VelFromAngle();
|
||||
|
||||
dist = actor->DistanceBySpeed(target, actor->Speed);
|
||||
if (actor->Top() < target->Z() ||
|
||||
target->Top() < actor->Z())
|
||||
{
|
||||
actor->Vel.Z = (target->Z() - actor->Z()) / dist;
|
||||
}
|
||||
if (target->flags&MF_SHOOTABLE && pr_dragonseek() < 64)
|
||||
{ // attack the destination mobj if it's attackable
|
||||
AActor *oldTarget;
|
||||
|
||||
if (absangle(actor->Angles.Yaw, actor->AngleTo(target)) < 22.5)
|
||||
{
|
||||
oldTarget = actor->target;
|
||||
actor->target = target;
|
||||
if (actor->CheckMeleeRange ())
|
||||
{
|
||||
int damage = pr_dragonseek.HitDice (10);
|
||||
int newdam = P_DamageMobj (actor->target, actor, actor, damage, NAME_Melee);
|
||||
P_TraceBleed (newdam > 0 ? newdam : damage, actor->target, actor);
|
||||
S_Sound (actor, CHAN_WEAPON, actor->AttackSound, 1, ATTN_NORM);
|
||||
}
|
||||
else if (pr_dragonseek() < 128 && P_CheckMissileRange(actor))
|
||||
{
|
||||
P_SpawnMissile(actor, target, PClass::FindActor("DragonFireball"));
|
||||
S_Sound (actor, CHAN_WEAPON, actor->AttackSound, 1, ATTN_NORM);
|
||||
}
|
||||
actor->target = oldTarget;
|
||||
}
|
||||
}
|
||||
if (dist < 4)
|
||||
{ // Hit the target thing
|
||||
if (actor->target && pr_dragonseek() < 200)
|
||||
{
|
||||
AActor *bestActor = NULL;
|
||||
bestAngle = 360.;
|
||||
angleToTarget = actor->AngleTo(actor->target);
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
if (!target->args[i])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
FActorIterator iterator (target->args[i]);
|
||||
mo = iterator.Next ();
|
||||
if (mo == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
angleToSpot = actor->AngleTo(mo);
|
||||
DAngle diff = absangle(angleToSpot, angleToTarget);
|
||||
if (diff < bestAngle)
|
||||
{
|
||||
bestAngle = diff;
|
||||
bestActor = mo;
|
||||
}
|
||||
}
|
||||
if (bestActor != NULL)
|
||||
{
|
||||
actor->tracer = bestActor;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// [RH] Don't lock up if the dragon doesn't have any
|
||||
// targets defined
|
||||
for (i = 0; i < 5; ++i)
|
||||
{
|
||||
if (target->args[i] != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < 5)
|
||||
{
|
||||
do
|
||||
{
|
||||
i = (pr_dragonseek()>>2)%5;
|
||||
} while(!target->args[i]);
|
||||
FActorIterator iterator (target->args[i]);
|
||||
actor->tracer = iterator.Next ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_DragonInitFlight
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_DragonInitFlight)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
FActorIterator iterator (self->tid);
|
||||
|
||||
do
|
||||
{ // find the first tid identical to the dragon's tid
|
||||
self->tracer = iterator.Next ();
|
||||
if (self->tracer == NULL)
|
||||
{
|
||||
self->SetState (self->SpawnState);
|
||||
return 0;
|
||||
}
|
||||
} while (self->tracer == self);
|
||||
self->RemoveFromHash ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_DragonFlight
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_DragonFlight)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
DAngle angle;
|
||||
|
||||
DragonSeek (self, 4., 8.);
|
||||
if (self->target)
|
||||
{
|
||||
if(!(self->target->flags&MF_SHOOTABLE))
|
||||
{ // target died
|
||||
self->target = NULL;
|
||||
return 0;
|
||||
}
|
||||
angle = absangle(self->Angles.Yaw, self->AngleTo(self->target));
|
||||
if (angle <22.5 && self->CheckMeleeRange())
|
||||
{
|
||||
int damage = pr_dragonflight.HitDice (8);
|
||||
int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee);
|
||||
P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self);
|
||||
S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM);
|
||||
}
|
||||
else if (angle <= 20)
|
||||
{
|
||||
self->SetState (self->MissileState);
|
||||
S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
P_LookForPlayers (self, true, NULL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_DragonFlap
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_DragonFlap)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
CALL_ACTION(A_DragonFlight, self);
|
||||
if (pr_dragonflap() < 240)
|
||||
{
|
||||
S_Sound (self, CHAN_BODY, "DragonWingflap", 1, ATTN_NORM);
|
||||
}
|
||||
else
|
||||
{
|
||||
self->PlayActiveSound ();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_DragonAttack
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_DragonAttack)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
P_SpawnMissile (self, self->target, PClass::FindActor("DragonFireball"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_DragonFX2
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_DragonFX2)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
AActor *mo;
|
||||
int i;
|
||||
int delay;
|
||||
|
||||
delay = 16+(pr_dragonfx2()>>3);
|
||||
for (i = 1+(pr_dragonfx2()&3); i; i--)
|
||||
{
|
||||
double xo = (pr_dragonfx2() - 128) / 4.;
|
||||
double yo = (pr_dragonfx2() - 128) / 4.;
|
||||
double zo = (pr_dragonfx2() - 128) / 16.;
|
||||
|
||||
mo = Spawn ("DragonExplosion", self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE);
|
||||
if (mo)
|
||||
{
|
||||
mo->tics = delay+(pr_dragonfx2()&3)*i*2;
|
||||
mo->target = self->target;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_DragonPain
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_DragonPain)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
CALL_ACTION(A_Pain, self);
|
||||
if (!self->tracer)
|
||||
{ // no destination spot yet
|
||||
self->SetState (self->SeeState);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_DragonCheckCrash
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_DragonCheckCrash)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
if (self->Z() <= self->floorz)
|
||||
{
|
||||
self->SetState (self->FindState ("Crash"));
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -33,7 +33,6 @@
|
|||
#include "a_clericholy.cpp"
|
||||
#include "a_clericmace.cpp"
|
||||
#include "a_clericstaff.cpp"
|
||||
#include "a_dragon.cpp"
|
||||
#include "a_fighteraxe.cpp"
|
||||
#include "a_fighterhammer.cpp"
|
||||
#include "a_fighterplayer.cpp"
|
||||
|
|
|
@ -1670,19 +1670,23 @@ ExpEmit FxMinusSign::Emit(VMFunctionBuilder *build)
|
|||
{
|
||||
assert(ValueType == Operand->ValueType);
|
||||
ExpEmit from = Operand->Emit(build);
|
||||
ExpEmit to;
|
||||
assert(from.Konst == 0);
|
||||
assert(ValueType->GetRegCount() == from.RegCount);
|
||||
// Do it in-place, unless a local variable
|
||||
if (from.Fixed)
|
||||
{
|
||||
ExpEmit to = ExpEmit(build, from.RegType, from.RegCount);
|
||||
build->Emit(Operand->ValueType->GetMoveOp(), to.RegNum, from.RegNum);
|
||||
from = to;
|
||||
to = ExpEmit(build, from.RegType, from.RegCount);
|
||||
from.Free(build);
|
||||
}
|
||||
else
|
||||
{
|
||||
to = from;
|
||||
}
|
||||
|
||||
if (ValueType->GetRegType() == REGT_INT)
|
||||
{
|
||||
build->Emit(OP_NEG, from.RegNum, from.RegNum, 0);
|
||||
build->Emit(OP_NEG, to.RegNum, from.RegNum, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1690,20 +1694,20 @@ ExpEmit FxMinusSign::Emit(VMFunctionBuilder *build)
|
|||
switch (from.RegCount)
|
||||
{
|
||||
case 1:
|
||||
build->Emit(OP_FLOP, from.RegNum, from.RegNum, FLOP_NEG);
|
||||
build->Emit(OP_FLOP, to.RegNum, from.RegNum, FLOP_NEG);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
build->Emit(OP_NEGV2, from.RegNum, from.RegNum);
|
||||
build->Emit(OP_NEGV2, to.RegNum, from.RegNum);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
build->Emit(OP_NEGV3, from.RegNum, from.RegNum);
|
||||
build->Emit(OP_NEGV3, to.RegNum, from.RegNum);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
return from;
|
||||
return to;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -4255,19 +4259,31 @@ FxExpression *FxAbs::Resolve(FCompileContext &ctx)
|
|||
|
||||
ExpEmit FxAbs::Emit(VMFunctionBuilder *build)
|
||||
{
|
||||
ExpEmit absofsteal = val->Emit(build);
|
||||
assert(!absofsteal.Konst);
|
||||
ExpEmit out(build, absofsteal.RegType);
|
||||
if (absofsteal.RegType == REGT_INT)
|
||||
assert(ValueType == val->ValueType);
|
||||
ExpEmit from = val->Emit(build);
|
||||
ExpEmit to;
|
||||
assert(from.Konst == 0);
|
||||
assert(ValueType->GetRegCount() == 1);
|
||||
// Do it in-place, unless a local variable
|
||||
if (from.Fixed)
|
||||
{
|
||||
build->Emit(OP_ABS, out.RegNum, absofsteal.RegNum, 0);
|
||||
to = ExpEmit(build, from.RegType);
|
||||
from.Free(build);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(absofsteal.RegType == REGT_FLOAT);
|
||||
build->Emit(OP_FLOP, out.RegNum, absofsteal.RegNum, FLOP_ABS);
|
||||
to = from;
|
||||
}
|
||||
return out;
|
||||
|
||||
if (ValueType->GetRegType() == REGT_INT)
|
||||
{
|
||||
build->Emit(OP_ABS, to.RegNum, from.RegNum, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
build->Emit(OP_FLOP, to.RegNum, from.RegNum, FLOP_ABS);
|
||||
}
|
||||
return to;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -5898,6 +5914,7 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build)
|
|||
else
|
||||
{
|
||||
ExpEmit indexv(index->Emit(build));
|
||||
ExpEmit indexwork = indexv.Fixed ? ExpEmit(build, indexv.RegType) : indexv;
|
||||
int shiftbits = 0;
|
||||
while (1u << shiftbits < arraytype->ElementSize)
|
||||
{
|
||||
|
@ -5907,19 +5924,19 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build)
|
|||
build->Emit(OP_BOUND, indexv.RegNum, arraytype->ElementCount);
|
||||
if (shiftbits > 0)
|
||||
{
|
||||
build->Emit(OP_SLL_RI, indexv.RegNum, indexv.RegNum, shiftbits);
|
||||
build->Emit(OP_SLL_RI, indexwork.RegNum, indexv.RegNum, shiftbits);
|
||||
}
|
||||
|
||||
if (AddressRequested)
|
||||
{
|
||||
build->Emit(OP_ADDA_RR, start.RegNum, start.RegNum, indexv.RegNum);
|
||||
build->Emit(OP_ADDA_RR, start.RegNum, start.RegNum, indexwork.RegNum);
|
||||
}
|
||||
else
|
||||
{
|
||||
build->Emit(arraytype->ElementType->GetLoadOp() + 1, // added 1 to use the *_R version that
|
||||
dest.RegNum, start.RegNum, indexv.RegNum); // takes the offset from a register
|
||||
dest.RegNum, start.RegNum, indexwork.RegNum); // takes the offset from a register
|
||||
}
|
||||
indexv.Free(build);
|
||||
indexwork.Free(build);
|
||||
}
|
||||
if (AddressRequested)
|
||||
{
|
||||
|
@ -6955,13 +6972,26 @@ FxExpression *FxFlopFunctionCall::Resolve(FCompileContext& ctx)
|
|||
|
||||
ExpEmit FxFlopFunctionCall::Emit(VMFunctionBuilder *build)
|
||||
{
|
||||
ExpEmit v = ArgList[0]->Emit(build);
|
||||
assert(!v.Konst && v.RegType == REGT_FLOAT);
|
||||
assert(ValueType == ArgList[0]->ValueType);
|
||||
ExpEmit from = ArgList[0]->Emit(build);
|
||||
ExpEmit to;
|
||||
assert(from.Konst == 0);
|
||||
assert(ValueType->GetRegCount() == 1);
|
||||
// Do it in-place, unless a local variable
|
||||
if (from.Fixed)
|
||||
{
|
||||
to = ExpEmit(build, from.RegType);
|
||||
from.Free(build);
|
||||
}
|
||||
else
|
||||
{
|
||||
to = from;
|
||||
}
|
||||
|
||||
build->Emit(OP_FLOP, v.RegNum, v.RegNum, FxFlops[Index].Flop);
|
||||
build->Emit(OP_FLOP, to.RegNum, from.RegNum, FxFlops[Index].Flop);
|
||||
ArgList.Clear();
|
||||
ArgList.ShrinkToFit();
|
||||
return v;
|
||||
return to;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -696,6 +696,8 @@ begin:
|
|||
OP(BOUND):
|
||||
if (reg.d[a] >= BC)
|
||||
{
|
||||
assert(false);
|
||||
Printf("Array access out of bounds: Max. index = %u, current index = %u\n", BC, reg.d[a]);
|
||||
THROW(X_ARRAY_OUT_OF_BOUNDS);
|
||||
}
|
||||
NEXTOP;
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
|
||||
// Dragon -------------------------------------------------------------------
|
||||
|
||||
class Dragon : Actor
|
||||
{
|
||||
Default
|
||||
|
@ -23,13 +21,6 @@ class Dragon : Actor
|
|||
Obituary "$OB_DRAGON";
|
||||
}
|
||||
|
||||
native void A_DragonInitFlight();
|
||||
native void A_DragonFlap();
|
||||
native void A_DragonFlight();
|
||||
native void A_DragonPain();
|
||||
native void A_DragonAttack();
|
||||
native void A_DragonCheckCrash();
|
||||
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
|
@ -58,6 +49,253 @@ class Dragon : Actor
|
|||
DRAG M -1;
|
||||
Stop;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// DragonSeek
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
private void DragonSeek (double thresh, double turnMax)
|
||||
{
|
||||
double dist;
|
||||
double delta;
|
||||
Actor targ;
|
||||
int i;
|
||||
double bestAngle;
|
||||
double angleToSpot, angleToTarget;
|
||||
Actor mo;
|
||||
|
||||
targ = tracer;
|
||||
if(targ == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
double diff = deltaangle(angle, AngleTo(targ));
|
||||
delta = abs(diff);
|
||||
|
||||
if (delta > thresh)
|
||||
{
|
||||
delta /= 2;
|
||||
if (delta > turnMax)
|
||||
{
|
||||
delta = turnMax;
|
||||
}
|
||||
}
|
||||
if (diff > 0)
|
||||
{ // Turn clockwise
|
||||
angle = angle + delta;
|
||||
}
|
||||
else
|
||||
{ // Turn counter clockwise
|
||||
angle = angle - delta;
|
||||
}
|
||||
VelFromAngle();
|
||||
|
||||
dist = DistanceBySpeed(targ, Speed);
|
||||
if (pos.z + height < targ.pos.z || targ.pos.z + targ.height < pos.z)
|
||||
{
|
||||
Vel.Z = (targ.pos.z - pos.z) / dist;
|
||||
}
|
||||
if (targ.bShootable && random[DragonSeek]() < 64)
|
||||
{ // attack the destination mobj if it's attackable
|
||||
Actor oldTarget;
|
||||
|
||||
if (absangle(angle, AngleTo(targ)) < 22.5)
|
||||
{
|
||||
oldTarget = target;
|
||||
target = targ;
|
||||
if (CheckMeleeRange ())
|
||||
{
|
||||
int damage = random[DragonSeek](1, 8) * 10;
|
||||
int newdam = target.DamageMobj (self, self, damage, 'Melee');
|
||||
target.TraceBleed (newdam > 0 ? newdam : damage, self);
|
||||
A_PlaySound (AttackSound, CHAN_WEAPON);
|
||||
}
|
||||
else if (random[DragonSeek]() < 128 && CheckMissileRange())
|
||||
{
|
||||
SpawnMissile(targ, "DragonFireball");
|
||||
A_PlaySound (AttackSound, CHAN_WEAPON);
|
||||
}
|
||||
target = oldTarget;
|
||||
}
|
||||
}
|
||||
if (dist < 4)
|
||||
{ // Hit the target thing
|
||||
if (target && random[DragonSeek]() < 200)
|
||||
{
|
||||
Actor bestActor = null;
|
||||
bestAngle = 360.;
|
||||
angleToTarget = AngleTo(target);
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
if (!targ.args[i])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
ActorIterator iter = ActorIterator.Create(targ.args[i]);
|
||||
mo = iter.Next ();
|
||||
if (mo == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
angleToSpot = AngleTo(mo);
|
||||
double diff = absangle(angleToSpot, angleToTarget);
|
||||
if (diff < bestAngle)
|
||||
{
|
||||
bestAngle = diff;
|
||||
bestActor = mo;
|
||||
}
|
||||
}
|
||||
if (bestActor != null)
|
||||
{
|
||||
tracer = bestActor;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// [RH] Don't lock up if the dragon doesn't have any
|
||||
// targs defined
|
||||
for (i = 0; i < 5; ++i)
|
||||
{
|
||||
if (targ.args[i] != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < 5)
|
||||
{
|
||||
do
|
||||
{
|
||||
i = (random[DragonSeek]() >> 2) % 5;
|
||||
} while(!targ.args[i]);
|
||||
ActorIterator iter = ActorIterator.Create(targ.args[i]);
|
||||
tracer = iter.Next ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_DragonInitFlight
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
void A_DragonInitFlight()
|
||||
{
|
||||
ActorIterator iter = ActorIterator.Create(tid);
|
||||
|
||||
do
|
||||
{ // find the first tid identical to the dragon's tid
|
||||
tracer = iter.Next ();
|
||||
if (tracer == null)
|
||||
{
|
||||
SetState (SpawnState);
|
||||
return;
|
||||
}
|
||||
} while (tracer == self);
|
||||
RemoveFromHash ();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_DragonFlight
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
void A_DragonFlight()
|
||||
{
|
||||
double ang;
|
||||
|
||||
DragonSeek (4., 8.);
|
||||
if (target)
|
||||
{
|
||||
if(!target.bShootable)
|
||||
{ // target died
|
||||
target = null;
|
||||
return;
|
||||
}
|
||||
ang = absangle(angle, AngleTo(target));
|
||||
if (ang <22.5 && CheckMeleeRange())
|
||||
{
|
||||
int damage = random[DragonFlight](1, 8) * 8;
|
||||
int newdam = target.DamageMobj (self, self, damage, 'Melee');
|
||||
target.TraceBleed (newdam > 0 ? newdam : damage, self);
|
||||
A_PlaySound (AttackSound, CHAN_WEAPON);
|
||||
}
|
||||
else if (ang <= 20)
|
||||
{
|
||||
SetState (MissileState);
|
||||
A_PlaySound (AttackSound, CHAN_WEAPON);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LookForPlayers (true);
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_DragonFlap
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
void A_DragonFlap()
|
||||
{
|
||||
A_DragonFlight();
|
||||
if (random[DragonFlight]() < 240)
|
||||
{
|
||||
A_PlaySound ("DragonWingflap", CHAN_BODY);
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayActiveSound ();
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_DragonAttack
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
void A_DragonAttack()
|
||||
{
|
||||
SpawnMissile (target, "DragonFireball");
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_DragonPain
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
void A_DragonPain()
|
||||
{
|
||||
A_Pain();
|
||||
if (!tracer)
|
||||
{ // no destination spot yet
|
||||
SetState (SeeState);
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_DragonCheckCrash
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
void A_DragonCheckCrash()
|
||||
{
|
||||
if (pos.z < floorz)
|
||||
{
|
||||
SetStateLabel ("Crash");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dragon Fireball ----------------------------------------------------------
|
||||
|
@ -77,8 +315,6 @@ class DragonFireball : Actor
|
|||
DeathSound "DragonFireballExplode";
|
||||
}
|
||||
|
||||
native void A_DragonFX2();
|
||||
|
||||
States
|
||||
{
|
||||
Spawn:
|
||||
|
@ -90,6 +326,30 @@ class DragonFireball : Actor
|
|||
DRFX KL 3 Bright;
|
||||
Stop;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_DragonFX2
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
void A_DragonFX2()
|
||||
{
|
||||
int delay = 16+(random[DragonFX2]()>>3);
|
||||
for (int i = random[DragonFX2](1, 4); i; i--)
|
||||
{
|
||||
double xo = (random[DragonFX2]() - 128) / 4.;
|
||||
double yo = (random[DragonFX2]() - 128) / 4.;
|
||||
double zo = (random[DragonFX2]() - 128) / 16.;
|
||||
|
||||
Actor mo = Spawn ("DragonExplosion", Vec3Offset(xo, yo, zo), ALLOW_REPLACE);
|
||||
if (mo)
|
||||
{
|
||||
mo.tics = delay + (random[DragonFX2](0, 3)) * i*2;
|
||||
mo.target = target;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dragon Fireball Secondary Explosion --------------------------------------
|
||||
|
|
Loading…
Reference in a new issue