mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2024-11-11 07:12:16 +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_clericholy.cpp"
|
||||||
#include "a_clericmace.cpp"
|
#include "a_clericmace.cpp"
|
||||||
#include "a_clericstaff.cpp"
|
#include "a_clericstaff.cpp"
|
||||||
#include "a_dragon.cpp"
|
|
||||||
#include "a_fighteraxe.cpp"
|
#include "a_fighteraxe.cpp"
|
||||||
#include "a_fighterhammer.cpp"
|
#include "a_fighterhammer.cpp"
|
||||||
#include "a_fighterplayer.cpp"
|
#include "a_fighterplayer.cpp"
|
||||||
|
|
|
@ -1670,19 +1670,23 @@ ExpEmit FxMinusSign::Emit(VMFunctionBuilder *build)
|
||||||
{
|
{
|
||||||
assert(ValueType == Operand->ValueType);
|
assert(ValueType == Operand->ValueType);
|
||||||
ExpEmit from = Operand->Emit(build);
|
ExpEmit from = Operand->Emit(build);
|
||||||
|
ExpEmit to;
|
||||||
assert(from.Konst == 0);
|
assert(from.Konst == 0);
|
||||||
assert(ValueType->GetRegCount() == from.RegCount);
|
assert(ValueType->GetRegCount() == from.RegCount);
|
||||||
// Do it in-place, unless a local variable
|
// Do it in-place, unless a local variable
|
||||||
if (from.Fixed)
|
if (from.Fixed)
|
||||||
{
|
{
|
||||||
ExpEmit to = ExpEmit(build, from.RegType, from.RegCount);
|
to = ExpEmit(build, from.RegType, from.RegCount);
|
||||||
build->Emit(Operand->ValueType->GetMoveOp(), to.RegNum, from.RegNum);
|
from.Free(build);
|
||||||
from = to;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
to = from;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ValueType->GetRegType() == REGT_INT)
|
if (ValueType->GetRegType() == REGT_INT)
|
||||||
{
|
{
|
||||||
build->Emit(OP_NEG, from.RegNum, from.RegNum, 0);
|
build->Emit(OP_NEG, to.RegNum, from.RegNum, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1690,20 +1694,20 @@ ExpEmit FxMinusSign::Emit(VMFunctionBuilder *build)
|
||||||
switch (from.RegCount)
|
switch (from.RegCount)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
build->Emit(OP_FLOP, from.RegNum, from.RegNum, FLOP_NEG);
|
build->Emit(OP_FLOP, to.RegNum, from.RegNum, FLOP_NEG);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
build->Emit(OP_NEGV2, from.RegNum, from.RegNum);
|
build->Emit(OP_NEGV2, to.RegNum, from.RegNum);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
build->Emit(OP_NEGV3, from.RegNum, from.RegNum);
|
build->Emit(OP_NEGV3, to.RegNum, from.RegNum);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return from;
|
return to;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -4255,19 +4259,31 @@ FxExpression *FxAbs::Resolve(FCompileContext &ctx)
|
||||||
|
|
||||||
ExpEmit FxAbs::Emit(VMFunctionBuilder *build)
|
ExpEmit FxAbs::Emit(VMFunctionBuilder *build)
|
||||||
{
|
{
|
||||||
ExpEmit absofsteal = val->Emit(build);
|
assert(ValueType == val->ValueType);
|
||||||
assert(!absofsteal.Konst);
|
ExpEmit from = val->Emit(build);
|
||||||
ExpEmit out(build, absofsteal.RegType);
|
ExpEmit to;
|
||||||
if (absofsteal.RegType == REGT_INT)
|
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
|
else
|
||||||
{
|
{
|
||||||
assert(absofsteal.RegType == REGT_FLOAT);
|
to = from;
|
||||||
build->Emit(OP_FLOP, out.RegNum, absofsteal.RegNum, FLOP_ABS);
|
|
||||||
}
|
}
|
||||||
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
|
else
|
||||||
{
|
{
|
||||||
ExpEmit indexv(index->Emit(build));
|
ExpEmit indexv(index->Emit(build));
|
||||||
|
ExpEmit indexwork = indexv.Fixed ? ExpEmit(build, indexv.RegType) : indexv;
|
||||||
int shiftbits = 0;
|
int shiftbits = 0;
|
||||||
while (1u << shiftbits < arraytype->ElementSize)
|
while (1u << shiftbits < arraytype->ElementSize)
|
||||||
{
|
{
|
||||||
|
@ -5907,19 +5924,19 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build)
|
||||||
build->Emit(OP_BOUND, indexv.RegNum, arraytype->ElementCount);
|
build->Emit(OP_BOUND, indexv.RegNum, arraytype->ElementCount);
|
||||||
if (shiftbits > 0)
|
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)
|
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
|
else
|
||||||
{
|
{
|
||||||
build->Emit(arraytype->ElementType->GetLoadOp() + 1, // added 1 to use the *_R version that
|
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)
|
if (AddressRequested)
|
||||||
{
|
{
|
||||||
|
@ -6955,13 +6972,26 @@ FxExpression *FxFlopFunctionCall::Resolve(FCompileContext& ctx)
|
||||||
|
|
||||||
ExpEmit FxFlopFunctionCall::Emit(VMFunctionBuilder *build)
|
ExpEmit FxFlopFunctionCall::Emit(VMFunctionBuilder *build)
|
||||||
{
|
{
|
||||||
ExpEmit v = ArgList[0]->Emit(build);
|
assert(ValueType == ArgList[0]->ValueType);
|
||||||
assert(!v.Konst && v.RegType == REGT_FLOAT);
|
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.Clear();
|
||||||
ArgList.ShrinkToFit();
|
ArgList.ShrinkToFit();
|
||||||
return v;
|
return to;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -696,6 +696,8 @@ begin:
|
||||||
OP(BOUND):
|
OP(BOUND):
|
||||||
if (reg.d[a] >= BC)
|
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);
|
THROW(X_ARRAY_OUT_OF_BOUNDS);
|
||||||
}
|
}
|
||||||
NEXTOP;
|
NEXTOP;
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
|
|
||||||
// Dragon -------------------------------------------------------------------
|
// Dragon -------------------------------------------------------------------
|
||||||
|
|
||||||
class Dragon : Actor
|
class Dragon : Actor
|
||||||
{
|
{
|
||||||
Default
|
Default
|
||||||
|
@ -23,13 +21,6 @@ class Dragon : Actor
|
||||||
Obituary "$OB_DRAGON";
|
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
|
States
|
||||||
{
|
{
|
||||||
Spawn:
|
Spawn:
|
||||||
|
@ -58,6 +49,253 @@ class Dragon : Actor
|
||||||
DRAG M -1;
|
DRAG M -1;
|
||||||
Stop;
|
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 ----------------------------------------------------------
|
// Dragon Fireball ----------------------------------------------------------
|
||||||
|
@ -77,8 +315,6 @@ class DragonFireball : Actor
|
||||||
DeathSound "DragonFireballExplode";
|
DeathSound "DragonFireballExplode";
|
||||||
}
|
}
|
||||||
|
|
||||||
native void A_DragonFX2();
|
|
||||||
|
|
||||||
States
|
States
|
||||||
{
|
{
|
||||||
Spawn:
|
Spawn:
|
||||||
|
@ -90,6 +326,30 @@ class DragonFireball : Actor
|
||||||
DRFX KL 3 Bright;
|
DRFX KL 3 Bright;
|
||||||
Stop;
|
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 --------------------------------------
|
// Dragon Fireball Secondary Explosion --------------------------------------
|
||||||
|
|
Loading…
Reference in a new issue