diff --git a/src/g_inventory/a_weapons.cpp b/src/g_inventory/a_weapons.cpp index 251a58bcb..6408c90c4 100644 --- a/src/g_inventory/a_weapons.cpp +++ b/src/g_inventory/a_weapons.cpp @@ -227,26 +227,6 @@ bool AWeapon::CheckAmmo(int fireMode, bool autoSwitch, bool requireAmmo, int amm return false; } -//=========================================================================== -// -// AWeapon :: GetDownState -// -//=========================================================================== - -FState *AWeapon::GetDownState () -{ - IFVIRTUAL(AWeapon, GetDownState) - { - VMValue params[1] = { (DObject*)this }; - VMReturn ret; - FState *retval; - ret.PointerAt((void**)&retval); - VMCall(func, params, 1, &ret, 1); - return retval; - } - return nullptr; -} - /* Weapon slots ***********************************************************/ //=========================================================================== diff --git a/src/g_inventory/a_weapons.h b/src/g_inventory/a_weapons.h index 581629af6..747f0bdb3 100644 --- a/src/g_inventory/a_weapons.h +++ b/src/g_inventory/a_weapons.h @@ -128,9 +128,6 @@ public: void Finalize(FStateDefinitions &statedef) override; void Serialize(FSerializer &arc) override; - // scripted virtuals. - FState *GetDownState (); - enum { PrimaryFire, diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index aba33a5cd..148f0a4d4 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -599,7 +599,13 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags, FName MeansOf flags &= ~MF_SOLID; player->playerstate = PST_DEAD; - P_DropWeapon (player); + + IFVM(PlayerPawn, DropWeapon) + { + VMValue param = player->mo; + VMCall(func, ¶m, 1, nullptr, 0); + } + if (this == players[consoleplayer].camera && automapactive) { // don't die in auto map, switch view prior to dying diff --git a/src/p_local.h b/src/p_local.h index 9b41253a9..66a1b304e 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -80,7 +80,6 @@ extern int bmapnegy; // P_PSPR // void P_SetupPsprites (player_t* curplayer, bool startweaponup); -void P_DropWeapon (player_t* player); // diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index 2eaa4dee1..f0a1a3856 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -563,34 +563,6 @@ void P_BringUpWeapon (player_t *player) } } -//--------------------------------------------------------------------------- -// -// PROC P_DropWeapon -// -// The player died, so put the weapon away. -// -//--------------------------------------------------------------------------- - -void P_DropWeapon (player_t *player) -{ - if (player == nullptr) - { - return; - } - // Since the weapon is dropping, stop blocking switching. - player->WeaponState &= ~WF_DISABLESWITCH; - if ((player->ReadyWeapon != nullptr) && (player->health > 0 || !(player->ReadyWeapon->WeaponFlags & WIF_NODEATHDESELECT))) - { - P_SetPsprite(player, PSP_WEAPON, player->ReadyWeapon->GetDownState()); - } -} - -DEFINE_ACTION_FUNCTION(_PlayerInfo, DropWeapon) -{ - PARAM_SELF_STRUCT_PROLOGUE(player_t); - P_DropWeapon(self); - return 0; -} //============================================================================ // // P_BobWeapon diff --git a/src/p_pspr.h b/src/p_pspr.h index c98918ded..2113a854e 100644 --- a/src/p_pspr.h +++ b/src/p_pspr.h @@ -124,7 +124,6 @@ void P_CalcSwing (player_t *player); void P_SetPsprite(player_t *player, PSPLayers id, FState *state, bool pending = false); void P_BringUpWeapon (player_t *player); void P_FireWeapon (player_t *player); -void P_DropWeapon (player_t *player); void P_BobWeapon (player_t *player, float *x, float *y, double ticfrac); DAngle P_BulletSlope (AActor *mo, FTranslatedLineTarget *pLineTarget = NULL, int aimflags = 0); AActor *P_AimTarget(AActor *mo); diff --git a/src/p_user.cpp b/src/p_user.cpp index 245a9fd21..bcc4a4ef9 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -1041,73 +1041,6 @@ bool APlayerPawn::UseInventory (AInventory *item) return true; } -//=========================================================================== -// -// APlayerPawn :: BestWeapon -// -// Returns the best weapon a player has, possibly restricted to a single -// type of ammo. -// -//=========================================================================== - -AWeapon *APlayerPawn::BestWeapon(PClassActor *ammotype) -{ - AWeapon *bestMatch = NULL; - int bestOrder = INT_MAX; - AInventory *item; - AWeapon *weap; - bool tomed = NULL != FindInventory (PClass::FindActor(NAME_PowerWeaponLevel2), true); - - // Find the best weapon the player has. - for (item = Inventory; item != NULL; item = item->Inventory) - { - if (!item->IsKindOf(NAME_Weapon)) - continue; - - weap = static_cast (item); - - // Don't select it if it's worse than what was already found. - if (weap->SelectionOrder > bestOrder) - continue; - - // Don't select it if its primary fire doesn't use the desired ammo. - if (ammotype != NULL && - (weap->Ammo1 == NULL || - weap->Ammo1->GetClass() != ammotype)) - continue; - - // Don't select it if the Tome is active and this isn't the powered-up version. - if (tomed && weap->SisterWeapon != NULL && weap->SisterWeapon->WeaponFlags & WIF_POWERED_UP) - continue; - - // Don't select it if it's powered-up and the Tome is not active. - if (!tomed && weap->WeaponFlags & WIF_POWERED_UP) - continue; - - // Don't select it if there isn't enough ammo to use its primary fire. - if (!(weap->WeaponFlags & WIF_AMMO_OPTIONAL) && - !weap->CheckAmmo (AWeapon::PrimaryFire, false)) - continue; - - // Don't select if if there isn't enough ammo as determined by the weapon's author. - if (weap->MinSelAmmo1 > 0 && (weap->Ammo1 == NULL || weap->Ammo1->Amount < weap->MinSelAmmo1)) - continue; - if (weap->MinSelAmmo2 > 0 && (weap->Ammo2 == NULL || weap->Ammo2->Amount < weap->MinSelAmmo2)) - continue; - - // This weapon is usable! - bestOrder = weap->SelectionOrder; - bestMatch = weap; - } - return bestMatch; -} - -DEFINE_ACTION_FUNCTION(APlayerPawn, BestWeapon) -{ - PARAM_SELF_PROLOGUE(APlayerPawn); - PARAM_CLASS(ammo, AActor); - ACTION_RETURN_POINTER(self->BestWeapon(ammo)); -} //=========================================================================== // // APlayerPawn :: PickNewWeapon @@ -1120,29 +1053,17 @@ DEFINE_ACTION_FUNCTION(APlayerPawn, BestWeapon) AWeapon *APlayerPawn::PickNewWeapon(PClassActor *ammotype) { - AWeapon *best = BestWeapon (ammotype); - - if (best != NULL) + AWeapon *best = nullptr; + IFVM(PlayerPawn, DropWeapon) { - player->PendingWeapon = best; - if (player->ReadyWeapon != NULL) - { - P_DropWeapon(player); - } - else if (player->PendingWeapon != WP_NOCHANGE) - { - P_BringUpWeapon (player); - } + VMValue param = player->mo; + VMReturn ret((void**)&best); + VMCall(func, ¶m, 1, &ret, 1); } + return best; } -DEFINE_ACTION_FUNCTION(APlayerPawn, PickNewWeapon) -{ - PARAM_SELF_PROLOGUE(APlayerPawn); - PARAM_CLASS(ammo, AActor); - ACTION_RETURN_POINTER(self->PickNewWeapon(ammo)); -} //=========================================================================== // // APlayerPawn :: GiveDeathmatchInventory diff --git a/wadsrc/static/zscript/inventory/weapons.txt b/wadsrc/static/zscript/inventory/weapons.txt index 3c4353f9a..dd63a6159 100644 --- a/wadsrc/static/zscript/inventory/weapons.txt +++ b/wadsrc/static/zscript/inventory/weapons.txt @@ -218,7 +218,7 @@ class Weapon : StateProvider native } if (player.PendingWeapon != WP_NOCHANGE) { - player.DropWeapon(); + player.mo.DropWeapon(); return; } if (player.ReadyWeapon == null) diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index 046d9cfa7..92c41ea6a 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -382,7 +382,7 @@ class PlayerPawn : Actor native if ((player.PendingWeapon != WP_NOCHANGE || player.health <= 0) && player.WeaponState & WF_WEAPONSWITCHOK) { - player.DropWeapon(); + DropWeapon(); } } @@ -1312,7 +1312,119 @@ class PlayerPawn : Actor native } } + //=========================================================================== + // + // APlayerPawn :: BestWeapon + // + // Returns the best weapon a player has, possibly restricted to a single + // type of ammo. + // + //=========================================================================== + + Weapon BestWeapon(Class ammotype) + { + Weapon bestMatch = NULL; + int bestOrder = int.max; + Inventory item; + bool tomed = !!FindInventory ('PowerWeaponLevel2', true); + + // Find the best weapon the player has. + for (item = Inv; item != NULL; item = item.Inv) + { + let weap = Weapon(item); + if (weap == null) + continue; + + // Don't select it if it's worse than what was already found. + if (weap.SelectionOrder > bestOrder) + continue; + + // Don't select it if its primary fire doesn't use the desired ammo. + if (ammotype != NULL && + (weap.Ammo1 == NULL || + weap.Ammo1.GetClass() != ammotype)) + continue; + + // Don't select it if the Tome is active and this isn't the powered-up version. + if (tomed && weap.SisterWeapon != NULL && weap.SisterWeapon.bPowered_Up) + continue; + + // Don't select it if it's powered-up and the Tome is not active. + if (!tomed && weap.bPowered_Up) + continue; + + // Don't select it if there isn't enough ammo to use its primary fire. + if (!(weap.bAMMO_OPTIONAL) && + !weap.CheckAmmo (Weapon.PrimaryFire, false)) + continue; + + // Don't select if if there isn't enough ammo as determined by the weapon's author. + if (weap.MinSelAmmo1 > 0 && (weap.Ammo1 == NULL || weap.Ammo1.Amount < weap.MinSelAmmo1)) + continue; + if (weap.MinSelAmmo2 > 0 && (weap.Ammo2 == NULL || weap.Ammo2.Amount < weap.MinSelAmmo2)) + continue; + + // This weapon is usable! + bestOrder = weap.SelectionOrder; + bestMatch = weap; + } + return bestMatch; + } + + //--------------------------------------------------------------------------- + // + // PROC P_DropWeapon + // + // The player died, so put the weapon away. + // + //--------------------------------------------------------------------------- + + void DropWeapon () + { + let player = self.player; + if (player == null) + { + return; + } + // Since the weapon is dropping, stop blocking switching. + player.WeaponState &= ~WF_DISABLESWITCH; + Weapon weap = player.ReadyWeapon; + if ((weap != null) && (player.health > 0 || !weap.bNoDeathDeselect)) + { + player.SetPsprite(PSP_WEAPON, weap.GetDownState()); + } + } + + //=========================================================================== + // + // APlayerPawn :: PickNewWeapon + // + // Picks a new weapon for this player. Used mostly for running out of ammo, + // but it also works when an ACS script explicitly takes the ready weapon + // away or the player picks up some ammo they had previously run out of. + // + //=========================================================================== + + Weapon PickNewWeapon(Class ammotype) + { + Weapon best = BestWeapon (ammotype); + + if (best != NULL) + { + player.PendingWeapon = best; + if (player.ReadyWeapon != NULL) + { + DropWeapon(); + } + else if (player.PendingWeapon != WP_NOCHANGE) + { + BringUpWeapon (); + } + } + return best; + } + //---------------------------------------------------------------------------- // // @@ -1327,8 +1439,6 @@ class PlayerPawn : Actor native native void CheckEnvironment(); native void CheckUse(); native void CheckWeaponButtons(); - native Weapon BestWeapon(class ammotype); - native Weapon PickNewWeapon(class ammotype); } class PlayerChunk : PlayerPawn @@ -1523,6 +1633,30 @@ struct PlayerInfo native play // this is what internally is known as player_t native @UserCmd cmd; native readonly @UserCmd original_cmd; + native bool PoisonPlayer(Actor poisoner, Actor source, int poison); + native void PoisonDamage(Actor source, int damage, bool playPainSound); + native void SetPsprite(int id, State stat, bool pending = false); + native void SetSafeFlash(Weapon weap, State flashstate, int index); + native PSprite GetPSprite(int id) const; + native PSprite FindPSprite(int id) const; + native void SetLogNumber (int text); + native void SetLogText (String text); + native bool Resurrect(); + + native String GetUserName() const; + native Color GetColor() const; + native Color GetDisplayColor() const; + native int GetColorSet() const; + native int GetPlayerClassNum() const; + native int GetSkin() const; + native bool GetNeverSwitch() const; + native int GetGender() const; + native int GetTeam() const; + native float GetAutoaim() const; + native bool GetNoAutostartMap() const; + native void SetFOV(float fov); + native bool GetClassicFlight() const; + native clearscope bool HasWeaponsInSlot(int slot) const; // The actual implementation is on PlayerPawn where it can be overridden. Use that directly in the future. deprecated("3.7") bool MorphPlayer(playerinfo p, Class spawntype, int duration, int style, Class enter_flash = null, Class exit_flash = null) @@ -1543,33 +1677,15 @@ struct PlayerInfo native play // this is what internally is known as player_t } return false; } + + deprecated("3.7") void DropWeapon() + { + if (mo != null) + { + mo.DropWeapon(); + } + } - native bool PoisonPlayer(Actor poisoner, Actor source, int poison); - native void PoisonDamage(Actor source, int damage, bool playPainSound); - native void SetPsprite(int id, State stat, bool pending = false); - native void SetSafeFlash(Weapon weap, State flashstate, int index); - native PSprite GetPSprite(int id) const; - native PSprite FindPSprite(int id) const; - native void SetLogNumber (int text); - native void SetLogText (String text); - native void DropWeapon(); - native bool Resurrect(); - - native String GetUserName() const; - native Color GetColor() const; - native Color GetDisplayColor() const; - native int GetColorSet() const; - native int GetPlayerClassNum() const; - native int GetSkin() const; - native bool GetNeverSwitch() const; - native int GetGender() const; - native int GetTeam() const; - native float GetAutoaim() const; - native bool GetNoAutostartMap() const; - native void SetFOV(float fov); - native bool GetClassicFlight() const; - native clearscope bool HasWeaponsInSlot(int slot) const; - bool IsTotallyFrozen() { return