diff --git a/src/g_shared/a_action.cpp b/src/g_shared/a_action.cpp index ca92e731f..ddfd23268 100644 --- a/src/g_shared/a_action.cpp +++ b/src/g_shared/a_action.cpp @@ -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(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(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) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 09f946fc7..df064c525 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -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 diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 6e529220f..edc11192d 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -491,6 +491,7 @@ class Actor : Thinker native native Inventory GiveInventoryType(class itemtype); native Inventory DropInventory (Inventory item); native bool UseInventory(Inventory item); + native void ObtainInventory(Actor other); native bool GiveAmmo (Class 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 skulltype = "BloodySkull"); native void A_CheckPlayerDone(); diff --git a/wadsrc/static/zscript/shared/ice.txt b/wadsrc/static/zscript/shared/ice.txt index 9b72e2455..d26131eb0 100644 --- a/wadsrc/static/zscript/shared/ice.txt +++ b/wadsrc/static/zscript/shared/ice.txt @@ -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(); + } + + +} \ No newline at end of file diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index 953b9d971..f9a576006 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -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 cls;