mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-11 07:12:02 +00:00
- scriptified A_FireShotgun and A_FireChaingun.
This commit is contained in:
parent
d50da34664
commit
0b70df88d8
9 changed files with 247 additions and 243 deletions
|
@ -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<PClassActor *>(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
|
||||
//
|
||||
|
|
|
@ -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<PClassActor *>(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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
82
wadsrc/static/zscript/doom/weaponchaingun.txt
Normal file
82
wadsrc/static/zscript/doom/weaponchaingun.txt
Normal file
|
@ -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 ());
|
||||
}
|
||||
}
|
85
wadsrc/static/zscript/doom/weaponshotgun.txt
Normal file
85
wadsrc/static/zscript/doom/weaponshotgun.txt
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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<Actor> grenadetype = "Grenade");
|
||||
action native void A_FireMissile();
|
||||
action native void A_FirePlasma();
|
||||
|
|
|
@ -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);
|
||||
}
|
Loading…
Reference in a new issue