mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-24 13:01:47 +00:00
- scriptified A_FreezeDeath(Chunks).
This commit is contained in:
parent
6dc1bb8475
commit
e16713492f
5 changed files with 132 additions and 143 deletions
|
@ -12,10 +12,6 @@
|
|||
#include "serializer.h"
|
||||
#include "r_data/r_translate.h"
|
||||
|
||||
static FRandom pr_freezedeath ("FreezeDeath");
|
||||
static FRandom pr_freeze ("FreezeDeathChunks");
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// PROC A_NoBlocking
|
||||
|
@ -74,137 +70,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_NoBlocking)
|
|||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_FreezeDeath
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeath)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
int t = pr_freezedeath();
|
||||
self->tics = 75+t+pr_freezedeath();
|
||||
self->flags |= MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD|MF_ICECORPSE;
|
||||
self->flags2 |= MF2_PUSHABLE|MF2_TELESTOMP|MF2_PASSMOBJ|MF2_SLIDE;
|
||||
self->flags3 |= MF3_CRASHED;
|
||||
self->Height = self->GetDefault()->Height;
|
||||
// Remove fuzz effects from frozen actors.
|
||||
if (self->RenderStyle.BlendOp >= STYLEOP_Fuzz && self->RenderStyle.BlendOp <= STYLEOP_FuzzOrRevSub)
|
||||
{
|
||||
self->RenderStyle = STYLE_Normal;
|
||||
}
|
||||
|
||||
S_Sound (self, CHAN_BODY, "misc/freeze", 1, ATTN_NORM);
|
||||
|
||||
// [RH] Andy Baker's stealth monsters
|
||||
if (self->flags & MF_STEALTH)
|
||||
{
|
||||
self->Alpha = 1;
|
||||
self->visdir = 0;
|
||||
}
|
||||
|
||||
if (self->player)
|
||||
{
|
||||
self->player->damagecount = 0;
|
||||
self->player->poisoncount = 0;
|
||||
self->player->bonuscount = 0;
|
||||
}
|
||||
else if (self->flags3 & MF3_ISMONSTER && self->special)
|
||||
{ // Initiate monster death actions
|
||||
P_ExecuteSpecial(self->special, NULL, self, false, self->args[0],
|
||||
self->args[1], self->args[2], self->args[3], self->args[4]);
|
||||
self->special = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_FreezeDeathChunks
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_FreezeDeathChunks)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
int i;
|
||||
int numChunks;
|
||||
AActor *mo;
|
||||
|
||||
if (!self->Vel.isZero() && !(self->flags6 & MF6_SHATTERING))
|
||||
{
|
||||
self->tics = 3*TICRATE;
|
||||
return 0;
|
||||
}
|
||||
self->Vel.Zero();
|
||||
S_Sound (self, CHAN_BODY, "misc/icebreak", 1, ATTN_NORM);
|
||||
|
||||
// [RH] In Hexen, this creates a random number of shards (range [24,56])
|
||||
// with no relation to the size of the self shattering. I think it should
|
||||
// base the number of shards on the size of the dead thing, so bigger
|
||||
// things break up into more shards than smaller things.
|
||||
// An actor with radius 20 and height 64 creates ~40 chunks.
|
||||
numChunks = MAX<int>(4, int(self->radius * self->Height)/32);
|
||||
i = (pr_freeze.Random2()) % (numChunks/4);
|
||||
for (i = MAX (24, numChunks + i); i >= 0; i--)
|
||||
{
|
||||
double xo = (pr_freeze() - 128)*self->radius / 128;
|
||||
double yo = (pr_freeze() - 128)*self->radius / 128;
|
||||
double zo = (pr_freeze()*self->Height / 255);
|
||||
|
||||
mo = Spawn("IceChunk", self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE);
|
||||
if (mo)
|
||||
{
|
||||
mo->SetState (mo->SpawnState + (pr_freeze()%3));
|
||||
mo->Vel.X = pr_freeze.Random2() / 128.;
|
||||
mo->Vel.Y = pr_freeze.Random2() / 128.;
|
||||
mo->Vel.Z = (mo->Z() - self->Z()) / self->Height * 4;
|
||||
mo->RenderStyle = self->RenderStyle;
|
||||
mo->Alpha = self->Alpha;
|
||||
}
|
||||
}
|
||||
if (self->player)
|
||||
{ // attach the player's view to a chunk of ice
|
||||
AActor *head = Spawn("IceChunkHead", self->PosPlusZ(self->player->mo->ViewHeight), ALLOW_REPLACE);
|
||||
if (head != NULL)
|
||||
{
|
||||
head->Vel.X = pr_freeze.Random2() / 128.;
|
||||
head->Vel.Y = pr_freeze.Random2() / 128.;
|
||||
head->Vel.Z = (mo->Z() - self->Z()) / self->Height * 4;
|
||||
|
||||
head->health = self->health;
|
||||
head->Angles.Yaw = self->Angles.Yaw;
|
||||
if (head->IsKindOf(RUNTIME_CLASS(APlayerPawn)))
|
||||
{
|
||||
head->player = self->player;
|
||||
head->player->mo = static_cast<APlayerPawn*>(head);
|
||||
self->player = NULL;
|
||||
head->ObtainInventory (self);
|
||||
}
|
||||
head->Angles.Pitch = 0.;
|
||||
head->RenderStyle = self->RenderStyle;
|
||||
head->Alpha = self->Alpha;
|
||||
if (head->player->camera == self)
|
||||
{
|
||||
head->player->camera = head;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// [RH] Do some stuff to make this more useful outside Hexen
|
||||
if (self->flags4 & MF4_BOSSDEATH)
|
||||
{
|
||||
A_BossDeath(self);
|
||||
}
|
||||
A_Unblock(self, true);
|
||||
|
||||
self->SetState(self->FindState(NAME_Null));
|
||||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// CorpseQueue Routines (used by Hexen)
|
||||
|
|
|
@ -1311,6 +1311,13 @@ void AActor::ObtainInventory (AActor *other)
|
|||
}
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, ObtainInventory)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
PARAM_OBJECT(other, AActor);
|
||||
self->ObtainInventory(other);
|
||||
return 0;
|
||||
}
|
||||
//============================================================================
|
||||
//
|
||||
// AActor :: CheckLocalView
|
||||
|
|
|
@ -491,6 +491,7 @@ class Actor : Thinker native
|
|||
native Inventory GiveInventoryType(class<Inventory> itemtype);
|
||||
native Inventory DropInventory (Inventory item);
|
||||
native bool UseInventory(Inventory item);
|
||||
native void ObtainInventory(Actor other);
|
||||
native bool GiveAmmo (Class<Ammo> type, int amount);
|
||||
native float AccuracyFactor();
|
||||
|
||||
|
@ -725,13 +726,6 @@ class Actor : Thinker native
|
|||
native void A_ActiveSound();
|
||||
|
||||
native void A_FastChase();
|
||||
native void A_FreezeDeath();
|
||||
native void A_FreezeDeathChunks();
|
||||
void A_GenericFreezeDeath()
|
||||
{
|
||||
A_SetTranslation('Ice');
|
||||
A_FreezeDeath();
|
||||
}
|
||||
native void A_PlayerScream();
|
||||
native void A_SkullPop(class<PlayerChunk> skulltype = "BloodySkull");
|
||||
native void A_CheckPlayerDone();
|
||||
|
|
|
@ -71,3 +71,126 @@ class IceChunkHead : PlayerChunk
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
extend class Actor
|
||||
{
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_FreezeDeath
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
void A_FreezeDeath()
|
||||
{
|
||||
|
||||
int t = random[freezedeath]();
|
||||
tics = 75+t+random[freezedeath]();
|
||||
bSolid = bShootable = bNoBlood = bIceCorpse = bPushable = bTelestomp = bCanPass = bSlidesOnWalls = bCrashed = true;
|
||||
Height = Default.Height;
|
||||
A_SetRenderStyle(1, STYLE_Normal);
|
||||
|
||||
A_PlaySound ("misc/freeze", CHAN_BODY);
|
||||
|
||||
// [RH] Andy Baker's stealth monsters
|
||||
if (bStealth)
|
||||
{
|
||||
Alpha = 1;
|
||||
visdir = 0;
|
||||
}
|
||||
|
||||
if (player)
|
||||
{
|
||||
player.damagecount = 0;
|
||||
player.poisoncount = 0;
|
||||
player.bonuscount = 0;
|
||||
}
|
||||
else if (bIsMonster && special)
|
||||
{ // Initiate monster death actions
|
||||
A_CallSpecial(special, args[0], args[1], args[2], args[3], args[4]);
|
||||
special = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_FreezeDeathChunks
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
void A_FreezeDeathChunks()
|
||||
{
|
||||
if (Vel != (0,0,0) && !bShattering)
|
||||
{
|
||||
tics = 3*TICRATE;
|
||||
return;
|
||||
}
|
||||
Vel = (0,0,0);
|
||||
A_PlaySound ("misc/icebreak", CHAN_BODY);
|
||||
|
||||
// [RH] In Hexen, this creates a random number of shards (range [24,56])
|
||||
// with no relation to the size of the self shattering. I think it should
|
||||
// base the number of shards on the size of the dead thing, so bigger
|
||||
// things break up into more shards than smaller things.
|
||||
// An actor with radius 20 and height 64 creates ~40 chunks.
|
||||
int numChunks = max(4, int(radius * Height)/32);
|
||||
int i = Random[FreezeDeathChunks]() % (numChunks/4);
|
||||
for (i = max(24, numChunks + i); i >= 0; i--)
|
||||
{
|
||||
double xo = (random[FreezeDeathChunks]() - 128)*radius / 128;
|
||||
double yo = (random[FreezeDeathChunks]() - 128)*radius / 128;
|
||||
double zo = (random[FreezeDeathChunks]() * Height / 255);
|
||||
|
||||
Actor mo = Spawn("IceChunk", Vec3Offset(xo, yo, zo), ALLOW_REPLACE);
|
||||
if (mo)
|
||||
{
|
||||
mo.SetState (mo.SpawnState + (random[FreezeDeathChunks]()%3));
|
||||
mo.Vel.X = random2[FreezeDeathChunks]() / 128.;
|
||||
mo.Vel.Y = random2[FreezeDeathChunks]() / 128.;
|
||||
mo.Vel.Z = (mo.pos.Z - pos.Z) / Height * 4;
|
||||
}
|
||||
}
|
||||
if (player)
|
||||
{ // attach the player's view to a chunk of ice
|
||||
Actor head = Spawn("IceChunkHead", pos + (0, 0, player.mo.ViewHeight), ALLOW_REPLACE);
|
||||
if (head != null)
|
||||
{
|
||||
head.Vel.X = random2[FreezeDeathChunks]() / 128.;
|
||||
head.Vel.Y = random2[FreezeDeathChunks]() / 128.;
|
||||
head.Vel.Z = (head.pos.Z - pos.Z) / Height * 4;
|
||||
|
||||
head.health = health;
|
||||
head.Angle = Angle;
|
||||
if (head is "PlayerPawn")
|
||||
{
|
||||
head.player = player;
|
||||
head.player.mo = PlayerPawn(head);
|
||||
player = null;
|
||||
head.ObtainInventory (self);
|
||||
}
|
||||
head.Pitch = 0.;
|
||||
if (head.player.camera == self)
|
||||
{
|
||||
head.player.camera = head;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// [RH] Do some stuff to make this more useful outside Hexen
|
||||
if (bBossDeath)
|
||||
{
|
||||
A_BossDeath();
|
||||
}
|
||||
A_NoBlocking();
|
||||
|
||||
SetStateLabel('null');
|
||||
}
|
||||
|
||||
void A_GenericFreezeDeath()
|
||||
{
|
||||
A_SetTranslation('Ice');
|
||||
A_FreezeDeath();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -162,7 +162,7 @@ enum EPlayerState
|
|||
|
||||
struct PlayerInfo native // this is what internally is known as player_t
|
||||
{
|
||||
native readonly PlayerPawn mo;
|
||||
native PlayerPawn mo;
|
||||
native uint8 playerstate;
|
||||
native uint original_oldbuttons;
|
||||
native readonly Class<PlayerPawn> cls;
|
||||
|
|
Loading…
Reference in a new issue