- scriptified A_FreezeDeath(Chunks).

This commit is contained in:
Christoph Oelckers 2017-01-14 18:26:59 +01:00
parent 6dc1bb8475
commit e16713492f
5 changed files with 132 additions and 143 deletions

View file

@ -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)

View file

@ -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

View file

@ -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();

View file

@ -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();
}
}

View file

@ -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;