mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-01-31 13:50:48 +00:00
- scriptified the Sigil. This isn't fully tested yet.
This commit is contained in:
parent
c9a4087c18
commit
8551a4f6e1
19 changed files with 450 additions and 494 deletions
|
@ -3545,6 +3545,16 @@ const PClass *PClass::NativeClass() const
|
||||||
return cls;
|
return cls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VMFunction *PClass::FindFunction(FName clsname, FName funcname)
|
||||||
|
{
|
||||||
|
auto cls = PClass::FindActor(clsname);
|
||||||
|
if (!cls) return nullptr;
|
||||||
|
auto func = dyn_cast<PFunction>(cls->Symbols.FindSymbol(funcname, true));
|
||||||
|
if (!func) return nullptr;
|
||||||
|
return func->Variants[0].Implementation;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* FTypeTable **************************************************************/
|
/* FTypeTable **************************************************************/
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -859,6 +859,7 @@ public:
|
||||||
static PClassActor *FindActor(const FString &name) { return FindActor(FName(name, true)); }
|
static PClassActor *FindActor(const FString &name) { return FindActor(FName(name, true)); }
|
||||||
static PClassActor *FindActor(ENamedName name) { return FindActor(FName(name)); }
|
static PClassActor *FindActor(ENamedName name) { return FindActor(FName(name)); }
|
||||||
static PClassActor *FindActor(FName name);
|
static PClassActor *FindActor(FName name);
|
||||||
|
static VMFunction *FindFunction(FName cls, FName func);
|
||||||
PClass *FindClassTentative(FName name);
|
PClass *FindClassTentative(FName name);
|
||||||
|
|
||||||
static TArray<PClass *> AllClasses;
|
static TArray<PClass *> AllClasses;
|
||||||
|
|
|
@ -589,6 +589,28 @@ bool AInventory::SpecialDropAction (AActor *dropper)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(AInventory, SpecialDropAction)
|
||||||
|
{
|
||||||
|
PARAM_SELF_PROLOGUE(AInventory);
|
||||||
|
PARAM_OBJECT(dropper, AActor);
|
||||||
|
ACTION_RETURN_BOOL(self->SpecialDropAction(dropper));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AInventory::CallSpecialDropAction(AActor *dropper)
|
||||||
|
{
|
||||||
|
IFVIRTUAL(AInventory, SpecialDropAction)
|
||||||
|
{
|
||||||
|
VMValue params[2] = { (DObject*)this, (DObject*)dropper };
|
||||||
|
VMReturn ret;
|
||||||
|
VMFrameStack stack;
|
||||||
|
int retval;
|
||||||
|
ret.IntAt(&retval);
|
||||||
|
stack.Call(func, params, 2, &ret, 1, nullptr);
|
||||||
|
return !!retval;
|
||||||
|
}
|
||||||
|
return SpecialDropAction(dropper);
|
||||||
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
//
|
//
|
||||||
// AInventory :: ShouldRespawn
|
// AInventory :: ShouldRespawn
|
||||||
|
|
|
@ -168,6 +168,7 @@ public:
|
||||||
bool CallTryPickup (AActor *toucher, AActor **toucher_return = NULL);
|
bool CallTryPickup (AActor *toucher, AActor **toucher_return = NULL);
|
||||||
virtual void DoPickupSpecial (AActor *toucher);
|
virtual void DoPickupSpecial (AActor *toucher);
|
||||||
virtual bool SpecialDropAction (AActor *dropper);
|
virtual bool SpecialDropAction (AActor *dropper);
|
||||||
|
bool CallSpecialDropAction(AActor *dropper);
|
||||||
virtual bool DrawPowerup (int x, int y);
|
virtual bool DrawPowerup (int x, int y);
|
||||||
virtual void DoEffect ();
|
virtual void DoEffect ();
|
||||||
virtual bool Grind(bool items);
|
virtual bool Grind(bool items);
|
||||||
|
|
|
@ -268,7 +268,7 @@ class CommandDrawImage : public SBarInfoCommandFlowControl
|
||||||
}
|
}
|
||||||
else if(type == SIGIL)
|
else if(type == SIGIL)
|
||||||
{
|
{
|
||||||
AInventory *item = statusBar->CPlayer->mo->FindInventory<ASigil>();
|
AInventory *item = statusBar->CPlayer->mo->FindInventory(PClass::FindActor(NAME_Sigil));
|
||||||
if (item != NULL)
|
if (item != NULL)
|
||||||
texture = TexMan(item->Icon);
|
texture = TexMan(item->Icon);
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,20 +49,6 @@ public:
|
||||||
bool TryPickup (AActor *&toucher);
|
bool TryPickup (AActor *&toucher);
|
||||||
};
|
};
|
||||||
|
|
||||||
class ASigil : public AWeapon
|
|
||||||
{
|
|
||||||
DECLARE_CLASS (ASigil, AWeapon)
|
|
||||||
public:
|
|
||||||
bool HandlePickup (AInventory *item);
|
|
||||||
AInventory *CreateCopy (AActor *other);
|
|
||||||
|
|
||||||
void Serialize(FSerializer &arc);
|
|
||||||
bool SpecialDropAction (AActor *dropper);
|
|
||||||
static int GiveSigilPiece (AActor *daPlayer);
|
|
||||||
void BeginPlay();
|
|
||||||
|
|
||||||
int NumPieces, DownPieces;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern PClassActor *QuestItemClasses[31];
|
extern PClassActor *QuestItemClasses[31];
|
||||||
|
|
||||||
|
|
|
@ -698,435 +698,3 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireGrenade)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Almighty Sigil! ------------------------------------------------------
|
|
||||||
|
|
||||||
IMPLEMENT_CLASS(ASigil, false, false)
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
//
|
|
||||||
// ASigil :: Serialize
|
|
||||||
//
|
|
||||||
//============================================================================
|
|
||||||
|
|
||||||
void ASigil::BeginPlay()
|
|
||||||
{
|
|
||||||
NumPieces = health;
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
//
|
|
||||||
// ASigil :: Serialize
|
|
||||||
//
|
|
||||||
//============================================================================
|
|
||||||
|
|
||||||
void ASigil::Serialize(FSerializer &arc)
|
|
||||||
{
|
|
||||||
Super::Serialize (arc);
|
|
||||||
arc("numpieces", NumPieces)
|
|
||||||
("downpieces", DownPieces);
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
//
|
|
||||||
// ASigil :: HandlePickup
|
|
||||||
//
|
|
||||||
//============================================================================
|
|
||||||
|
|
||||||
bool ASigil::HandlePickup (AInventory *item)
|
|
||||||
{
|
|
||||||
if (item->IsKindOf (RUNTIME_CLASS(ASigil)))
|
|
||||||
{
|
|
||||||
int otherPieces = static_cast<ASigil*>(item)->NumPieces;
|
|
||||||
if (otherPieces > NumPieces)
|
|
||||||
{
|
|
||||||
item->ItemFlags |= IF_PICKUPGOOD;
|
|
||||||
Icon = item->Icon;
|
|
||||||
// If the player is holding the Sigil right now, drop it and bring
|
|
||||||
// it back with the new piece(s) in view.
|
|
||||||
if (Owner->player != NULL && Owner->player->ReadyWeapon == this)
|
|
||||||
{
|
|
||||||
DownPieces = NumPieces;
|
|
||||||
Owner->player->PendingWeapon = this;
|
|
||||||
}
|
|
||||||
NumPieces = otherPieces;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
//
|
|
||||||
// ASigil :: CreateCopy
|
|
||||||
//
|
|
||||||
//============================================================================
|
|
||||||
|
|
||||||
AInventory *ASigil::CreateCopy (AActor *other)
|
|
||||||
{
|
|
||||||
ASigil *copy = Spawn<ASigil> ();
|
|
||||||
copy->Amount = Amount;
|
|
||||||
copy->MaxAmount = MaxAmount;
|
|
||||||
copy->NumPieces = NumPieces;
|
|
||||||
copy->Icon = Icon;
|
|
||||||
GoAwayAndDie ();
|
|
||||||
return copy;
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
//
|
|
||||||
// A_SelectPiece
|
|
||||||
//
|
|
||||||
// Decide which sprite frame this Sigil should use as an item, based on how
|
|
||||||
// many pieces it represents.
|
|
||||||
//
|
|
||||||
//============================================================================
|
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION(AActor, A_SelectPiece)
|
|
||||||
{
|
|
||||||
PARAM_ACTION_PROLOGUE(AActor);
|
|
||||||
|
|
||||||
int pieces = MIN (static_cast<ASigil*>(self)->NumPieces, 5);
|
|
||||||
|
|
||||||
if (pieces > 1)
|
|
||||||
{
|
|
||||||
self->SetState (self->FindState("Spawn")+pieces);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
//
|
|
||||||
// A_SelectSigilView
|
|
||||||
//
|
|
||||||
// Decide which first-person frame this Sigil should show, based on how many
|
|
||||||
// pieces it represents. Strife did this by selecting a flash that looked like
|
|
||||||
// the Sigil whenever you switched to it and at the end of an attack. I have
|
|
||||||
// chosen to make the weapon sprite choose the correct frame and let the flash
|
|
||||||
// be a regular flash. It means I need to use more states, but I think it's
|
|
||||||
// worth it.
|
|
||||||
//
|
|
||||||
//============================================================================
|
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION(AActor, A_SelectSigilView)
|
|
||||||
{
|
|
||||||
PARAM_ACTION_PROLOGUE(AActor);
|
|
||||||
|
|
||||||
DPSprite *pspr;
|
|
||||||
int pieces;
|
|
||||||
|
|
||||||
if (self->player == nullptr)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
pieces = static_cast<ASigil*>(self->player->ReadyWeapon)->NumPieces;
|
|
||||||
pspr = self->player->GetPSprite(PSP_WEAPON);
|
|
||||||
pspr->SetState(pspr->GetState() + pieces);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
//
|
|
||||||
// A_SelectSigilDown
|
|
||||||
//
|
|
||||||
// Same as A_SelectSigilView, except it uses DownPieces. This is so that when
|
|
||||||
// you pick up a Sigil, the old one will drop and *then* change to the new
|
|
||||||
// one.
|
|
||||||
//
|
|
||||||
//============================================================================
|
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION(AActor, A_SelectSigilDown)
|
|
||||||
{
|
|
||||||
PARAM_ACTION_PROLOGUE(AActor);
|
|
||||||
|
|
||||||
DPSprite *pspr;
|
|
||||||
int pieces;
|
|
||||||
|
|
||||||
if (self->player == nullptr)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
pieces = static_cast<ASigil*>(self->player->ReadyWeapon)->DownPieces;
|
|
||||||
static_cast<ASigil*>(self->player->ReadyWeapon)->DownPieces = 0;
|
|
||||||
if (pieces == 0)
|
|
||||||
{
|
|
||||||
pieces = static_cast<ASigil*>(self->player->ReadyWeapon)->NumPieces;
|
|
||||||
}
|
|
||||||
pspr = self->player->GetPSprite(PSP_WEAPON);
|
|
||||||
pspr->SetState(pspr->GetState() + pieces);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
//
|
|
||||||
// A_SelectSigilAttack
|
|
||||||
//
|
|
||||||
// Same as A_SelectSigilView, but used just before attacking.
|
|
||||||
//
|
|
||||||
//============================================================================
|
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION(AActor, A_SelectSigilAttack)
|
|
||||||
{
|
|
||||||
PARAM_ACTION_PROLOGUE(AActor);
|
|
||||||
|
|
||||||
DPSprite *pspr;
|
|
||||||
int pieces;
|
|
||||||
|
|
||||||
if (self->player == nullptr)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
pieces = static_cast<ASigil*>(self->player->ReadyWeapon)->NumPieces;
|
|
||||||
pspr = self->player->GetPSprite(PSP_WEAPON);
|
|
||||||
pspr->SetState(pspr->GetState() + 4*pieces - 3);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
//
|
|
||||||
// A_SigilCharge
|
|
||||||
//
|
|
||||||
//============================================================================
|
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION(AActor, A_SigilCharge)
|
|
||||||
{
|
|
||||||
PARAM_ACTION_PROLOGUE(AActor);
|
|
||||||
|
|
||||||
S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM);
|
|
||||||
if (self->player != NULL)
|
|
||||||
{
|
|
||||||
self->player->extralight = 2;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
//
|
|
||||||
// A_FireSigil1
|
|
||||||
//
|
|
||||||
//============================================================================
|
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION(AActor, A_FireSigil1)
|
|
||||||
{
|
|
||||||
PARAM_ACTION_PROLOGUE(AActor);
|
|
||||||
|
|
||||||
AActor *spot;
|
|
||||||
player_t *player = self->player;
|
|
||||||
FTranslatedLineTarget t;
|
|
||||||
|
|
||||||
if (player == NULL || player->ReadyWeapon == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
P_DamageMobj (self, self, NULL, 1*4, 0, DMG_NO_ARMOR);
|
|
||||||
S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM);
|
|
||||||
|
|
||||||
P_BulletSlope (self, &t, ALF_PORTALRESTRICT);
|
|
||||||
if (t.linetarget != NULL)
|
|
||||||
{
|
|
||||||
spot = Spawn("SpectralLightningSpot", t.linetarget->PosAtZ(t.linetarget->floorz), ALLOW_REPLACE);
|
|
||||||
if (spot != NULL)
|
|
||||||
{
|
|
||||||
spot->tracer = t.linetarget;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
spot = Spawn("SpectralLightningSpot", self->Pos(), ALLOW_REPLACE);
|
|
||||||
if (spot != NULL)
|
|
||||||
{
|
|
||||||
spot->VelFromAngle(28., self->Angles.Yaw);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (spot != NULL)
|
|
||||||
{
|
|
||||||
spot->SetFriendPlayer(player);
|
|
||||||
spot->target = self;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
//
|
|
||||||
// A_FireSigil2
|
|
||||||
//
|
|
||||||
//============================================================================
|
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION(AActor, A_FireSigil2)
|
|
||||||
{
|
|
||||||
PARAM_ACTION_PROLOGUE(AActor);
|
|
||||||
|
|
||||||
player_t *player = self->player;
|
|
||||||
|
|
||||||
if (player == NULL || player->ReadyWeapon == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
P_DamageMobj (self, self, NULL, 2*4, 0, DMG_NO_ARMOR);
|
|
||||||
S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM);
|
|
||||||
|
|
||||||
P_SpawnPlayerMissile (self, PClass::FindActor("SpectralLightningH1"));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
//
|
|
||||||
// A_FireSigil3
|
|
||||||
//
|
|
||||||
//============================================================================
|
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION(AActor, A_FireSigil3)
|
|
||||||
{
|
|
||||||
PARAM_ACTION_PROLOGUE(AActor);
|
|
||||||
|
|
||||||
AActor *spot;
|
|
||||||
player_t *player = self->player;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (player == NULL || player->ReadyWeapon == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
P_DamageMobj (self, self, NULL, 3*4, 0, DMG_NO_ARMOR);
|
|
||||||
S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM);
|
|
||||||
|
|
||||||
self->Angles.Yaw -= 90.;
|
|
||||||
for (i = 0; i < 20; ++i)
|
|
||||||
{
|
|
||||||
self->Angles.Yaw += 9.;
|
|
||||||
spot = P_SpawnSubMissile (self, PClass::FindActor("SpectralLightningBall1"), self);
|
|
||||||
if (spot != NULL)
|
|
||||||
{
|
|
||||||
spot->SetZ(self->Z() + 32);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self->Angles.Yaw -= 90.;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
//
|
|
||||||
// A_FireSigil4
|
|
||||||
//
|
|
||||||
//============================================================================
|
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION(AActor, A_FireSigil4)
|
|
||||||
{
|
|
||||||
PARAM_ACTION_PROLOGUE(AActor);
|
|
||||||
|
|
||||||
AActor *spot;
|
|
||||||
player_t *player = self->player;
|
|
||||||
FTranslatedLineTarget t;
|
|
||||||
|
|
||||||
if (player == NULL || player->ReadyWeapon == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
P_DamageMobj (self, self, NULL, 4*4, 0, DMG_NO_ARMOR);
|
|
||||||
S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM);
|
|
||||||
|
|
||||||
P_BulletSlope (self, &t, ALF_PORTALRESTRICT);
|
|
||||||
if (t.linetarget != NULL)
|
|
||||||
{
|
|
||||||
spot = P_SpawnPlayerMissile (self, 0,0,0, PClass::FindActor("SpectralLightningBigV1"), self->Angles.Yaw, &t, NULL, false, false, ALF_PORTALRESTRICT);
|
|
||||||
if (spot != NULL)
|
|
||||||
{
|
|
||||||
spot->tracer = t.linetarget;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
spot = P_SpawnPlayerMissile (self, PClass::FindActor("SpectralLightningBigV1"));
|
|
||||||
if (spot != NULL)
|
|
||||||
{
|
|
||||||
spot->VelFromAngle(spot->Speed, self->Angles.Yaw);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
//
|
|
||||||
// A_FireSigil5
|
|
||||||
//
|
|
||||||
//============================================================================
|
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION(AActor, A_FireSigil5)
|
|
||||||
{
|
|
||||||
PARAM_ACTION_PROLOGUE(AActor);
|
|
||||||
|
|
||||||
player_t *player = self->player;
|
|
||||||
|
|
||||||
if (player == NULL || player->ReadyWeapon == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
P_DamageMobj (self, self, NULL, 5*4, 0, DMG_NO_ARMOR);
|
|
||||||
S_Sound (self, CHAN_WEAPON, "weapons/sigilcharge", 1, ATTN_NORM);
|
|
||||||
|
|
||||||
P_SpawnPlayerMissile (self, PClass::FindActor("SpectralLightningBigBall1"));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
//
|
|
||||||
// ASigil :: SpecialDropAction
|
|
||||||
//
|
|
||||||
// Monsters don't drop Sigil pieces. The Sigil pieces grab hold of the person
|
|
||||||
// who killed the dropper and automatically enter their inventory. That's the
|
|
||||||
// way it works if you believe Macil, anyway...
|
|
||||||
//
|
|
||||||
//============================================================================
|
|
||||||
|
|
||||||
bool ASigil::SpecialDropAction (AActor *dropper)
|
|
||||||
{
|
|
||||||
// Give a Sigil piece to every player in the game
|
|
||||||
for (int i = 0; i < MAXPLAYERS; ++i)
|
|
||||||
{
|
|
||||||
if (playeringame[i] && players[i].mo != NULL)
|
|
||||||
{
|
|
||||||
GiveSigilPiece (players[i].mo);
|
|
||||||
Destroy ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//============================================================================
|
|
||||||
//
|
|
||||||
// ASigil :: GiveSigilPiece
|
|
||||||
//
|
|
||||||
// Gives the actor another Sigil piece, up to 5. Returns the number of Sigil
|
|
||||||
// pieces the actor previously held.
|
|
||||||
//
|
|
||||||
//============================================================================
|
|
||||||
|
|
||||||
int ASigil::GiveSigilPiece (AActor *receiver)
|
|
||||||
{
|
|
||||||
ASigil *sigil;
|
|
||||||
|
|
||||||
sigil = receiver->FindInventory<ASigil> ();
|
|
||||||
if (sigil == NULL)
|
|
||||||
{
|
|
||||||
sigil = static_cast<ASigil*>(Spawn("Sigil1"));
|
|
||||||
if (!sigil->CallTryPickup (receiver))
|
|
||||||
{
|
|
||||||
sigil->Destroy ();
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else if (sigil->NumPieces < 5)
|
|
||||||
{
|
|
||||||
++sigil->NumPieces;
|
|
||||||
static const char* sigils[5] =
|
|
||||||
{
|
|
||||||
"Sigil1", "Sigil2", "Sigil3", "Sigil4", "Sigil5"
|
|
||||||
};
|
|
||||||
sigil->Icon = ((AInventory*)GetDefaultByName (sigils[MAX(0,sigil->NumPieces-1)]))->Icon;
|
|
||||||
// If the player has the Sigil out, drop it and bring it back up.
|
|
||||||
if (sigil->Owner->player != NULL && sigil->Owner->player->ReadyWeapon == sigil)
|
|
||||||
{
|
|
||||||
sigil->Owner->player->PendingWeapon = sigil;
|
|
||||||
sigil->DownPieces = sigil->NumPieces - 1;
|
|
||||||
}
|
|
||||||
return sigil->NumPieces - 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -439,7 +439,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sigil
|
// Sigil
|
||||||
item = CPlayer->mo->FindInventory<ASigil>();
|
item = CPlayer->mo->FindInventory(PClass::FindActor(NAME_Sigil));
|
||||||
if (item != NULL)
|
if (item != NULL)
|
||||||
{
|
{
|
||||||
DrawImage (TexMan(item->Icon), 253, 7);
|
DrawImage (TexMan(item->Icon), 253, 7);
|
||||||
|
|
|
@ -483,18 +483,28 @@ void cht_DoCheat (player_t *player, int cheat)
|
||||||
case CHT_LEGO:
|
case CHT_LEGO:
|
||||||
if (player->mo != NULL && player->health >= 0)
|
if (player->mo != NULL && player->health >= 0)
|
||||||
{
|
{
|
||||||
int oldpieces = ASigil::GiveSigilPiece (player->mo);
|
static VMFunction *gsp = nullptr;
|
||||||
item = player->mo->FindInventory (RUNTIME_CLASS(ASigil));
|
if (gsp == nullptr) gsp = PClass::FindFunction(NAME_Sigil, NAME_GiveSigilPiece);
|
||||||
|
if (gsp)
|
||||||
if (item != NULL)
|
|
||||||
{
|
{
|
||||||
if (oldpieces == 5)
|
VMValue params[1] = { player->mo };
|
||||||
|
VMFrameStack stack;
|
||||||
|
VMReturn ret;
|
||||||
|
int oldpieces = 1;
|
||||||
|
ret.IntAt(&oldpieces);
|
||||||
|
stack.Call(gsp, params, 1, &ret, 1, nullptr);
|
||||||
|
item = player->mo->FindInventory(PClass::FindActor(NAME_Sigil));
|
||||||
|
|
||||||
|
if (item != NULL)
|
||||||
{
|
{
|
||||||
item->Destroy ();
|
if (oldpieces == 5)
|
||||||
}
|
{
|
||||||
else
|
item->Destroy();
|
||||||
{
|
}
|
||||||
player->PendingWeapon = static_cast<AWeapon *> (item);
|
else
|
||||||
|
{
|
||||||
|
player->PendingWeapon = static_cast<AWeapon *> (item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,6 +120,11 @@ xx(ArtiPoisonBag3)
|
||||||
|
|
||||||
// Strife quests
|
// Strife quests
|
||||||
xx(QuestItem)
|
xx(QuestItem)
|
||||||
|
xx(Sigil)
|
||||||
|
xx(ScriptedMarine)
|
||||||
|
xx(GiveSigilPiece)
|
||||||
|
xx(SetWeapon)
|
||||||
|
xx(SetSprite)
|
||||||
|
|
||||||
// Armor
|
// Armor
|
||||||
xx(BasicArmor)
|
xx(BasicArmor)
|
||||||
|
|
|
@ -6112,29 +6112,25 @@ static bool CharArrayParms(int &capacity, int &offset, int &a, int *Stack, int &
|
||||||
static void SetMarineWeapon(AActor *marine, int weapon)
|
static void SetMarineWeapon(AActor *marine, int weapon)
|
||||||
{
|
{
|
||||||
static VMFunction *smw = nullptr;
|
static VMFunction *smw = nullptr;
|
||||||
if (smw == nullptr)
|
if (smw == nullptr) smw = PClass::FindFunction(NAME_ScriptedMarine, NAME_SetWeapon);
|
||||||
|
if (smw)
|
||||||
{
|
{
|
||||||
auto cls = PClass::FindActor("ScriptedMarine");
|
VMValue params[2] = { marine, weapon };
|
||||||
auto func = dyn_cast<PFunction>(cls->Symbols.FindSymbol("SetWeapon", true));
|
VMFrameStack stack;
|
||||||
smw = func->Variants[0].Implementation;
|
stack.Call(smw, params, 2, nullptr, 0, nullptr);
|
||||||
}
|
}
|
||||||
VMValue params[2] = { marine, weapon };
|
|
||||||
VMFrameStack stack;
|
|
||||||
stack.Call(smw, params, 2, nullptr, 0, nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SetMarineSprite(AActor *marine, PClassActor *source)
|
static void SetMarineSprite(AActor *marine, PClassActor *source)
|
||||||
{
|
{
|
||||||
static VMFunction *sms = nullptr;
|
static VMFunction *sms = nullptr;
|
||||||
if (sms == nullptr)
|
if (sms == nullptr) sms = PClass::FindFunction(NAME_ScriptedMarine, NAME_SetSprite);
|
||||||
|
if (sms)
|
||||||
{
|
{
|
||||||
auto cls = PClass::FindActor("ScriptedMarine");
|
VMValue params[2] = { marine, source };
|
||||||
auto func = dyn_cast<PFunction>(cls->Symbols.FindSymbol("SetSprite", true));
|
VMFrameStack stack;
|
||||||
sms = func->Variants[0].Implementation;
|
stack.Call(sms, params, 2, nullptr, 0, nullptr);
|
||||||
}
|
}
|
||||||
VMValue params[2] = { marine, source };
|
|
||||||
VMFrameStack stack;
|
|
||||||
stack.Call(sms, params, 2, nullptr, 0, nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int DLevelScript::RunScript ()
|
int DLevelScript::RunScript ()
|
||||||
|
@ -8577,15 +8573,15 @@ scriptwait:
|
||||||
|
|
||||||
case PCD_GETSIGILPIECES:
|
case PCD_GETSIGILPIECES:
|
||||||
{
|
{
|
||||||
ASigil *sigil;
|
AInventory *sigil;
|
||||||
|
|
||||||
if (activator == NULL || (sigil = activator->FindInventory<ASigil>()) == NULL)
|
if (activator == NULL || (sigil = activator->FindInventory(PClass::FindActor(NAME_Sigil))) == NULL)
|
||||||
{
|
{
|
||||||
PushToStack (0);
|
PushToStack (0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PushToStack (sigil->NumPieces);
|
PushToStack (sigil->health);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -646,7 +646,7 @@ static void TakeStrifeItem (player_t *player, PClassActor *itemtype, int amount)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Don't take the sigil.
|
// Don't take the sigil.
|
||||||
if (itemtype == RUNTIME_CLASS(ASigil))
|
if (itemtype->GetClass()->TypeName == NAME_Sigil)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
player->mo->TakeInventory(itemtype, amount);
|
player->mo->TakeInventory(itemtype, amount);
|
||||||
|
|
|
@ -3209,7 +3209,7 @@ AInventory *P_DropItem (AActor *source, PClassActor *type, int dropamount, int c
|
||||||
AInventory *inv = static_cast<AInventory *>(mo);
|
AInventory *inv = static_cast<AInventory *>(mo);
|
||||||
ModifyDropAmount(inv, dropamount);
|
ModifyDropAmount(inv, dropamount);
|
||||||
inv->ItemFlags |= IF_TOSSED;
|
inv->ItemFlags |= IF_TOSSED;
|
||||||
if (inv->SpecialDropAction (source))
|
if (inv->CallSpecialDropAction (source))
|
||||||
{
|
{
|
||||||
// The special action indicates that the item should not spawn
|
// The special action indicates that the item should not spawn
|
||||||
inv->Destroy();
|
inv->Destroy();
|
||||||
|
|
|
@ -439,6 +439,15 @@ void DPSprite::SetState(FState *newstate, bool pending)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_ACTION_FUNCTION(DPSprite, SetState)
|
||||||
|
{
|
||||||
|
PARAM_SELF_PROLOGUE(DPSprite);
|
||||||
|
PARAM_POINTER(state, FState);
|
||||||
|
PARAM_BOOL_DEF(pending);
|
||||||
|
self->SetState(state, pending);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// PROC P_BringUpWeapon
|
// PROC P_BringUpWeapon
|
||||||
|
|
|
@ -2408,7 +2408,7 @@ static bool CheckRandom(ZCC_Expression *duration)
|
||||||
// Sets up the action function call
|
// Sets up the action function call
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
FxExpression *ZCCCompiler::SetupActionFunction(PClass *cls, ZCC_TreeNode *af)
|
FxExpression *ZCCCompiler::SetupActionFunction(PClass *cls, ZCC_TreeNode *af, int StateFlags)
|
||||||
{
|
{
|
||||||
// We have 3 cases to consider here:
|
// We have 3 cases to consider here:
|
||||||
// 1. A function without parameters. This can be called directly
|
// 1. A function without parameters. This can be called directly
|
||||||
|
@ -2436,7 +2436,9 @@ FxExpression *ZCCCompiler::SetupActionFunction(PClass *cls, ZCC_TreeNode *af)
|
||||||
// We can use this function directly without wrapping it in a caller.
|
// We can use this function directly without wrapping it in a caller.
|
||||||
auto selfclass = dyn_cast<PClass>(afd->Variants[0].SelfClass);
|
auto selfclass = dyn_cast<PClass>(afd->Variants[0].SelfClass);
|
||||||
assert(selfclass != nullptr); // non classes are not supposed to get here.
|
assert(selfclass != nullptr); // non classes are not supposed to get here.
|
||||||
if ((afd->Variants[0].Flags & VARF_Action) || !cls->IsDescendantOf(RUNTIME_CLASS(AStateProvider)) || !selfclass->IsDescendantOf(RUNTIME_CLASS(AStateProvider)))
|
|
||||||
|
int comboflags = afd->Variants[0].UseFlags & StateFlags;
|
||||||
|
if (comboflags == StateFlags) // the function must satisfy all the flags the state requires
|
||||||
{
|
{
|
||||||
return new FxVMFunctionCall(new FxSelf(*af), afd, argumentlist, *af, false);
|
return new FxVMFunctionCall(new FxSelf(*af), afd, argumentlist, *af, false);
|
||||||
}
|
}
|
||||||
|
@ -2627,7 +2629,7 @@ void ZCCCompiler::CompileStates()
|
||||||
|
|
||||||
if (sl->Action != nullptr)
|
if (sl->Action != nullptr)
|
||||||
{
|
{
|
||||||
auto code = SetupActionFunction(static_cast<PClassActor *>(c->Type()), sl->Action);
|
auto code = SetupActionFunction(static_cast<PClassActor *>(c->Type()), sl->Action, state.UseFlags);
|
||||||
if (code != nullptr)
|
if (code != nullptr)
|
||||||
{
|
{
|
||||||
auto funcsym = CreateAnonymousFunction(c->Type(), nullptr, state.UseFlags);
|
auto funcsym = CreateAnonymousFunction(c->Type(), nullptr, state.UseFlags);
|
||||||
|
|
|
@ -108,7 +108,7 @@ private:
|
||||||
|
|
||||||
void InitFunctions();
|
void InitFunctions();
|
||||||
void CompileStates();
|
void CompileStates();
|
||||||
FxExpression *SetupActionFunction(PClass *cls, ZCC_TreeNode *sl);
|
FxExpression *SetupActionFunction(PClass *cls, ZCC_TreeNode *sl, int stateflags);
|
||||||
|
|
||||||
bool SimplifyingConstant;
|
bool SimplifyingConstant;
|
||||||
TArray<ZCC_ConstantDef *> Constants;
|
TArray<ZCC_ConstantDef *> Constants;
|
||||||
|
|
|
@ -29,6 +29,7 @@ class Inventory : Actor native
|
||||||
virtual native color GetBlend ();
|
virtual native color GetBlend ();
|
||||||
virtual native bool HandlePickup(Inventory item);
|
virtual native bool HandlePickup(Inventory item);
|
||||||
virtual native Inventory CreateCopy(Actor other);
|
virtual native Inventory CreateCopy(Actor other);
|
||||||
|
virtual native bool SpecialDropAction (Actor dropper);
|
||||||
|
|
||||||
native void GoAwayAndDie();
|
native void GoAwayAndDie();
|
||||||
|
|
||||||
|
|
|
@ -133,6 +133,9 @@ class PSprite : Object native
|
||||||
native bool bPowDouble;
|
native bool bPowDouble;
|
||||||
native bool bCVarFast;
|
native bool bCVarFast;
|
||||||
native bool bFlip;
|
native bool bFlip;
|
||||||
|
|
||||||
|
native void SetState(State newstate, bool pending = false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PlayerInfo native // this is what internally is known as player_t
|
struct PlayerInfo native // this is what internally is known as player_t
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
|
|
||||||
// The Almighty Sigil! ------------------------------------------------------
|
// The Almighty Sigil! ------------------------------------------------------
|
||||||
|
|
||||||
class Sigil : Weapon native
|
class Sigil : Weapon
|
||||||
{
|
{
|
||||||
|
// NUmPieces gets stored in 'health', so that it can be quickly accessed by ACS's GetSigilPieces function.
|
||||||
|
int downpieces;
|
||||||
|
|
||||||
Default
|
Default
|
||||||
{
|
{
|
||||||
Weapon.Kickback 100;
|
Weapon.Kickback 100;
|
||||||
|
@ -16,18 +19,7 @@ class Sigil : Weapon native
|
||||||
Inventory.PickupMessage "$TXT_SIGIL";
|
Inventory.PickupMessage "$TXT_SIGIL";
|
||||||
}
|
}
|
||||||
|
|
||||||
action native void A_SelectPiece ();
|
States(Actor)
|
||||||
action native void A_SelectSigilView ();
|
|
||||||
action native void A_SelectSigilDown ();
|
|
||||||
action native void A_SelectSigilAttack ();
|
|
||||||
action native void A_SigilCharge ();
|
|
||||||
action native void A_FireSigil1 ();
|
|
||||||
action native void A_FireSigil2 ();
|
|
||||||
action native void A_FireSigil3 ();
|
|
||||||
action native void A_FireSigil4 ();
|
|
||||||
action native void A_FireSigil5 ();
|
|
||||||
|
|
||||||
States
|
|
||||||
{
|
{
|
||||||
Spawn:
|
Spawn:
|
||||||
SIGL A 1;
|
SIGL A 1;
|
||||||
|
@ -41,6 +33,9 @@ class Sigil : Weapon native
|
||||||
Stop;
|
Stop;
|
||||||
SIGL E -1;
|
SIGL E -1;
|
||||||
Stop;
|
Stop;
|
||||||
|
}
|
||||||
|
States(Weapon)
|
||||||
|
{
|
||||||
Ready:
|
Ready:
|
||||||
SIGH A 0 Bright A_SelectSigilView;
|
SIGH A 0 Bright A_SelectSigilView;
|
||||||
Wait;
|
Wait;
|
||||||
|
@ -120,6 +115,353 @@ class Sigil : Weapon native
|
||||||
SIGF C 0 Bright A_Light0;
|
SIGF C 0 Bright A_Light0;
|
||||||
Stop;
|
Stop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// ASigil :: HandlePickup
|
||||||
|
//
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
override bool HandlePickup (Inventory item)
|
||||||
|
{
|
||||||
|
if (item is "Sigil")
|
||||||
|
{
|
||||||
|
int otherPieces = item.health;
|
||||||
|
if (otherPieces > health)
|
||||||
|
{
|
||||||
|
item.bPickupGood = true;
|
||||||
|
Icon = item.Icon;
|
||||||
|
// If the player is holding the Sigil right now, drop it and bring
|
||||||
|
// it back with the new piece(s) in view.
|
||||||
|
if (Owner.player != null && Owner.player.ReadyWeapon == self)
|
||||||
|
{
|
||||||
|
DownPieces = health;
|
||||||
|
Owner.player.PendingWeapon = self;
|
||||||
|
}
|
||||||
|
health = otherPieces;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// ASigil :: CreateCopy
|
||||||
|
//
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
override Inventory CreateCopy (Actor other)
|
||||||
|
{
|
||||||
|
Sigil copy = Sigil(Spawn("Sigil"));
|
||||||
|
copy.Amount = Amount;
|
||||||
|
copy.MaxAmount = MaxAmount;
|
||||||
|
copy.health = health;
|
||||||
|
copy.Icon = Icon;
|
||||||
|
GoAwayAndDie ();
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// A_SelectPiece
|
||||||
|
//
|
||||||
|
// Decide which sprite frame self Sigil should use as an item, based on how
|
||||||
|
// many pieces it represents.
|
||||||
|
//
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
void A_SelectPiece ()
|
||||||
|
{
|
||||||
|
int pieces = min (health, 5);
|
||||||
|
|
||||||
|
if (pieces > 1)
|
||||||
|
{
|
||||||
|
SetState (FindState("Spawn") + pieces);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// A_SelectSigilView
|
||||||
|
//
|
||||||
|
// Decide which first-person frame self Sigil should show, based on how many
|
||||||
|
// pieces it represents. Strife did self by selecting a flash that looked like
|
||||||
|
// the Sigil whenever you switched to it and at the end of an attack. I have
|
||||||
|
// chosen to make the weapon sprite choose the correct frame and let the flash
|
||||||
|
// be a regular flash. It means I need to use more states, but I think it's
|
||||||
|
// worth it.
|
||||||
|
//
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
action void A_SelectSigilView ()
|
||||||
|
{
|
||||||
|
if (player == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PSprite pspr = player.GetPSprite(PSP_WEAPON);
|
||||||
|
pspr.SetState(pspr.CurState + invoker.health);
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// A_SelectSigilDown
|
||||||
|
//
|
||||||
|
// Same as A_SelectSigilView, except it uses DownPieces. self is so that when
|
||||||
|
// you pick up a Sigil, the old one will drop and *then* change to the new
|
||||||
|
// one.
|
||||||
|
//
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
action void A_SelectSigilDown ()
|
||||||
|
{
|
||||||
|
if (player == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PSprite pspr = player.GetPSprite(PSP_WEAPON);
|
||||||
|
int pieces = invoker.downpieces;
|
||||||
|
if (pieces < 1 || pieces > 5) pieces = invoker.health;
|
||||||
|
pspr.SetState(pspr.CurState + pieces);
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// A_SelectSigilAttack
|
||||||
|
//
|
||||||
|
// Same as A_SelectSigilView, but used just before attacking.
|
||||||
|
//
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
action void A_SelectSigilAttack ()
|
||||||
|
{
|
||||||
|
if (player == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PSprite pspr = player.GetPSprite(PSP_WEAPON);
|
||||||
|
pspr.SetState(pspr.CurState + (4 * invoker.health - 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// A_SigilCharge
|
||||||
|
//
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
action void A_SigilCharge ()
|
||||||
|
{
|
||||||
|
A_PlaySound ("weapons/sigilcharge", CHAN_WEAPON);
|
||||||
|
if (player != null)
|
||||||
|
{
|
||||||
|
player.extralight = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// A_FireSigil1
|
||||||
|
//
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
action void A_FireSigil1 ()
|
||||||
|
{
|
||||||
|
Actor spot;
|
||||||
|
FTranslatedLineTarget t;
|
||||||
|
|
||||||
|
if (player == null || player.ReadyWeapon == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
DamageMobj (self, null, 1*4, 'Sigil', DMG_NO_ARMOR);
|
||||||
|
A_PlaySound ("weapons/sigilcharge", CHAN_WEAPON);
|
||||||
|
|
||||||
|
BulletSlope (t, ALF_PORTALRESTRICT);
|
||||||
|
if (t.linetarget != null)
|
||||||
|
{
|
||||||
|
spot = Spawn("SpectralLightningSpot", (t.linetarget.pos.xy, t.linetarget.floorz), ALLOW_REPLACE);
|
||||||
|
if (spot != null)
|
||||||
|
{
|
||||||
|
spot.tracer = t.linetarget;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
spot = Spawn("SpectralLightningSpot", Pos, ALLOW_REPLACE);
|
||||||
|
if (spot != null)
|
||||||
|
{
|
||||||
|
spot.VelFromAngle(28., angle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (spot != null)
|
||||||
|
{
|
||||||
|
spot.SetFriendPlayer(player);
|
||||||
|
spot.target = self;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// A_FireSigil2
|
||||||
|
//
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
action void A_FireSigil2 ()
|
||||||
|
{
|
||||||
|
if (player == null || player.ReadyWeapon == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
DamageMobj (self, null, 2*4, 'Sigil', DMG_NO_ARMOR);
|
||||||
|
A_PlaySound ("weapons/sigilcharge", CHAN_WEAPON);
|
||||||
|
SpawnPlayerMissile ("SpectralLightningH1");
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// A_FireSigil3
|
||||||
|
//
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
action void A_FireSigil3 ()
|
||||||
|
{
|
||||||
|
if (player == null || player.ReadyWeapon == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
DamageMobj (self, null, 3*4, 'Sigil', DMG_NO_ARMOR);
|
||||||
|
A_PlaySound ("weapons/sigilcharge", CHAN_WEAPON);
|
||||||
|
|
||||||
|
angle -= 90.;
|
||||||
|
for (int i = 0; i < 20; ++i)
|
||||||
|
{
|
||||||
|
angle += 9.;
|
||||||
|
Actor spot = SpawnSubMissile ("SpectralLightningBall1", self);
|
||||||
|
if (spot != null)
|
||||||
|
{
|
||||||
|
spot.SetZ(pos.z + 32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
angle -= 90.;
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// A_FireSigil4
|
||||||
|
//
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
action void A_FireSigil4 ()
|
||||||
|
{
|
||||||
|
FTranslatedLineTarget t;
|
||||||
|
|
||||||
|
if (player == null || player.ReadyWeapon == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
DamageMobj (self, null, 4*4, 'Sigil', DMG_NO_ARMOR);
|
||||||
|
A_PlaySound ("weapons/sigilcharge", CHAN_WEAPON);
|
||||||
|
|
||||||
|
BulletSlope (t, ALF_PORTALRESTRICT);
|
||||||
|
if (t.linetarget != null)
|
||||||
|
{
|
||||||
|
Actor spot = SpawnPlayerMissile ("SpectralLightningBigV1", angle, pLineTarget: t, aimFlags: ALF_PORTALRESTRICT);
|
||||||
|
if (spot != null)
|
||||||
|
{
|
||||||
|
spot.tracer = t.linetarget;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Actor spot = SpawnPlayerMissile ("SpectralLightningBigV1");
|
||||||
|
if (spot != null)
|
||||||
|
{
|
||||||
|
spot.VelFromAngle(spot.Speed, angle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// A_FireSigil5
|
||||||
|
//
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
action void A_FireSigil5 ()
|
||||||
|
{
|
||||||
|
if (player == null || player.ReadyWeapon == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
DamageMobj (self, null, 5*4, 'Sigil', DMG_NO_ARMOR);
|
||||||
|
A_PlaySound ("weapons/sigilcharge", CHAN_WEAPON);
|
||||||
|
|
||||||
|
SpawnPlayerMissile ("SpectralLightningBigBall1");
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// ASigil :: SpecialDropAction
|
||||||
|
//
|
||||||
|
// Monsters don't drop Sigil pieces. The Sigil pieces grab hold of the person
|
||||||
|
// who killed the dropper and automatically enter their inventory. That's the
|
||||||
|
// way it works if you believe Macil, anyway...
|
||||||
|
//
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
override bool SpecialDropAction (Actor dropper)
|
||||||
|
{
|
||||||
|
// Give a Sigil piece to every player in the game
|
||||||
|
for (int i = 0; i < MAXPLAYERS; ++i)
|
||||||
|
{
|
||||||
|
if (playeringame[i] && players[i].mo != null)
|
||||||
|
{
|
||||||
|
GiveSigilPiece (players[i].mo);
|
||||||
|
Destroy ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
//
|
||||||
|
// ASigil :: GiveSigilPiece
|
||||||
|
//
|
||||||
|
// Gives the actor another Sigil piece, up to 5. Returns the number of Sigil
|
||||||
|
// pieces the actor previously held.
|
||||||
|
//
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
static int GiveSigilPiece (Actor receiver)
|
||||||
|
{
|
||||||
|
Sigil sigl = Sigil(receiver.FindInventory("Sigil"));
|
||||||
|
if (sigl == null)
|
||||||
|
{
|
||||||
|
sigl = Sigil(Spawn("Sigil1"));
|
||||||
|
if (!sigl.CallTryPickup (receiver))
|
||||||
|
{
|
||||||
|
sigl.Destroy ();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if (sigl.health < 5)
|
||||||
|
{
|
||||||
|
++sigl.health;
|
||||||
|
static const class<Sigil> sigils[] =
|
||||||
|
{
|
||||||
|
"Sigil1", "Sigil2", "Sigil3", "Sigil4", "Sigil5"
|
||||||
|
};
|
||||||
|
sigl.Icon = GetDefaultByType(sigils[clamp(sigl.health, 1, 5)]).Icon;
|
||||||
|
// If the player has the Sigil out, drop it and bring it back up.
|
||||||
|
if (sigl.Owner.player != null && sigl.Owner.player.ReadyWeapon == sigl)
|
||||||
|
{
|
||||||
|
sigl.Owner.player.PendingWeapon = sigl;
|
||||||
|
sigl.DownPieces = sigl.health - 1;
|
||||||
|
}
|
||||||
|
return sigl.health - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sigil 1 ------------------------------------------------------------------
|
// Sigil 1 ------------------------------------------------------------------
|
||||||
|
|
Loading…
Reference in a new issue