mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-10 14:51:51 +00:00
- converted half of ClericHoly. (Making a commit before starting on the more complex stuff.)
- added a 'constructor' for color values.
This commit is contained in:
parent
bc1e4eff72
commit
177aa6ec42
17 changed files with 455 additions and 368 deletions
|
@ -386,6 +386,7 @@ enum ActorFlag7
|
||||||
MF7_NOKILLSCRIPTS = 0x01000000, // [JM] No "KILL" Script on death whatsoever, even if forced by GameInfo.
|
MF7_NOKILLSCRIPTS = 0x01000000, // [JM] No "KILL" Script on death whatsoever, even if forced by GameInfo.
|
||||||
MF7_SPRITEANGLE = 0x02000000, // [MC] Utilize the SpriteAngle property and lock the rotation to the degrees specified.
|
MF7_SPRITEANGLE = 0x02000000, // [MC] Utilize the SpriteAngle property and lock the rotation to the degrees specified.
|
||||||
MF7_SMASHABLE = 0x04000000, // dies if hitting the floor.
|
MF7_SMASHABLE = 0x04000000, // dies if hitting the floor.
|
||||||
|
MF7_NOSHIELDREFLECT = 0x08000000, // will not be reflected by shields.
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- mobj.renderflags ---
|
// --- mobj.renderflags ---
|
||||||
|
|
|
@ -24,332 +24,8 @@ static FRandom pr_wraithvergedrop ("WraithvergeDrop");
|
||||||
|
|
||||||
void SpawnSpiritTail (AActor *spirit);
|
void SpawnSpiritTail (AActor *spirit);
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
// Cleric's Wraithverge (Holy Symbol?) --------------------------------------
|
|
||||||
|
|
||||||
class ACWeapWraithverge : public AClericWeapon
|
|
||||||
{
|
|
||||||
DECLARE_CLASS (ACWeapWraithverge, AClericWeapon)
|
|
||||||
public:
|
|
||||||
|
|
||||||
void Serialize(FSerializer &arc)
|
|
||||||
{
|
|
||||||
Super::Serialize (arc);
|
|
||||||
arc("cholycount", CHolyCount);
|
|
||||||
}
|
|
||||||
PalEntry GetBlend ()
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BYTE CHolyCount;
|
|
||||||
};
|
|
||||||
|
|
||||||
IMPLEMENT_CLASS(ACWeapWraithverge, false, false)
|
|
||||||
|
|
||||||
// Holy Spirit --------------------------------------------------------------
|
// Holy Spirit --------------------------------------------------------------
|
||||||
|
|
||||||
IMPLEMENT_CLASS(AHolySpirit, false, false)
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
P_DamageMobj(thing, this, target, dam, NAME_Melee);
|
|
||||||
if (pr_spiritslam() < 128)
|
|
||||||
{
|
|
||||||
Spawn("HolyPuff", Pos(), ALLOW_REPLACE);
|
|
||||||
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, double strength)
|
|
||||||
{
|
|
||||||
if (tracer == source)
|
|
||||||
{
|
|
||||||
tracer = target;
|
|
||||||
target = source;
|
|
||||||
GC::WriteBarrier(this, source);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
//
|
|
||||||
// A_CHolyAttack2
|
|
||||||
//
|
|
||||||
// Spawns the spirits
|
|
||||||
//============================================================================
|
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION(AActor, A_CHolyAttack2)
|
|
||||||
{
|
|
||||||
PARAM_SELF_PROLOGUE(AActor);
|
|
||||||
|
|
||||||
int j;
|
|
||||||
AActor *mo;
|
|
||||||
|
|
||||||
for (j = 0; j < 4; j++)
|
|
||||||
{
|
|
||||||
mo = Spawn<AHolySpirit> (self->Pos(), ALLOW_REPLACE);
|
|
||||||
if (!mo)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
switch (j)
|
|
||||||
{ // float bob index
|
|
||||||
|
|
||||||
case 0:
|
|
||||||
mo->WeaveIndexZ = pr_holyatk2() & 7; // upper-left
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
mo->WeaveIndexZ = 32 + (pr_holyatk2() & 7); // upper-right
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
mo->WeaveIndexXY = 32 + (pr_holyatk2() & 7); // lower-left
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
mo->WeaveIndexXY = 32 + (pr_holyatk2() & 7);
|
|
||||||
mo->WeaveIndexZ = 32 + (pr_holyatk2() & 7);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
mo->SetZ(self->Z());
|
|
||||||
mo->Angles.Yaw = self->Angles.Yaw + 67.5 - 45.*j;
|
|
||||||
mo->Thrust();
|
|
||||||
mo->target = self->target;
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
if (self->tracer)
|
|
||||||
{
|
|
||||||
mo->tracer = self->tracer;
|
|
||||||
mo->flags |= MF_NOCLIP|MF_SKULLFLY;
|
|
||||||
mo->flags &= ~MF_MISSILE;
|
|
||||||
}
|
|
||||||
SpawnSpiritTail (mo);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
//
|
|
||||||
// SpawnSpiritTail
|
|
||||||
//
|
|
||||||
//============================================================================
|
|
||||||
|
|
||||||
void SpawnSpiritTail (AActor *spirit)
|
|
||||||
{
|
|
||||||
AActor *tail, *next;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
tail = Spawn ("HolyTail", spirit->Pos(), ALLOW_REPLACE);
|
|
||||||
tail->target = spirit; // parent
|
|
||||||
for (i = 1; i < 3; i++)
|
|
||||||
{
|
|
||||||
next = Spawn ("HolyTailTrail", spirit->Pos(), ALLOW_REPLACE);
|
|
||||||
tail->tracer = next;
|
|
||||||
tail = next;
|
|
||||||
}
|
|
||||||
tail->tracer = NULL; // last tail bit
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
//
|
|
||||||
// A_CHolyAttack
|
|
||||||
//
|
|
||||||
//============================================================================
|
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION(AActor, A_CHolyAttack)
|
|
||||||
{
|
|
||||||
PARAM_ACTION_PROLOGUE(AActor);
|
|
||||||
|
|
||||||
player_t *player;
|
|
||||||
FTranslatedLineTarget t;
|
|
||||||
|
|
||||||
if (NULL == (player = self->player))
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
ACWeapWraithverge *weapon = static_cast<ACWeapWraithverge *> (self->player->ReadyWeapon);
|
|
||||||
if (weapon != NULL)
|
|
||||||
{
|
|
||||||
if (!weapon->DepleteAmmo (weapon->bAltFire))
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
AActor *missile = P_SpawnPlayerMissile (self, 0,0,0, PClass::FindActor("HolyMissile"), self->Angles.Yaw, &t);
|
|
||||||
if (missile != NULL && !t.unlinked)
|
|
||||||
{
|
|
||||||
missile->tracer = t.linetarget;
|
|
||||||
}
|
|
||||||
|
|
||||||
weapon->CHolyCount = 3;
|
|
||||||
S_Sound (self, CHAN_WEAPON, "HolySymbolFire", 1, ATTN_NORM);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
//
|
|
||||||
// A_CHolyPalette
|
|
||||||
//
|
|
||||||
//============================================================================
|
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION(AActor, A_CHolyPalette)
|
|
||||||
{
|
|
||||||
PARAM_ACTION_PROLOGUE(AActor);
|
|
||||||
|
|
||||||
if (self->player != NULL)
|
|
||||||
{
|
|
||||||
ACWeapWraithverge *weapon = static_cast<ACWeapWraithverge *> (self->player->ReadyWeapon);
|
|
||||||
if (weapon != NULL && weapon->CHolyCount != 0)
|
|
||||||
{
|
|
||||||
weapon->CHolyCount--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
//
|
|
||||||
// CHolyTailFollow
|
|
||||||
//
|
|
||||||
//============================================================================
|
|
||||||
|
|
||||||
static void CHolyTailFollow(AActor *actor, double dist)
|
|
||||||
{
|
|
||||||
AActor *child;
|
|
||||||
DAngle an;
|
|
||||||
double oldDistance, newDistance;
|
|
||||||
|
|
||||||
while (actor)
|
|
||||||
{
|
|
||||||
child = actor->tracer;
|
|
||||||
if (child)
|
|
||||||
{
|
|
||||||
an = actor->AngleTo(child);
|
|
||||||
oldDistance = child->Distance2D(actor);
|
|
||||||
if (P_TryMove(child, actor->Pos().XY() + an.ToVector(dist), true))
|
|
||||||
{
|
|
||||||
newDistance = child->Distance2D(actor) - 1;
|
|
||||||
if (oldDistance < 1)
|
|
||||||
{
|
|
||||||
if (child->Z() < actor->Z())
|
|
||||||
{
|
|
||||||
child->SetZ(actor->Z() - dist);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
child->SetZ(actor->Z() + dist);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
child->SetZ(actor->Z() + (newDistance * (child->Z() - actor->Z()) / oldDistance));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
actor = child;
|
|
||||||
dist -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
//
|
|
||||||
// CHolyTailRemove
|
|
||||||
//
|
|
||||||
//============================================================================
|
|
||||||
|
|
||||||
static void CHolyTailRemove (AActor *actor)
|
|
||||||
{
|
|
||||||
AActor *next;
|
|
||||||
|
|
||||||
while (actor)
|
|
||||||
{
|
|
||||||
next = actor->tracer;
|
|
||||||
actor->Destroy ();
|
|
||||||
actor = next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
//
|
|
||||||
// A_CHolyTail
|
|
||||||
//
|
|
||||||
//============================================================================
|
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION(AActor, A_CHolyTail)
|
|
||||||
{
|
|
||||||
PARAM_SELF_PROLOGUE(AActor);
|
|
||||||
|
|
||||||
AActor *parent;
|
|
||||||
|
|
||||||
parent = self->target;
|
|
||||||
|
|
||||||
if (parent == NULL || parent->health <= 0) // better check for health than current state - it's safer!
|
|
||||||
{ // Ghost removed, so remove all tail parts
|
|
||||||
CHolyTailRemove (self);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (P_TryMove(self, parent->Vec2Angle(14., parent->Angles.Yaw, true), true))
|
|
||||||
{
|
|
||||||
self->SetZ(parent->Z() - 5.);
|
|
||||||
}
|
|
||||||
CHolyTailFollow(self, 10);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
//
|
//
|
||||||
// CHolyFindTarget
|
// CHolyFindTarget
|
||||||
|
@ -495,22 +171,3 @@ DEFINE_ACTION_FUNCTION(AActor, A_CHolyCheckScream)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
//
|
|
||||||
// A_ClericAttack
|
|
||||||
// (for the ClericBoss)
|
|
||||||
//
|
|
||||||
//============================================================================
|
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION(AActor, A_ClericAttack)
|
|
||||||
{
|
|
||||||
PARAM_SELF_PROLOGUE(AActor);
|
|
||||||
|
|
||||||
if (!self->target) return 0;
|
|
||||||
|
|
||||||
AActor * missile = P_SpawnMissileZ (self, self->Z() + 40., self->target, PClass::FindActor ("HolyMissile"));
|
|
||||||
if (missile != NULL) missile->tracer = NULL; // No initial target
|
|
||||||
S_Sound (self, CHAN_WEAPON, "HolySymbolFire", 1, ATTN_NORM);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -5,14 +5,6 @@
|
||||||
|
|
||||||
void AdjustPlayerAngle(AActor *pmo, FTranslatedLineTarget *t);
|
void AdjustPlayerAngle(AActor *pmo, FTranslatedLineTarget *t);
|
||||||
|
|
||||||
class AHolySpirit : public AActor
|
|
||||||
{
|
|
||||||
DECLARE_CLASS (AHolySpirit, AActor)
|
|
||||||
public:
|
|
||||||
bool Slam (AActor *thing);
|
|
||||||
bool SpecialBlastHandling (AActor *source, double strength);
|
|
||||||
};
|
|
||||||
|
|
||||||
class AFighterWeapon : public AWeapon
|
class AFighterWeapon : public AWeapon
|
||||||
{
|
{
|
||||||
DECLARE_CLASS (AFighterWeapon, AWeapon);
|
DECLARE_CLASS (AFighterWeapon, AWeapon);
|
||||||
|
|
|
@ -189,8 +189,11 @@ void KSpiritInit (AActor *spirit, AActor *korax)
|
||||||
spirit->args[0] = 10; // initial turn value
|
spirit->args[0] = 10; // initial turn value
|
||||||
spirit->args[1] = 0; // initial look angle
|
spirit->args[1] = 0; // initial look angle
|
||||||
|
|
||||||
|
#if 0 // Temporarily deactivated.
|
||||||
// Spawn a tail for spirit
|
// Spawn a tail for spirit
|
||||||
SpawnSpiritTail (spirit);
|
HolyTail.SpawnSpiritTail (spirit);
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
|
|
|
@ -1324,6 +1324,27 @@ PalEntry AInventory::GetBlend ()
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(AInventory, GetBlend)
|
||||||
|
{
|
||||||
|
PARAM_SELF_PROLOGUE(AInventory);
|
||||||
|
ACTION_RETURN_INT(self->GetBlend());
|
||||||
|
}
|
||||||
|
|
||||||
|
PalEntry AInventory::CallGetBlend()
|
||||||
|
{
|
||||||
|
IFVIRTUAL(AInventory, GetBlend)
|
||||||
|
{
|
||||||
|
VMValue params[1] = { (DObject*)this };
|
||||||
|
VMReturn ret;
|
||||||
|
VMFrameStack stack;
|
||||||
|
int retval;
|
||||||
|
ret.IntAt(&retval);
|
||||||
|
stack.Call(func, params, 1, &ret, 1, nullptr);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
else return GetBlend();
|
||||||
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
//
|
//
|
||||||
// AInventory :: PrevItem
|
// AInventory :: PrevItem
|
||||||
|
|
|
@ -215,6 +215,7 @@ public:
|
||||||
virtual int AlterWeaponSprite (visstyle_t *vis);
|
virtual int AlterWeaponSprite (visstyle_t *vis);
|
||||||
|
|
||||||
virtual PalEntry GetBlend ();
|
virtual PalEntry GetBlend ();
|
||||||
|
PalEntry CallGetBlend();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool TryPickup (AActor *&toucher);
|
virtual bool TryPickup (AActor *&toucher);
|
||||||
|
|
|
@ -3284,6 +3284,13 @@ void AActor::Howl ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(AActor, Howl)
|
||||||
|
{
|
||||||
|
PARAM_SELF_PROLOGUE(AActor);
|
||||||
|
self->Howl();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool AActor::Slam (AActor *thing)
|
bool AActor::Slam (AActor *thing)
|
||||||
{
|
{
|
||||||
flags &= ~MF_SKULLFLY;
|
flags &= ~MF_SKULLFLY;
|
||||||
|
@ -3367,8 +3374,7 @@ bool AActor::AdjustReflectionAngle (AActor *thing, DAngle &angle)
|
||||||
if (absangle(angle, thing->Angles.Yaw) > 45)
|
if (absangle(angle, thing->Angles.Yaw) > 45)
|
||||||
return true; // Let missile explode
|
return true; // Let missile explode
|
||||||
|
|
||||||
if (thing->IsKindOf (RUNTIME_CLASS(AHolySpirit))) // shouldn't this be handled by another flag???
|
if (thing->flags7 & MF7_NOSHIELDREFLECT) return true;
|
||||||
return true;
|
|
||||||
|
|
||||||
if (pr_reflect () < 128)
|
if (pr_reflect () < 128)
|
||||||
angle += 45;
|
angle += 45;
|
||||||
|
@ -7349,6 +7355,16 @@ DEFINE_ACTION_FUNCTION(AActor, SetXYZ)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(AActor, Vec2Angle)
|
||||||
|
{
|
||||||
|
PARAM_SELF_PROLOGUE(AActor);
|
||||||
|
PARAM_FLOAT(length);
|
||||||
|
PARAM_ANGLE(angle);
|
||||||
|
PARAM_BOOL_DEF(absolute);
|
||||||
|
ACTION_RETURN_VEC2(self->Vec2Angle(length, angle, absolute));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION(AActor, Vec3Angle)
|
DEFINE_ACTION_FUNCTION(AActor, Vec3Angle)
|
||||||
{
|
{
|
||||||
PARAM_SELF_PROLOGUE(AActor);
|
PARAM_SELF_PROLOGUE(AActor);
|
||||||
|
|
|
@ -6969,13 +6969,19 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
|
||||||
|
|
||||||
switch (MethodName)
|
switch (MethodName)
|
||||||
{
|
{
|
||||||
|
case NAME_Color:
|
||||||
|
if (ArgList.Size() == 3 || ArgList.Size() == 4)
|
||||||
|
{
|
||||||
|
func = new FxColorLiteral(ArgList, ScriptPosition);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// fall through
|
||||||
case NAME_Bool:
|
case NAME_Bool:
|
||||||
case NAME_Int:
|
case NAME_Int:
|
||||||
case NAME_uInt:
|
case NAME_uInt:
|
||||||
case NAME_Float:
|
case NAME_Float:
|
||||||
case NAME_Double:
|
case NAME_Double:
|
||||||
case NAME_Name:
|
case NAME_Name:
|
||||||
case NAME_Color:
|
|
||||||
case NAME_Sound:
|
case NAME_Sound:
|
||||||
case NAME_State:
|
case NAME_State:
|
||||||
case NAME_SpriteID:
|
case NAME_SpriteID:
|
||||||
|
@ -8090,6 +8096,76 @@ ExpEmit FxGetClass::Emit(VMFunctionBuilder *build)
|
||||||
return to;
|
return to;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
FxColorLiteral::FxColorLiteral(FArgumentList &args, FScriptPosition &sc)
|
||||||
|
:FxExpression(EFX_ColorLiteral, sc)
|
||||||
|
{
|
||||||
|
ArgList = std::move(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
FxExpression *FxColorLiteral::Resolve(FCompileContext &ctx)
|
||||||
|
{
|
||||||
|
CHECKRESOLVED();
|
||||||
|
unsigned constelements = 0;
|
||||||
|
assert(ArgList.Size() == 3 || ArgList.Size() == 4);
|
||||||
|
if (ArgList.Size() == 3) ArgList.Insert(0, nullptr);
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
if (ArgList[i] != nullptr)
|
||||||
|
{
|
||||||
|
SAFE_RESOLVE(ArgList[i], ctx);
|
||||||
|
if (!ArgList[i]->IsInteger())
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "Integer expected for color component");
|
||||||
|
delete this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if (ArgList[i]->isConstant())
|
||||||
|
{
|
||||||
|
constval += clamp(static_cast<FxConstant *>(ArgList[i])->GetValue().GetInt(), 0, 255) << (24 - i * 8);
|
||||||
|
delete ArgList[i];
|
||||||
|
ArgList[i] = nullptr;
|
||||||
|
constelements++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else constelements++;
|
||||||
|
}
|
||||||
|
if (constelements == 4)
|
||||||
|
{
|
||||||
|
auto x = new FxConstant(constval, ScriptPosition);
|
||||||
|
x->ValueType = TypeColor;
|
||||||
|
delete this;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
ValueType = TypeColor;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpEmit FxColorLiteral::Emit(VMFunctionBuilder *build)
|
||||||
|
{
|
||||||
|
ExpEmit out(build, REGT_INT);
|
||||||
|
build->Emit(OP_LK, out.RegNum, build->GetConstantInt(constval));
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
if (ArgList[i] != nullptr)
|
||||||
|
{
|
||||||
|
assert(!ArgList[i]->isConstant());
|
||||||
|
ExpEmit in = ArgList[i]->Emit(build);
|
||||||
|
in.Free(build);
|
||||||
|
ExpEmit work(build, REGT_INT);
|
||||||
|
build->Emit(OP_MAX_RK, work.RegNum, in.RegNum, build->GetConstantInt(0));
|
||||||
|
build->Emit(OP_MIN_RK, work.RegNum, work.RegNum, build->GetConstantInt(255));
|
||||||
|
if (i != 3) build->Emit(OP_SLL_RI, work.RegNum, work.RegNum, 24 - (i * 8));
|
||||||
|
build->Emit(OP_OR_RR, out.RegNum, out.RegNum, work.RegNum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// FxSequence :: Resolve
|
// FxSequence :: Resolve
|
||||||
|
|
|
@ -287,6 +287,7 @@ enum EFxType
|
||||||
EFX_CVar,
|
EFX_CVar,
|
||||||
EFX_NamedNode,
|
EFX_NamedNode,
|
||||||
EFX_GetClass,
|
EFX_GetClass,
|
||||||
|
EFX_ColorLiteral,
|
||||||
EFX_COUNT
|
EFX_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1540,6 +1541,24 @@ public:
|
||||||
ExpEmit Emit(VMFunctionBuilder *build);
|
ExpEmit Emit(VMFunctionBuilder *build);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
//
|
||||||
|
// FxColorLiteral
|
||||||
|
//
|
||||||
|
//==========================================================================
|
||||||
|
|
||||||
|
class FxColorLiteral : public FxExpression
|
||||||
|
{
|
||||||
|
FArgumentList ArgList;
|
||||||
|
int constval = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
FxColorLiteral(FArgumentList &args, FScriptPosition &sc);
|
||||||
|
FxExpression *Resolve(FCompileContext&);
|
||||||
|
ExpEmit Emit(VMFunctionBuilder *build);
|
||||||
|
};
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
// FxVMFunctionCall
|
// FxVMFunctionCall
|
||||||
|
|
|
@ -296,6 +296,7 @@ static FFlagDef ActorFlagDefs[]=
|
||||||
DEFINE_FLAG(MF7, NOKILLSCRIPTS, AActor, flags7),
|
DEFINE_FLAG(MF7, NOKILLSCRIPTS, AActor, flags7),
|
||||||
DEFINE_FLAG(MF7, SPRITEANGLE, AActor, flags7),
|
DEFINE_FLAG(MF7, SPRITEANGLE, AActor, flags7),
|
||||||
DEFINE_FLAG(MF7, SMASHABLE, AActor, flags7),
|
DEFINE_FLAG(MF7, SMASHABLE, AActor, flags7),
|
||||||
|
DEFINE_FLAG(MF7, NOSHIELDREFLECT, AActor, flags7),
|
||||||
|
|
||||||
// Effect flags
|
// Effect flags
|
||||||
DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects),
|
DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects),
|
||||||
|
|
|
@ -740,7 +740,7 @@ type_name(X) ::= DOT dottable_id(A).
|
||||||
/* Type names can also be used as identifiers in contexts where type names
|
/* Type names can also be used as identifiers in contexts where type names
|
||||||
* are not normally allowed. */
|
* are not normally allowed. */
|
||||||
%fallback IDENTIFIER
|
%fallback IDENTIFIER
|
||||||
SBYTE BYTE SHORT USHORT INT UINT BOOL FLOAT DOUBLE STRING VECTOR2 VECTOR3 NAME MAP ARRAY VOID STATE.
|
SBYTE BYTE SHORT USHORT INT UINT BOOL FLOAT DOUBLE STRING VECTOR2 VECTOR3 NAME MAP ARRAY VOID STATE COLOR UINT8 INT8 UINT16 INT16.
|
||||||
|
|
||||||
/* Aggregate types */
|
/* Aggregate types */
|
||||||
%type aggregate_type {ZCC_Type *}
|
%type aggregate_type {ZCC_Type *}
|
||||||
|
|
|
@ -104,7 +104,7 @@ void V_AddPlayerBlend (player_t *CPlayer, float blend[4], float maxinvalpha, int
|
||||||
// [RH] All powerups can affect the screen blending now
|
// [RH] All powerups can affect the screen blending now
|
||||||
for (AInventory *item = CPlayer->mo->Inventory; item != NULL; item = item->Inventory)
|
for (AInventory *item = CPlayer->mo->Inventory; item != NULL; item = item->Inventory)
|
||||||
{
|
{
|
||||||
PalEntry color = item->GetBlend ();
|
PalEntry color = item->CallGetBlend ();
|
||||||
if (color.a != 0)
|
if (color.a != 0)
|
||||||
{
|
{
|
||||||
V_AddBlend (color.r/255.f, color.g/255.f, color.b/255.f, color.a/255.f, blend);
|
V_AddBlend (color.r/255.f, color.g/255.f, color.b/255.f, color.a/255.f, blend);
|
||||||
|
|
|
@ -339,6 +339,7 @@ class Actor : Thinker native
|
||||||
native void SetZ(double z);
|
native void SetZ(double z);
|
||||||
native vector3 Vec3Offset(double x, double y, double z, bool absolute = false);
|
native vector3 Vec3Offset(double x, double y, double z, bool absolute = false);
|
||||||
native vector3 Vec3Angle(double length, double angle, double z = 0, bool absolute = false);
|
native vector3 Vec3Angle(double length, double angle, double z = 0, bool absolute = false);
|
||||||
|
native vector2 Vec2Angle(double length, double angle, bool absolute = false);
|
||||||
native vector3 Vec2OffsetZ(double x, double y, double atz, bool absolute = false);
|
native vector3 Vec2OffsetZ(double x, double y, double atz, bool absolute = false);
|
||||||
native void VelFromAngle(double speed = 0, double angle = 0);
|
native void VelFromAngle(double speed = 0, double angle = 0);
|
||||||
native void Thrust(double speed = 0, double angle = 0);
|
native void Thrust(double speed = 0, double angle = 0);
|
||||||
|
@ -351,6 +352,7 @@ class Actor : Thinker native
|
||||||
native double DistanceBySpeed(Actor other, double speed);
|
native double DistanceBySpeed(Actor other, double speed);
|
||||||
native name GetSpecies();
|
native name GetSpecies();
|
||||||
native void PlayActiveSound();
|
native void PlayActiveSound();
|
||||||
|
native void Howl();
|
||||||
|
|
||||||
// DECORATE compatible functions
|
// DECORATE compatible functions
|
||||||
native bool CheckClass(class<Actor> checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false);
|
native bool CheckClass(class<Actor> checkclass, int ptr_select = AAPTR_DEFAULT, bool match_superclass = false);
|
||||||
|
|
|
@ -1007,3 +1007,11 @@ enum EGameType
|
||||||
GAME_DoomChex = GAME_Doom|GAME_Chex,
|
GAME_DoomChex = GAME_Doom|GAME_Chex,
|
||||||
GAME_DoomStrifeChex = GAME_Doom|GAME_Strife|GAME_Chex
|
GAME_DoomStrifeChex = GAME_Doom|GAME_Strife|GAME_Chex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum PaletteFlashFlags
|
||||||
|
{
|
||||||
|
PF_HEXENWEAPONS = 1,
|
||||||
|
PF_POISON = 2,
|
||||||
|
PF_ICE = 4,
|
||||||
|
PF_HAZARD = 8,
|
||||||
|
};
|
||||||
|
|
|
@ -18,8 +18,6 @@ class ClericBoss : Actor
|
||||||
Obituary "$OBCBOSS";
|
Obituary "$OBCBOSS";
|
||||||
}
|
}
|
||||||
|
|
||||||
native void A_ClericAttack();
|
|
||||||
|
|
||||||
States
|
States
|
||||||
{
|
{
|
||||||
Spawn:
|
Spawn:
|
||||||
|
@ -79,4 +77,19 @@ class ClericBoss : Actor
|
||||||
FDTH V 4 Bright ;
|
FDTH V 4 Bright ;
|
||||||
Stop;
|
Stop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// A_ClericAttack
|
||||||
|
//
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
void A_ClericAttack()
|
||||||
|
{
|
||||||
|
if (!target) return;
|
||||||
|
|
||||||
|
Actor missile = SpawnMissileZ (pos.z + 40., target, "HolyMissile");
|
||||||
|
if (missile != null) missile.tracer = null; // No initial target
|
||||||
|
A_PlaySound ("HolySymbolFire", CHAN_WEAPON);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,8 +76,10 @@ class WraithvergeDrop : Actor
|
||||||
|
|
||||||
// Cleric's Wraithverge (Holy Symbol?) --------------------------------------
|
// Cleric's Wraithverge (Holy Symbol?) --------------------------------------
|
||||||
|
|
||||||
class CWeapWraithverge : ClericWeapon native
|
class CWeapWraithverge : ClericWeapon
|
||||||
{
|
{
|
||||||
|
int CHolyCount;
|
||||||
|
|
||||||
Default
|
Default
|
||||||
{
|
{
|
||||||
Health 3;
|
Health 3;
|
||||||
|
@ -96,8 +98,6 @@ class CWeapWraithverge : ClericWeapon native
|
||||||
Inventory.PickupSound "WeaponBuild";
|
Inventory.PickupSound "WeaponBuild";
|
||||||
}
|
}
|
||||||
|
|
||||||
action native void A_CHolyAttack();
|
|
||||||
action native void A_CHolyPalette();
|
|
||||||
|
|
||||||
States
|
States
|
||||||
{
|
{
|
||||||
|
@ -122,6 +122,66 @@ class CWeapWraithverge : ClericWeapon native
|
||||||
CHLY G 2 Offset (0, 36) A_CHolyPalette;
|
CHLY G 2 Offset (0, 36) A_CHolyPalette;
|
||||||
Goto Ready;
|
Goto Ready;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override color GetBlend ()
|
||||||
|
{
|
||||||
|
if (paletteflash & PF_HEXENWEAPONS)
|
||||||
|
{
|
||||||
|
if (CHolyCount == 3)
|
||||||
|
return Color(128, 70, 70, 70);
|
||||||
|
else if (CHolyCount == 2)
|
||||||
|
return Color(128, 100, 100, 100);
|
||||||
|
else if (CHolyCount == 1)
|
||||||
|
return Color(128, 130, 130, 130);
|
||||||
|
else
|
||||||
|
return Color(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Color(CHolyCount * 128 / 3, 131, 131, 131);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// A_CHolyAttack
|
||||||
|
//
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
action void A_CHolyAttack()
|
||||||
|
{
|
||||||
|
FTranslatedLineTarget t;
|
||||||
|
|
||||||
|
if (player == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Weapon weapon = player.ReadyWeapon;
|
||||||
|
if (weapon != null)
|
||||||
|
{
|
||||||
|
if (!weapon.DepleteAmmo (weapon.bAltFire))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Actor missile = SpawnPlayerMissile ("HolyMissile", angle, pLineTarget:t);
|
||||||
|
if (missile != null && !t.unlinked)
|
||||||
|
{
|
||||||
|
missile.tracer = t.linetarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
invoker.CHolyCount = 3;
|
||||||
|
A_PlaySound ("HolySymbolFire", CHAN_WEAPON);
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// A_CHolyPalette
|
||||||
|
//
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
action void A_CHolyPalette()
|
||||||
|
{
|
||||||
|
if (invoker.CHolyCount > 0) invoker.CHolyCount--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Holy Missile -------------------------------------------------------------
|
// Holy Missile -------------------------------------------------------------
|
||||||
|
@ -139,8 +199,6 @@ class HolyMissile : Actor
|
||||||
+EXTREMEDEATH
|
+EXTREMEDEATH
|
||||||
}
|
}
|
||||||
|
|
||||||
native void A_CHolyAttack2();
|
|
||||||
|
|
||||||
States
|
States
|
||||||
{
|
{
|
||||||
Spawn:
|
Spawn:
|
||||||
|
@ -149,6 +207,60 @@ class HolyMissile : Actor
|
||||||
SPIR P 1 Bright A_CHolyAttack2;
|
SPIR P 1 Bright A_CHolyAttack2;
|
||||||
Stop;
|
Stop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// A_CHolyAttack2
|
||||||
|
//
|
||||||
|
// Spawns the spirits
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
void A_CHolyAttack2()
|
||||||
|
{
|
||||||
|
for (int j = 0; j < 4; j++)
|
||||||
|
{
|
||||||
|
Actor mo = Spawn("HolySpirit", Pos, ALLOW_REPLACE);
|
||||||
|
if (!mo)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (j)
|
||||||
|
{ // float bob index
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
mo.WeaveIndexZ = random[HolyAtk2]() & 7; // upper-left
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
mo.WeaveIndexZ = 32 + (random[HolyAtk2]() & 7); // upper-right
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
mo.WeaveIndexXY = 32 + (random[HolyAtk2]() & 7); // lower-left
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
mo.WeaveIndexXY = 32 + (random[HolyAtk2]() & 7);
|
||||||
|
mo.WeaveIndexZ = 32 + (random[HolyAtk2]() & 7);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
mo.SetZ(pos.z);
|
||||||
|
mo.angle = angle + 67.5 - 45.*j;
|
||||||
|
mo.Thrust();
|
||||||
|
mo.target = target;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
if (tracer)
|
||||||
|
{
|
||||||
|
mo.tracer = tracer;
|
||||||
|
mo.bNoClip = true;
|
||||||
|
mo.bSkullFly = true;
|
||||||
|
mo.bMissile = false;
|
||||||
|
}
|
||||||
|
HolyTail.SpawnSpiritTail (mo);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Holy Missile Puff --------------------------------------------------------
|
// Holy Missile Puff --------------------------------------------------------
|
||||||
|
@ -192,7 +304,7 @@ class HolyPuff : Actor
|
||||||
|
|
||||||
// Holy Spirit --------------------------------------------------------------
|
// Holy Spirit --------------------------------------------------------------
|
||||||
|
|
||||||
class HolySpirit : Actor native
|
class HolySpirit : Actor
|
||||||
{
|
{
|
||||||
Default
|
Default
|
||||||
{
|
{
|
||||||
|
@ -204,7 +316,7 @@ class HolySpirit : Actor native
|
||||||
Projectile;
|
Projectile;
|
||||||
+RIPPER +SEEKERMISSILE
|
+RIPPER +SEEKERMISSILE
|
||||||
+FOILINVUL +SKYEXPLODE +NOEXPLODEFLOOR +CANBLAST
|
+FOILINVUL +SKYEXPLODE +NOEXPLODEFLOOR +CANBLAST
|
||||||
+EXTREMEDEATH
|
+EXTREMEDEATH +NOSHIELDREFLECT
|
||||||
RenderStyle "Translucent";
|
RenderStyle "Translucent";
|
||||||
Alpha 0.4;
|
Alpha 0.4;
|
||||||
DeathSound "SpiritDie";
|
DeathSound "SpiritDie";
|
||||||
|
@ -226,6 +338,70 @@ class HolySpirit : Actor native
|
||||||
SPIR FGHI 4;
|
SPIR FGHI 4;
|
||||||
Stop;
|
Stop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
override bool Slam(Actor thing)
|
||||||
|
{
|
||||||
|
if (thing.bShootable && thing != target)
|
||||||
|
{
|
||||||
|
if (multiplayer && !deathmatch && thing.player && target.player)
|
||||||
|
{ // don't attack other co-op players
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (thing.bReflective && (thing.player || thing.bBoss))
|
||||||
|
{
|
||||||
|
tracer = target;
|
||||||
|
target = thing;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (thing.bIsMonster || thing.player)
|
||||||
|
{
|
||||||
|
tracer = thing;
|
||||||
|
}
|
||||||
|
if (random[SpiritSlam]() < 96)
|
||||||
|
{
|
||||||
|
int dam = 12;
|
||||||
|
if (thing.player || thing.bBoss)
|
||||||
|
{
|
||||||
|
dam = 3;
|
||||||
|
// ghost burns out faster when attacking players/bosses
|
||||||
|
health -= 6;
|
||||||
|
}
|
||||||
|
thing.DamageMobj(self, target, dam, 'Melee');
|
||||||
|
if (random[SpiritSlam]() < 128)
|
||||||
|
{
|
||||||
|
Spawn("HolyPuff", Pos, ALLOW_REPLACE);
|
||||||
|
A_PlaySound("SpiritAttack", CHAN_WEAPON);
|
||||||
|
if (thing.bIsMonster && random[SpiritSlam]() < 128)
|
||||||
|
{
|
||||||
|
thing.Howl();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (thing.health <= 0)
|
||||||
|
{
|
||||||
|
tracer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
override bool SpecialBlastHandling (Actor source, double strength)
|
||||||
|
{
|
||||||
|
if (tracer == source)
|
||||||
|
{
|
||||||
|
tracer = target;
|
||||||
|
target = source;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Holy Tail ----------------------------------------------------------------
|
// Holy Tail ----------------------------------------------------------------
|
||||||
|
@ -242,8 +418,6 @@ class HolyTail : Actor
|
||||||
Alpha 0.6;
|
Alpha 0.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
native void A_CHolyTail();
|
|
||||||
|
|
||||||
States
|
States
|
||||||
{
|
{
|
||||||
Spawn:
|
Spawn:
|
||||||
|
@ -253,6 +427,108 @@ class HolyTail : Actor
|
||||||
SPIR D -1;
|
SPIR D -1;
|
||||||
Stop;
|
Stop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// SpawnSpiritTail
|
||||||
|
//
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
static void SpawnSpiritTail (Actor spirit)
|
||||||
|
{
|
||||||
|
Actor tail = Spawn ("HolyTail", spirit.Pos, ALLOW_REPLACE);
|
||||||
|
tail.target = spirit; // parent
|
||||||
|
for (int i = 1; i < 3; i++)
|
||||||
|
{
|
||||||
|
Actor next = Spawn ("HolyTailTrail", spirit.Pos, ALLOW_REPLACE);
|
||||||
|
tail.tracer = next;
|
||||||
|
tail = next;
|
||||||
|
}
|
||||||
|
tail.tracer = null; // last tail bit
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// CHolyTailFollow
|
||||||
|
//
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
private void CHolyTailFollow(double dist)
|
||||||
|
{
|
||||||
|
Actor mo = self;
|
||||||
|
while (mo)
|
||||||
|
{
|
||||||
|
Actor child = mo.tracer;
|
||||||
|
if (child)
|
||||||
|
{
|
||||||
|
double an = mo.AngleTo(child);
|
||||||
|
double oldDistance = child.Distance2D(mo);
|
||||||
|
if (child.TryMove(mo.Pos.XY + AngleToVector(an, dist), true))
|
||||||
|
{
|
||||||
|
double newDistance = child.Distance2D(mo) - 1;
|
||||||
|
if (oldDistance < 1)
|
||||||
|
{
|
||||||
|
if (child.pos.z < mo.pos.z)
|
||||||
|
{
|
||||||
|
child.SetZ(mo.pos.z - dist);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
child.SetZ(mo.pos.z + dist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
child.SetZ(mo.pos.z + (newDistance * (child.pos.z - mo.pos.z) / oldDistance));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mo = child;
|
||||||
|
dist -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// CHolyTailRemove
|
||||||
|
//
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
private void CHolyTailRemove ()
|
||||||
|
{
|
||||||
|
Actor mo = self;
|
||||||
|
while (mo)
|
||||||
|
{
|
||||||
|
Actor next = mo.tracer;
|
||||||
|
mo.Destroy ();
|
||||||
|
mo = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// A_CHolyTail
|
||||||
|
//
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
void A_CHolyTail()
|
||||||
|
{
|
||||||
|
Actor parent = self.target;
|
||||||
|
|
||||||
|
if (parent == null || parent.health <= 0) // better check for health than current state - it's safer!
|
||||||
|
{ // Ghost removed, so remove all tail parts
|
||||||
|
CHolyTailRemove ();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (TryMove(parent.Vec2Angle(14., parent.Angle, true), true))
|
||||||
|
{
|
||||||
|
self.SetZ(parent.pos.z - 5.);
|
||||||
|
}
|
||||||
|
CHolyTailFollow(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Holy Tail Trail ---------------------------------------------------------
|
// Holy Tail Trail ---------------------------------------------------------
|
||||||
|
|
|
@ -26,6 +26,7 @@ class Inventory : Actor native
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual native bool Use (bool pickup);
|
virtual native bool Use (bool pickup);
|
||||||
|
virtual native color GetBlend ();
|
||||||
|
|
||||||
|
|
||||||
// These are regular functions for the item itself.
|
// These are regular functions for the item itself.
|
||||||
|
|
Loading…
Reference in a new issue