diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 19179a0c4d..c1a14d7037 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -867,7 +867,6 @@ set( NOT_COMPILED_SOURCE_FILES sc_man_scanner.h sc_man_scanner.re g_doom/a_painelemental.cpp - g_heretic/a_chicken.cpp g_heretic/a_dsparil.cpp g_heretic/a_hereticartifacts.cpp g_heretic/a_hereticweaps.cpp @@ -892,7 +891,6 @@ set( NOT_COMPILED_SOURCE_FILES g_hexen/a_magecone.cpp g_hexen/a_magelightning.cpp g_hexen/a_magestaff.cpp - g_hexen/a_pig.cpp g_hexen/a_serpent.cpp g_hexen/a_spike.cpp g_hexen/a_summon.cpp diff --git a/src/d_player.h b/src/d_player.h index 20a78c9321..d3f6841374 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -100,6 +100,7 @@ FString GetPrintableDisplayName(PClassPlayerPawn *cls); class APlayerPawn : public AActor { DECLARE_CLASS_WITH_META(APlayerPawn, AActor, PClassPlayerPawn) + HAS_FIELDS HAS_OBJECT_POINTERS public: @@ -116,7 +117,7 @@ public: virtual void PlayRunning (); virtual void ThrowPoisonBag (); virtual void TweakSpeeds (double &forwardmove, double &sidemove); - virtual void MorphPlayerThink (); + void MorphPlayerThink (); virtual void ActivateMorphWeapon (); AWeapon *PickNewWeapon (PClassAmmo *ammotype); AWeapon *BestWeapon (PClassAmmo *ammotype); diff --git a/src/g_heretic/a_chicken.cpp b/src/g_heretic/a_chicken.cpp deleted file mode 100644 index 8a109d46dd..0000000000 --- a/src/g_heretic/a_chicken.cpp +++ /dev/null @@ -1,233 +0,0 @@ -/* -#include "actor.h" -#include "gi.h" -#include "m_random.h" -#include "s_sound.h" -#include "d_player.h" -#include "a_action.h" -#include "a_pickups.h" -#include "p_local.h" -#include "a_sharedglobal.h" -#include "p_enemy.h" -#include "d_event.h" -#include "gstrings.h" -#include "vm.h" -*/ - -void P_UpdateBeak (AActor *actor); - -static FRandom pr_chickenplayerthink ("ChickenPlayerThink"); -static FRandom pr_chicattack ("ChicAttack"); -static FRandom pr_feathers ("Feathers"); -static FRandom pr_beakatkpl1 ("BeakAtkPL1"); -static FRandom pr_beakatkpl2 ("BeakAtkPL2"); - -class AChickenPlayer : public APlayerPawn -{ - DECLARE_CLASS (AChickenPlayer, APlayerPawn) -public: - void MorphPlayerThink (); -}; - -IMPLEMENT_CLASS(AChickenPlayer, false, false, false, false) - -void AChickenPlayer::MorphPlayerThink () -{ - if (health > 0) - { // Handle beak movement - P_UpdateBeak (this); - } - if (player->morphTics & 15) - { - return; - } - if (Vel.X == 0 && Vel.Y == 0 && pr_chickenplayerthink () < 160) - { // Twitch view angle - Angles.Yaw += pr_chickenplayerthink.Random2() * (360. / 256. / 32.); - } - if ((Z() <= floorz) && (pr_chickenplayerthink() < 32)) - { // Jump and noise - Vel.Z += JumpZ; - - FState * painstate = FindState(NAME_Pain); - if (painstate != NULL) SetState (painstate); - } - if (pr_chickenplayerthink () < 48) - { // Just noise - S_Sound (this, CHAN_VOICE, "chicken/active", 1, ATTN_NORM); - } -} - -//---------------------------------------------------------------------------- -// -// PROC A_ChicAttack -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_ChicAttack) -{ - PARAM_SELF_PROLOGUE(AActor); - - if (!self->target) - { - return 0; - } - if (self->CheckMeleeRange()) - { - int damage = 1 + (pr_chicattack() & 1); - int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); - P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); - } - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_Feathers -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_Feathers) -{ - PARAM_SELF_PROLOGUE(AActor); - - int i; - int count; - AActor *mo; - - if (self->health > 0) - { // Pain - count = pr_feathers() < 32 ? 2 : 1; - } - else - { // Death - count = 5 + (pr_feathers()&3); - } - for (i = 0; i < count; i++) - { - mo = Spawn("Feather", self->PosPlusZ(20.), NO_REPLACE); - mo->target = self; - mo->Vel.X = pr_feathers.Random2() / 256.; - mo->Vel.Y = pr_feathers.Random2() / 256.; - mo->Vel.Z = 1. + pr_feathers() / 128.; - mo->SetState (mo->SpawnState + (pr_feathers()&7)); - } - return 0; -} - -//--------------------------------------------------------------------------- -// -// PROC P_UpdateBeak -// -//--------------------------------------------------------------------------- - -void P_UpdateBeak (AActor *self) -{ - DPSprite *pspr; - if (self->player != nullptr && (pspr = self->player->FindPSprite(PSP_WEAPON)) != nullptr) - { - pspr->y = WEAPONTOP + self->player->chickenPeck / 2; - } -} - -//--------------------------------------------------------------------------- -// -// PROC A_BeakRaise -// -//--------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_BeakRaise) -{ - PARAM_ACTION_PROLOGUE(AActor); - - player_t *player; - - if (nullptr == (player = self->player)) - { - return 0; - } - player->GetPSprite(PSP_WEAPON)->y = WEAPONTOP; - P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->GetReadyState()); - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC P_PlayPeck -// -//---------------------------------------------------------------------------- - -void P_PlayPeck (AActor *chicken) -{ - S_Sound (chicken, CHAN_VOICE, "chicken/peck", 1, ATTN_NORM); -} - -//---------------------------------------------------------------------------- -// -// PROC A_BeakAttackPL1 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL1) -{ - PARAM_ACTION_PROLOGUE(AActor); - - DAngle angle; - int damage; - DAngle slope; - player_t *player; - FTranslatedLineTarget t; - - if (NULL == (player = self->player)) - { - return 0; - } - - damage = 1 + (pr_beakatkpl1()&3); - angle = player->mo->Angles.Yaw; - slope = P_AimLineAttack (player->mo, angle, MELEERANGE); - P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "BeakPuff", true, &t); - if (t.linetarget) - { - player->mo->Angles.Yaw = t.angleFromSource; - } - P_PlayPeck (player->mo); - player->chickenPeck = 12; - player->GetPSprite(PSP_WEAPON)->Tics -= pr_beakatkpl1() & 7; - return 0; -} - -//---------------------------------------------------------------------------- -// -// PROC A_BeakAttackPL2 -// -//---------------------------------------------------------------------------- - -DEFINE_ACTION_FUNCTION(AActor, A_BeakAttackPL2) -{ - PARAM_ACTION_PROLOGUE(AActor); - - DAngle angle; - int damage; - DAngle slope; - player_t *player; - FTranslatedLineTarget t; - - if (NULL == (player = self->player)) - { - return 0; - } - - damage = pr_beakatkpl2.HitDice (4); - angle = player->mo->Angles.Yaw; - slope = P_AimLineAttack (player->mo, angle, MELEERANGE); - P_LineAttack (player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "BeakPuff", true, &t); - if (t.linetarget) - { - player->mo->Angles.Yaw = t.angleFromSource; - } - P_PlayPeck (player->mo); - player->chickenPeck = 12; - player->GetPSprite(PSP_WEAPON)->Tics -= pr_beakatkpl2()&3; - return 0; -} diff --git a/src/g_heretic/a_hereticmisc.cpp b/src/g_heretic/a_hereticmisc.cpp index 64de3ef843..5aa048977a 100644 --- a/src/g_heretic/a_hereticmisc.cpp +++ b/src/g_heretic/a_hereticmisc.cpp @@ -19,7 +19,6 @@ #include "serializer.h" // Include all the other Heretic stuff here to reduce compile time -#include "a_chicken.cpp" #include "a_dsparil.cpp" #include "a_hereticartifacts.cpp" #include "a_hereticweaps.cpp" diff --git a/src/g_hexen/a_fighterplayer.cpp b/src/g_hexen/a_fighterplayer.cpp index 7e1502a1cb..afdbe8a90f 100644 --- a/src/g_hexen/a_fighterplayer.cpp +++ b/src/g_hexen/a_fighterplayer.cpp @@ -49,6 +49,13 @@ void AdjustPlayerAngle (AActor *pmo, FTranslatedLineTarget *t) } } +DEFINE_ACTION_FUNCTION(AActor, AdjustPlayerAngle) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_POINTER(t, FTranslatedLineTarget); + AdjustPlayerAngle(self, t); + return 0; +} //============================================================================ // // TryPunch diff --git a/src/g_hexen/a_hexenmisc.cpp b/src/g_hexen/a_hexenmisc.cpp index c87c9e46d3..f98305cbaf 100644 --- a/src/g_hexen/a_hexenmisc.cpp +++ b/src/g_hexen/a_hexenmisc.cpp @@ -45,7 +45,6 @@ #include "a_magecone.cpp" #include "a_magelightning.cpp" #include "a_magestaff.cpp" -#include "a_pig.cpp" #include "a_serpent.cpp" #include "a_spike.cpp" #include "a_summon.cpp" diff --git a/src/g_hexen/a_pig.cpp b/src/g_hexen/a_pig.cpp deleted file mode 100644 index 41054da001..0000000000 --- a/src/g_hexen/a_pig.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* -#include "actor.h" -#include "gi.h" -#include "m_random.h" -#include "s_sound.h" -#include "d_player.h" -#include "a_action.h" -#include "a_pickups.h" -#include "p_local.h" -#include "a_sharedglobal.h" -#include "p_enemy.h" -#include "d_event.h" -#include "gstrings.h" -#include "vm.h" -*/ - -static FRandom pr_snoutattack ("SnoutAttack"); -static FRandom pr_pigattack ("PigAttack"); -static FRandom pr_pigplayerthink ("PigPlayerThink"); - -// Pig player --------------------------------------------------------------- - -class APigPlayer : public APlayerPawn -{ - DECLARE_CLASS (APigPlayer, APlayerPawn) -public: - void MorphPlayerThink (); -}; - -IMPLEMENT_CLASS(APigPlayer, false, false, false, false) - -void APigPlayer::MorphPlayerThink () -{ - if (player->morphTics & 15) - { - return; - } - if(Vel.X == 0 && Vel.Y == 0 && pr_pigplayerthink() < 64) - { // Snout sniff - if (player->ReadyWeapon != nullptr) - { - P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->FindState("Grunt")); - } - S_Sound (this, CHAN_VOICE, "PigActive1", 1, ATTN_NORM); // snort - return; - } - if (pr_pigplayerthink() < 48) - { - S_Sound (this, CHAN_VOICE, "PigActive", 1, ATTN_NORM); - } -} - -//============================================================================ -// -// A_SnoutAttack -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_SnoutAttack) -{ - PARAM_ACTION_PROLOGUE(AActor); - - DAngle angle; - int damage; - DAngle slope; - player_t *player; - AActor *puff; - FTranslatedLineTarget t; - - if (NULL == (player = self->player)) - { - return 0; - } - - damage = 3+(pr_snoutattack()&3); - angle = player->mo->Angles.Yaw; - slope = P_AimLineAttack(player->mo, angle, MELEERANGE); - puff = P_LineAttack(player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "SnoutPuff", true, &t); - S_Sound(player->mo, CHAN_VOICE, "PigActive", 1, ATTN_NORM); - if(t.linetarget) - { - AdjustPlayerAngle(player->mo, &t); - if(puff != NULL) - { // Bit something - S_Sound(player->mo, CHAN_VOICE, "PigAttack", 1, ATTN_NORM); - } - } - return 0; -} - -//============================================================================ -// -// A_PigPain -// -//============================================================================ - -DEFINE_ACTION_FUNCTION(AActor, A_PigPain) -{ - PARAM_SELF_PROLOGUE(AActor); - - CALL_ACTION(A_Pain, self); - if (self->Z() <= self->floorz) - { - self->Vel.Z = 3.5; - } - return 0; -} diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 157badd879..b5f5691089 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -109,8 +109,29 @@ IMPLEMENT_POINTERS_END void DPSprite::InitNativeFields() { auto meta = RUNTIME_CLASS(DPSprite); + PType *TypeActor = NewPointer(RUNTIME_CLASS(AActor)); + PType *TypePSP = NewPointer(RUNTIME_CLASS(DPSprite)); + PType *TypePlayer = NewPointer(NewNativeStruct("Player", nullptr)); meta->AddNativeField("State", TypeState, myoffsetof(DPSprite, State), VARF_ReadOnly); + meta->AddNativeField("Caller", TypeActor, myoffsetof(DPSprite, Caller), VARF_ReadOnly); + meta->AddNativeField("Next", TypePSP, myoffsetof(DPSprite, Next), VARF_ReadOnly); + meta->AddNativeField("Owner", TypePlayer, myoffsetof(DPSprite, Owner), VARF_ReadOnly); + meta->AddNativeField("Sprite", TypeSpriteID, myoffsetof(DPSprite, Sprite)); + meta->AddNativeField("Frame", TypeSInt32, myoffsetof(DPSprite, Frame)); + meta->AddNativeField("ID", TypePlayer, myoffsetof(DPSprite, ID), VARF_ReadOnly); + meta->AddNativeField("processPending", TypeBool, myoffsetof(DPSprite, processPending)); + meta->AddNativeField("x", TypeFloat64, myoffsetof(DPSprite, x)); + meta->AddNativeField("y", TypeFloat64, myoffsetof(DPSprite, y)); + meta->AddNativeField("oldx", TypeFloat64, myoffsetof(DPSprite, oldx)); + meta->AddNativeField("oldy", TypeFloat64, myoffsetof(DPSprite, oldy)); + meta->AddNativeField("firstTic", TypeBool, myoffsetof(DPSprite, firstTic)); + meta->AddNativeField("Tics", TypeSInt32, myoffsetof(DPSprite, Tics)); + meta->AddNativeField("bAddWeapon", TypeSInt32, myoffsetof(DPSprite, Flags), 0, PSPF_ADDWEAPON); + meta->AddNativeField("bAddBob", TypeSInt32, myoffsetof(DPSprite, Flags), 0, PSPF_ADDBOB); + meta->AddNativeField("bPowDouble", TypeSInt32, myoffsetof(DPSprite, Flags), 0, PSPF_POWDOUBLE); + meta->AddNativeField("bCVarFast", TypeSInt32, myoffsetof(DPSprite, Flags), 0, PSPF_CVARFAST); + meta->AddNativeField("bFlip", TypeSInt32, myoffsetof(DPSprite, Flags), 0, PSPF_FLIP); } //------------------------------------------------------------------------ @@ -179,6 +200,14 @@ DPSprite *player_t::FindPSprite(int layer) return pspr; } +DEFINE_ACTION_FUNCTION(_Player, FindPSprite) // the underscore is needed to get past the name mangler which removes the first clas name character to match the class representation (needs to be fixed in a later commit) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + PARAM_INT(id); + ACTION_RETURN_OBJECT(self->FindPSprite((PSPLayers)id)); +} + + //------------------------------------------------------------------------ // // diff --git a/src/p_user.cpp b/src/p_user.cpp index 6d34037f1e..84fcbd313c 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -161,6 +161,12 @@ bool ValidatePlayerClass(PClassActor *ti, const char *name) return true; } +void APlayerPawn::InitNativeFields() +{ + auto meta = RUNTIME_CLASS(APlayerPawn); + meta->AddNativeField("JumpZ", TypeFloat64, myoffsetof(APlayerPawn, JumpZ)); +} + void SetupPlayerClasses () { FPlayerClass newclass; @@ -622,7 +628,7 @@ void player_t::SendPitchLimits() const // //=========================================================================== -IMPLEMENT_CLASS(APlayerPawn, false, true, false, true) +IMPLEMENT_CLASS(APlayerPawn, false, true, true, true) IMPLEMENT_POINTERS_START(APlayerPawn) IMPLEMENT_POINTER(InvFirst) @@ -1381,6 +1387,10 @@ void APlayerPawn::GiveDefaultInventory () void APlayerPawn::MorphPlayerThink () { + VINDEX(APlayerPawn, MorphPlayerThink); + VMValue params[1] = { (DObject*)this }; + VMFrameStack stack; + stack.Call(VFUNC, params, 1, nullptr, 0, nullptr); } void APlayerPawn::ActivateMorphWeapon () diff --git a/src/scripting/codegeneration/codegen.cpp b/src/scripting/codegeneration/codegen.cpp index 701b998cab..3f8f09eb78 100644 --- a/src/scripting/codegeneration/codegen.cpp +++ b/src/scripting/codegeneration/codegen.cpp @@ -2543,7 +2543,15 @@ FxExpression *FxAddSub::Resolve(FCompileContext& ctx) return nullptr; } - if (left->IsVector() && right->IsVector()) + if (left->ValueType == TypeState && right->IsInteger() && Operator == '+' && !left->isConstant()) + { + // This is the only special case of pointer addition that will be accepted - because it is used quite often in the existing game code. + ValueType = TypeState; + right = new FxMulDiv('*', right, new FxConstant((int)sizeof(FState), ScriptPosition)); // multiply by size here, so that constants can be better optimized. + right = right->Resolve(ctx); + ABORT(right); + } + else if (left->IsVector() && right->IsVector()) { // a vector2 can be added to or subtracted from a vector 3 but it needs to be the right operand. if (left->ValueType == right->ValueType || (left->ValueType == TypeVector3 && right->ValueType == TypeVector2)) @@ -2616,6 +2624,16 @@ ExpEmit FxAddSub::Emit(VMFunctionBuilder *build) ExpEmit op2 = right->Emit(build); if (Operator == '+') { + if (op1.RegType == REGT_POINTER) + { + assert(!op1.Konst); + assert(op2.RegType == REGT_INT); + op1.Free(build); + op2.Free(build); + ExpEmit opout(build, REGT_POINTER); + build->Emit(op2.Konst? OP_ADDA_RK : OP_ADDA_RR, opout.RegNum, op1.RegNum, op2.RegNum); + return opout; + } // Since addition is commutative, only the second operand may be a constant. if (op1.Konst) { diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 61bdf49c82..db86647c39 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -67,6 +67,7 @@ class Actor : Thinker native virtual native void Activate(Actor activator); virtual native void Deactivate(Actor activator); + native void AdjustPlayerAngle(FTranslatedLineTarget t); native static readonly GetDefaultByType(class cls); native static double deltaangle(double ang1, double ang2); native static double absangle(double ang1, double ang2); @@ -467,7 +468,6 @@ class Actor : Thinker native native void A_DeQueueCorpse(); native void A_ClearLastHeard(); native bool A_SelectWeapon(class whichweapon, int flags = 0); - native void A_Feathers(); native void A_ClassBossHealth(); native void A_ShootGun(); native void A_RocketInFlight(); @@ -476,7 +476,6 @@ class Actor : Thinker native native void A_GiveQuestItem(int itemno); native void A_RemoveForcefield(); native void A_DropWeaponPieces(class p1, class p2, class p3); - native void A_PigPain (); native void A_SetAngle(double angle = 0, int flags = 0, int ptr = AAPTR_DEFAULT); native void A_SetPitch(double pitch, int flags = 0, int ptr = AAPTR_DEFAULT); native void A_SetRoll(double roll, int flags = 0, int ptr = AAPTR_DEFAULT); diff --git a/wadsrc/static/zscript/constants.txt b/wadsrc/static/zscript/constants.txt index 29c60450c2..b5b60481aa 100644 --- a/wadsrc/static/zscript/constants.txt +++ b/wadsrc/static/zscript/constants.txt @@ -948,3 +948,8 @@ enum EFSkillProperty // floating point properties SKILLP_FriendlyHealth, }; +enum EWeaponPos +{ + WEAPONBOTTOM = 128, + WEAPONTOP = 32 +} \ No newline at end of file diff --git a/wadsrc/static/zscript/heretic/chicken.txt b/wadsrc/static/zscript/heretic/chicken.txt index 2e5ada81c8..5d6065f66a 100644 --- a/wadsrc/static/zscript/heretic/chicken.txt +++ b/wadsrc/static/zscript/heretic/chicken.txt @@ -26,8 +26,6 @@ class Beak : Weapon Weapon.SisterWeapon "BeakPowered"; } - action native void A_BeakRaise (); - action native void A_BeakAttackPL1(); States { @@ -44,9 +42,56 @@ class Beak : Weapon BEAK A 18 A_BeakAttackPL1; Goto Ready; } + + //--------------------------------------------------------------------------- + // + // PROC A_BeakRaise + // + //--------------------------------------------------------------------------- + + action void A_BeakRaise () + { + + if (player == null) + { + return; + } + player.GetPSprite(PSP_WEAPON).y = WEAPONTOP; + player.SetPsprite(PSP_WEAPON, player.ReadyWeapon.GetReadyState()); + } + + //---------------------------------------------------------------------------- + // + // PROC A_BeakAttackPL1 + // + //---------------------------------------------------------------------------- + + action void A_BeakAttackPL1() + { + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + + int damage = random[BeakAtk](1,3); + double ang = angle; + double slope = AimLineAttack (ang, MELEERANGE); + LineAttack (ang, MELEERANGE, slope, damage, 'Melee', "BeakPuff", true, t); + if (t.linetarget) + { + angle = t.angleFromSource; + } + A_PlaySound ("chicken/peck", CHAN_VOICE); + player.chickenPeck = 12; + player.GetPSprite(PSP_WEAPON).Tics -= random[BeakAtk](0,7); + } } +// BeakPowered --------------------------------------------------------------------- + class BeakPowered : Beak { Default @@ -55,7 +100,6 @@ class BeakPowered : Beak Weapon.SisterWeapon "Beak"; } - action native void A_BeakAttackPL2(); States { @@ -63,11 +107,40 @@ class BeakPowered : Beak BEAK A 12 A_BeakAttackPL2; Goto Ready; } + + //---------------------------------------------------------------------------- + // + // PROC A_BeakAttackPL2 + // + //---------------------------------------------------------------------------- + + action void A_BeakAttackPL2() + { + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + + int damage = random[BeakAtk](1,8) * 4; + double ang = angle; + double slope = AimLineAttack (ang, MELEERANGE); + LineAttack (ang, MELEERANGE, slope, damage, 'Melee', "BeakPuff", true, t); + if (t.linetarget) + { + angle = t.angleFromSource; + } + A_PlaySound ("chicken/peck", CHAN_VOICE); + player.chickenPeck = 12; + player.GetPSprite(PSP_WEAPON).Tics -= random[BeakAtk](0,3); + } + } // Chicken player ----------------------------------------------------------- -class ChickenPlayer : PlayerPawn native +class ChickenPlayer : PlayerPawn { Default { @@ -118,6 +191,44 @@ class ChickenPlayer : PlayerPawn native CHKN L -1; Stop; } + + //--------------------------------------------------------------------------- + // + // PROC P_UpdateBeak + // + //--------------------------------------------------------------------------- + + override void MorphPlayerThink () + { + if (health > 0) + { // Handle beak movement + PSprite pspr; + if (player != null && (pspr = player.FindPSprite(PSP_WEAPON)) != null) + { + pspr.y = WEAPONTOP + player.chickenPeck / 2; + } + } + if (player.morphTics & 15) + { + return; + } + if (Vel.X == 0 && Vel.Y == 0 && random[ChickenPlayerThink]() < 160) + { // Twitch view ang + angle += Random2[ChickenPlayerThink]() * (360. / 256. / 32.); + } + if ((pos.z <= floorz) && (random[ChickenPlayerThink]() < 32)) + { // Jump and noise + Vel.Z += JumpZ; + + State painstate = FindState('Pain'); + if (painstate != null) SetState (painstate); + } + if (random[ChickenPlayerThink]() < 48) + { // Just noise + A_PlaySound ("chicken/active", CHAN_VOICE); + } + } + } @@ -199,3 +310,37 @@ class Feather : Actor } } +extend class Actor +{ + //---------------------------------------------------------------------------- + // + // PROC A_Feathers + // This is used by both the chicken player and monster and must be in the + // common base class to be accessible by both + // + //---------------------------------------------------------------------------- + + void A_Feathers() + { + int count; + + if (health > 0) + { // Pain + count = random[Feathers]() < 32 ? 2 : 1; + } + else + { // Death + count = 5 + (random[Feathers]()&3); + } + for (int i = 0; i < count; i++) + { + Actor mo = Spawn("Feather", pos + (0, 0, 20), NO_REPLACE); + mo.target = self; + mo.Vel.X = Random2[Feathers]() / 256.; + mo.Vel.Y = Random2[Feathers]() / 256.; + mo.Vel.Z = 1. + random[Feathers]() / 128.; + mo.SetState (mo.SpawnState + (random[Feathers]()&7)); + } + } + +} \ No newline at end of file diff --git a/wadsrc/static/zscript/hexen/pig.txt b/wadsrc/static/zscript/hexen/pig.txt index 8fa4468827..9f62e661ea 100644 --- a/wadsrc/static/zscript/hexen/pig.txt +++ b/wadsrc/static/zscript/hexen/pig.txt @@ -34,8 +34,6 @@ class Snout : Weapon Weapon.YAdjust 10; } - action native void A_SnoutAttack (); - States { Ready: @@ -54,12 +52,43 @@ class Snout : Weapon WPIG B 8; Goto Ready; } + + //============================================================================ + // + // A_SnoutAttack + // + //============================================================================ + + action void A_SnoutAttack () + { + FTranslatedLineTarget t; + + if (player == null) + { + return; + } + + int damage = random[SnoutAttack](3, 6); + double ang = angle; + double slope = AimLineAttack(ang, MELEERANGE); + Actor puff = LineAttack(ang, MELEERANGE, slope, damage, 'Melee', "SnoutPuff", true, t); + A_PlaySound("PigActive", CHAN_VOICE); + if(t.linetarget) + { + AdjustPlayerAngle(t); + if(puff != null) + { // Bit something + A_PlaySound("PigAttack", CHAN_VOICE); + } + } + } + } // Pig player --------------------------------------------------------------- -class PigPlayer : PlayerPawn native +class PigPlayer : PlayerPawn { Default { @@ -112,6 +141,30 @@ class PigPlayer : PlayerPawn native PIGY M 1 A_FreezeDeathChunks; Wait; } + + + override void MorphPlayerThink () + { + if (player.morphTics & 15) + { + return; + } + if(Vel.X == 0 && Vel.Y == 0 && random[PigPlayerThink]() < 64) + { // Snout sniff + if (player.ReadyWeapon != null) + { + player.SetPsprite(PSP_WEAPON, player.ReadyWeapon.FindState('Grunt')); + } + A_PlaySound ("PigActive1", CHAN_VOICE); // snort + return; + } + if (random[PigPlayerThink]() < 48) + { + A_PlaySound ("PigActive", CHAN_VOICE); // snort + } + } + + } @@ -168,3 +221,21 @@ class Pig : MorphedMonster } } + +extend class Actor +{ + //============================================================================ + // + // A_PigPain + // + //============================================================================ + + void A_PigPain () + { + A_Pain(); + if (pos.z <= floorz) + { + Vel.Z = 3.5; + } + } +} \ No newline at end of file diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index f906ca01c5..2a9aabe272 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -457,6 +457,12 @@ class Weapon : StateProvider native native bool DepleteAmmo(bool altFire, bool checkEnough = true, int ammouse = -1); + virtual State GetReadyState () + { + return FindState('Ready'); + } + + native action void A_ZoomFactor(double scale = 1, int flags = 0); native action void A_SetCrosshair(int xhair); const ZOOM_INSTANT = 1; diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index c8485cebde..4f9e843331 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -49,6 +49,10 @@ class PlayerPawn : Actor native if (MeleeState != null) SetState (MeleeState); } + virtual void MorphPlayerThink() + { + } + } class PlayerChunk : PlayerPawn native @@ -78,4 +82,5 @@ struct Player native native void SetPsprite(int id, State stat, bool pending = false); native void SetSafeFlash(Weapon weap, State flashstate, int index); native PSprite GetPSprite(int id); -} \ No newline at end of file + native PSprite FindPSprite(int id); +}