diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp index 77085f5b5..f7a73a4ce 100644 --- a/src/g_doom/a_doomweaps.cpp +++ b/src/g_doom/a_doomweaps.cpp @@ -15,6 +15,7 @@ #include "doomstat.h" */ +void P_SetSafeFlash(AWeapon *weapon, player_t *player, FState *flashstate, int index); static FRandom pr_saw ("Saw"); static FRandom pr_fireshotgun2 ("FireSG2"); static FRandom pr_fireplasma ("FirePlasma"); @@ -38,28 +39,6 @@ enum SAW_Flags }; -static FRandom pr_gunshot("GunShot"); -// -// P_GunShot -// -void P_GunShot(AActor *mo, bool accurate, PClassActor *pufftype, DAngle pitch) -{ - DAngle angle; - int damage; - - damage = 5 * (pr_gunshot() % 3 + 1); - angle = mo->Angles.Yaw; - - if (!accurate) - { - angle += pr_gunshot.Random2() * (5.625 / 256); - } - - P_LineAttack(mo, angle, PLAYERMISSILERANGE, pitch, damage, NAME_Hitscan, pufftype); -} - - - DEFINE_ACTION_FUNCTION(AActor, A_Saw) { PARAM_ACTION_PROLOGUE(AActor); @@ -199,40 +178,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_Saw) return 0; } -// -// A_FireShotgun -// -DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun) -{ - PARAM_ACTION_PROLOGUE(AActor); - - int i; - player_t *player; - - if (nullptr == (player = self->player)) - { - return 0; - } - - S_Sound (self, CHAN_WEAPON, "weapons/shotgf", 1, ATTN_NORM); - AWeapon *weapon = self->player->ReadyWeapon; - if (weapon != nullptr && ACTION_CALL_FROM_PSPRITE()) - { - if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1)) - return 0; - P_SetPsprite(player, PSP_FLASH, weapon->FindState(NAME_Flash), true); - } - player->mo->PlayAttacking2 (); - - DAngle pitch = P_BulletSlope (self); - - for (i = 0; i < 7; i++) - { - P_GunShot (self, false, PClass::FindActor(NAME_BulletPuff), pitch); - } - return 0; -} - // // A_FireShotgun2 // @@ -283,98 +228,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_FireShotgun2) return 0; } -//------------------------------------------------------------------------------------ -// -// Setting a random flash like some of Doom's weapons can easily crash when the -// definition is overridden incorrectly so let's check that the state actually exists. -// Be aware though that this will not catch all DEHACKED related problems. But it will -// find all DECORATE related ones. -// -//------------------------------------------------------------------------------------ - -void P_SetSafeFlash(AWeapon *weapon, player_t *player, FState *flashstate, int index) -{ - - PClassActor *cls = weapon->GetClass(); - while (cls != RUNTIME_CLASS(AWeapon)) - { - if (flashstate >= cls->OwnedStates && flashstate < cls->OwnedStates + cls->NumOwnedStates) - { - // The flash state belongs to this class. - // Now let's check if the actually wanted state does also - if (flashstate + index < cls->OwnedStates + cls->NumOwnedStates) - { - // we're ok so set the state - P_SetPsprite(player, PSP_FLASH, flashstate + index, true); - return; - } - else - { - // oh, no! The state is beyond the end of the state table so use the original flash state. - P_SetPsprite(player, PSP_FLASH, flashstate, true); - return; - } - } - // try again with parent class - cls = static_cast(cls->ParentClass); - } - // if we get here the state doesn't seem to belong to any class in the inheritance chain - // This can happen with Dehacked if the flash states are remapped. - // The only way to check this would be to go through all Dehacked modifiable actors, convert - // their states into a single flat array and find the correct one. - // Rather than that, just check to make sure it belongs to something. - if (FState::StaticFindStateOwner(flashstate + index) == NULL) - { // Invalid state. With no index offset, it should at least be valid. - index = 0; - } - P_SetPsprite(player, PSP_FLASH, flashstate + index, true); -} - -// -// A_FireCGun -// -DEFINE_ACTION_FUNCTION(AActor, A_FireCGun) -{ - PARAM_ACTION_PROLOGUE(AActor); - - player_t *player; - - if (self == nullptr || nullptr == (player = self->player)) - { - return 0; - } - - AWeapon *weapon = player->ReadyWeapon; - if (weapon != nullptr && ACTION_CALL_FROM_PSPRITE()) - { - if (!weapon->DepleteAmmo (weapon->bAltFire, true, 1)) - return 0; - - S_Sound (self, CHAN_WEAPON, "weapons/chngun", 1, ATTN_NORM); - - FState *flash = weapon->FindState(NAME_Flash); - if (flash != nullptr) - { - // [RH] Fix for Sparky's messed-up Dehacked patch! Blargh! - FState * atk = weapon->FindState(NAME_Fire); - - int theflash = clamp (int(player->GetPSprite(PSP_WEAPON)->GetState() - atk), 0, 1); - - if (flash[theflash].sprite != flash->sprite) - { - theflash = 0; - } - - P_SetSafeFlash (weapon, player, flash, theflash); - } - - } - player->mo->PlayAttacking2 (); - - P_GunShot (self, !player->refire, PClass::FindActor(NAME_BulletPuff), P_BulletSlope (self)); - return 0; -} - // // A_FireMissile // diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index d47156d16..3bc2dfbe1 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -29,6 +29,7 @@ #include "d_player.h" #include "serializer.h" #include "v_text.h" +#include "cmdlib.h" // MACROS ------------------------------------------------------------------ @@ -98,13 +99,20 @@ static const FGenericButtons ButtonChecks[] = // //------------------------------------------------------------------------ -IMPLEMENT_CLASS(DPSprite, false, true, false, false) +IMPLEMENT_CLASS(DPSprite, false, true, true, false) IMPLEMENT_POINTERS_START(DPSprite) IMPLEMENT_POINTER(Caller) IMPLEMENT_POINTER(Next) IMPLEMENT_POINTERS_END +void DPSprite::InitNativeFields() +{ + auto meta = RUNTIME_CLASS(DPSprite); + + meta->AddNativeField("State", TypeState, myoffsetof(DPSprite, State), VARF_ReadOnly); +} + //------------------------------------------------------------------------ // // @@ -254,6 +262,14 @@ DPSprite *player_t::GetPSprite(PSPLayers layer) return pspr; } +DEFINE_ACTION_FUNCTION(_Player, GetPSprite) // 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->GetPSprite((PSPLayers)id)); +} + + //--------------------------------------------------------------------------- // // PROC P_NewPspriteTick @@ -1561,6 +1577,63 @@ void player_t::DestroyPSprites() } } +//------------------------------------------------------------------------------------ +// +// Setting a random flash like some of Doom's weapons can easily crash when the +// definition is overridden incorrectly so let's check that the state actually exists. +// Be aware though that this will not catch all DEHACKED related problems. But it will +// find all DECORATE related ones. +// +//------------------------------------------------------------------------------------ + +void P_SetSafeFlash(AWeapon *weapon, player_t *player, FState *flashstate, int index) +{ + + PClassActor *cls = weapon->GetClass(); + while (cls != RUNTIME_CLASS(AWeapon)) + { + if (flashstate >= cls->OwnedStates && flashstate < cls->OwnedStates + cls->NumOwnedStates) + { + // The flash state belongs to this class. + // Now let's check if the actually wanted state does also + if (flashstate + index < cls->OwnedStates + cls->NumOwnedStates) + { + // we're ok so set the state + P_SetPsprite(player, PSP_FLASH, flashstate + index, true); + return; + } + else + { + // oh, no! The state is beyond the end of the state table so use the original flash state. + P_SetPsprite(player, PSP_FLASH, flashstate, true); + return; + } + } + // try again with parent class + cls = static_cast(cls->ParentClass); + } + // if we get here the state doesn't seem to belong to any class in the inheritance chain + // This can happen with Dehacked if the flash states are remapped. + // The only way to check this would be to go through all Dehacked modifiable actors, convert + // their states into a single flat array and find the correct one. + // Rather than that, just check to make sure it belongs to something. + if (FState::StaticFindStateOwner(flashstate + index) == NULL) + { // Invalid state. With no index offset, it should at least be valid. + index = 0; + } + P_SetPsprite(player, PSP_FLASH, flashstate + index, true); +} + +DEFINE_ACTION_FUNCTION(_Player, SetSafeFlash) +{ + PARAM_SELF_STRUCT_PROLOGUE(player_t); + PARAM_OBJECT(weapon, AWeapon); + PARAM_POINTER(state, FState); + PARAM_INT(index); + P_SetSafeFlash(weapon, self, state, index); + return 0; +} + //------------------------------------------------------------------------ // // diff --git a/src/p_pspr.h b/src/p_pspr.h index 3c8f0097e..4c019c7d4 100644 --- a/src/p_pspr.h +++ b/src/p_pspr.h @@ -59,6 +59,7 @@ enum PSPFlags class DPSprite : public DObject { DECLARE_CLASS (DPSprite, DObject) + HAS_FIELDS HAS_OBJECT_POINTERS public: DPSprite(player_t *owner, AActor *caller, int id); diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index 2f5a420a3..9244b9bdb 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -50,6 +50,8 @@ zscript/doom/keen.txt zscript/doom/bossbrain.txt zscript/doom/weaponfist.txt zscript/doom/weaponpistol.txt +zscript/doom/weaponshotgun.txt +zscript/doom/weaponchaingun.txt zscript/doom/deadthings.txt zscript/doom/doomammo.txt diff --git a/wadsrc/static/zscript/doom/doomweapons.txt b/wadsrc/static/zscript/doom/doomweapons.txt index 60b5ba157..ee7a821ea 100644 --- a/wadsrc/static/zscript/doom/doomweapons.txt +++ b/wadsrc/static/zscript/doom/doomweapons.txt @@ -54,54 +54,6 @@ class Chainsaw : Weapon } -// -------------------------------------------------------------------------- -// -// Shotgun -// -// -------------------------------------------------------------------------- - -class Shotgun : DoomWeapon -{ - Default - { - Weapon.SelectionOrder 1300; - Weapon.AmmoUse 1; - Weapon.AmmoGive 8; - Weapon.AmmoType "Shell"; - Inventory.PickupMessage "$GOTSHOTGUN"; - Obituary "$OB_MPSHOTGUN"; - Tag "$TAG_SHOTGUN"; - } - States - { - Ready: - SHTG A 1 A_WeaponReady; - Loop; - Deselect: - SHTG A 1 A_Lower; - Loop; - Select: - SHTG A 1 A_Raise; - Loop; - Fire: - SHTG A 3; - SHTG A 7 A_FireShotgun; - SHTG BC 5; - SHTG D 4; - SHTG CB 5; - SHTG A 3; - SHTG A 7 A_ReFire; - Goto Ready; - Flash: - SHTF A 4 Bright A_Light1; - SHTF B 3 Bright A_Light2; - Goto LightDone; - Spawn: - SHOT A -1; - Stop; - } -} - // -------------------------------------------------------------------------- // // Shotgun @@ -157,50 +109,6 @@ class SuperShotgun : DoomWeapon } } -// -------------------------------------------------------------------------- -// -// Chaingun -// -// -------------------------------------------------------------------------- - -class Chaingun : DoomWeapon -{ - Default - { - Weapon.SelectionOrder 700; - Weapon.AmmoUse 1; - Weapon.AmmoGive 20; - Weapon.AmmoType "Clip"; - Inventory.PickupMessage "$GOTCHAINGUN"; - Obituary "$OB_MPCHAINGUN"; - Tag "$TAG_CHAINGUN"; - } - States - { - Ready: - CHGG A 1 A_WeaponReady; - Loop; - Deselect: - CHGG A 1 A_Lower; - Loop; - Select: - CHGG A 1 A_Raise; - Loop; - Fire: - CHGG AB 4 A_FireCGun; - CHGG B 0 A_ReFire; - Goto Ready; - Flash: - CHGF A 5 Bright A_Light1; - Goto LightDone; - CHGF B 5 Bright A_Light2; - Goto LightDone; - Spawn: - MGUN A -1; - Stop; - } -} - // -------------------------------------------------------------------------- // // Rocket launcher diff --git a/wadsrc/static/zscript/doom/weaponchaingun.txt b/wadsrc/static/zscript/doom/weaponchaingun.txt new file mode 100644 index 000000000..92b3aec46 --- /dev/null +++ b/wadsrc/static/zscript/doom/weaponchaingun.txt @@ -0,0 +1,82 @@ +// -------------------------------------------------------------------------- +// +// Chaingun +// +// -------------------------------------------------------------------------- + +class Chaingun : DoomWeapon +{ + Default + { + Weapon.SelectionOrder 700; + Weapon.AmmoUse 1; + Weapon.AmmoGive 20; + Weapon.AmmoType "Clip"; + Inventory.PickupMessage "$GOTCHAINGUN"; + Obituary "$OB_MPCHAINGUN"; + Tag "$TAG_CHAINGUN"; + } + States + { + Ready: + CHGG A 1 A_WeaponReady; + Loop; + Deselect: + CHGG A 1 A_Lower; + Loop; + Select: + CHGG A 1 A_Raise; + Loop; + Fire: + CHGG AB 4 A_FireCGun; + CHGG B 0 A_ReFire; + Goto Ready; + Flash: + CHGF A 5 Bright A_Light1; + Goto LightDone; + CHGF B 5 Bright A_Light2; + Goto LightDone; + Spawn: + MGUN A -1; + Stop; + } +} + +//=========================================================================== +// +// Code (must be attached to StateProvider) +// +//=========================================================================== + +extend class StateProvider +{ + action void A_FireCGun() + { + if (player == null) + { + return; + } + + Weapon weap = player.ReadyWeapon; + if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + if (!weap.DepleteAmmo (weap.bAltFire, true, 1)) + return; + + A_PlaySound ("weapons/chngun", CHAN_WEAPON); + + State flash = weap.FindState('Flash'); + if (flash != null) + { + // Removed most of the mess that was here in the C++ code because SetSafeFlash already does some thorough validation. + State atk = weap.FindState('Fire'); + State cur = player.GetPSprite(PSP_WEAPON).State; + int theflash = atk == cur? 0:1; + player.SetSafeFlash(weap, flash, theflash); + } + } + player.mo.PlayAttacking2 (); + + GunShot (!player.refire, "BulletPuff", BulletSlope ()); + } +} diff --git a/wadsrc/static/zscript/doom/weaponshotgun.txt b/wadsrc/static/zscript/doom/weaponshotgun.txt new file mode 100644 index 000000000..6a08afc11 --- /dev/null +++ b/wadsrc/static/zscript/doom/weaponshotgun.txt @@ -0,0 +1,85 @@ +// -------------------------------------------------------------------------- +// +// Shotgun +// +// -------------------------------------------------------------------------- + +class Shotgun : DoomWeapon +{ + Default + { + Weapon.SelectionOrder 1300; + Weapon.AmmoUse 1; + Weapon.AmmoGive 8; + Weapon.AmmoType "Shell"; + Inventory.PickupMessage "$GOTSHOTGUN"; + Obituary "$OB_MPSHOTGUN"; + Tag "$TAG_SHOTGUN"; + } + States + { + Ready: + SHTG A 1 A_WeaponReady; + Loop; + Deselect: + SHTG A 1 A_Lower; + Loop; + Select: + SHTG A 1 A_Raise; + Loop; + Fire: + SHTG A 3; + SHTG A 7 A_FireShotgun; + SHTG BC 5; + SHTG D 4; + SHTG CB 5; + SHTG A 3; + SHTG A 7 A_ReFire; + Goto Ready; + Flash: + SHTF A 4 Bright A_Light1; + SHTF B 3 Bright A_Light2; + Goto LightDone; + Spawn: + SHOT A -1; + Stop; + } +} + +//=========================================================================== +// +// Code (must be attached to StateProvider) +// +//=========================================================================== + +extend class StateProvider +{ + + action void A_FireShotgun() + { + if (player == null) + { + return; + } + + A_PlaySound ("weapons/shotgf", CHAN_WEAPON); + Weapon weap = player.ReadyWeapon; + if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + if (!weap.DepleteAmmo (weap.bAltFire, true, 1)) + return; + + player.SetPsprite(PSP_FLASH, weap.FindState('Flash'), true); + } + player.mo.PlayAttacking2 (); + + double pitch = BulletSlope (); + + for (int i = 0; i < 7; i++) + { + GunShot (false, "BulletPuff", pitch); + } + } + +} + diff --git a/wadsrc/static/zscript/shared/inventory.txt b/wadsrc/static/zscript/shared/inventory.txt index d66843593..64c649ad6 100644 --- a/wadsrc/static/zscript/shared/inventory.txt +++ b/wadsrc/static/zscript/shared/inventory.txt @@ -49,14 +49,12 @@ class StateProvider : Inventory native action native void A_WeaponReady(int flags = 0); action native void A_Lower(); action native void A_Raise(); - action native void A_FireShotgun(); action native void A_FireShotgun2(); action void A_OpenShotgun2() { A_PlaySound("weapons/sshoto", CHAN_WEAPON); } action void A_LoadShotgun2() { A_PlaySound("weapons/sshotl", CHAN_WEAPON); } action void A_CloseShotgun2() { A_PlaySound("weapons/sshotc", CHAN_WEAPON); } - action native void A_FireCGun(); action native void A_FireSTGrenade(class grenadetype = "Grenade"); action native void A_FireMissile(); action native void A_FirePlasma(); diff --git a/wadsrc/static/zscript/shared/player.txt b/wadsrc/static/zscript/shared/player.txt index e2bbefbea..c8485cebd 100644 --- a/wadsrc/static/zscript/shared/player.txt +++ b/wadsrc/static/zscript/shared/player.txt @@ -76,4 +76,6 @@ class PSprite : Object native 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