diff --git a/src/p_actionfunctions.cpp b/src/p_actionfunctions.cpp index 93a521a25f..464eb1cb6e 100644 --- a/src/p_actionfunctions.cpp +++ b/src/p_actionfunctions.cpp @@ -75,7 +75,6 @@ AActor *SingleActorFromTID(int tid, AActor *defactor); static FRandom pr_camissile ("CustomActorfire"); static FRandom pr_cabullet ("CustomBullet"); -static FRandom pr_cwbullet ("CustomWpBullet"); static FRandom pr_cwjump ("CustomWpJump"); static FRandom pr_cwpunch ("CustomWpPunch"); static FRandom pr_grenade ("ThrowGrenade"); @@ -1516,112 +1515,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnProjectile) ACTION_RETURN_OBJECT(missile); } -//========================================================================== -// -// An even more customizable hitscan attack -// -//========================================================================== -enum CBA_Flags -{ - CBAF_AIMFACING = 1, - CBAF_NORANDOM = 2, - CBAF_EXPLICITANGLE = 4, - CBAF_NOPITCH = 8, - CBAF_NORANDOMPUFFZ = 16, - CBAF_PUFFTARGET = 32, - CBAF_PUFFMASTER = 64, - CBAF_PUFFTRACER = 128, -}; - -static void AimBulletMissile(AActor *proj, AActor *puff, int flags, bool temp, bool cba); - -DEFINE_ACTION_FUNCTION(AActor, A_CustomBulletAttack) -{ - PARAM_SELF_PROLOGUE(AActor); - PARAM_ANGLE (spread_xy); - PARAM_ANGLE (spread_z); - PARAM_INT (numbullets); - PARAM_INT (damageperbullet); - PARAM_CLASS (pufftype, AActor); - PARAM_FLOAT (range); - PARAM_INT (flags); - PARAM_INT (ptr); - PARAM_CLASS (missile, AActor); - PARAM_FLOAT (Spawnheight); - PARAM_FLOAT (Spawnofs_xy); - - AActor *ref = COPY_AAPTR(self, ptr); - - if (range == 0) - range = MISSILERANGE; - - int i; - DAngle bangle; - DAngle bslope = 0.; - int laflags = (flags & CBAF_NORANDOMPUFFZ)? LAF_NORANDOMPUFFZ : 0; - - if (ref != NULL || (flags & CBAF_AIMFACING)) - { - if (!(flags & CBAF_AIMFACING)) - { - A_Face(self, ref); - } - bangle = self->Angles.Yaw; - - if (!(flags & CBAF_NOPITCH)) bslope = P_AimLineAttack (self, bangle, MISSILERANGE); - if (pufftype == nullptr) pufftype = PClass::FindActor(NAME_BulletPuff); - - S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM); - for (i = 0; i < numbullets; i++) - { - DAngle angle = bangle; - DAngle slope = bslope; - - if (flags & CBAF_EXPLICITANGLE) - { - angle += spread_xy; - slope += spread_z; - } - else - { - angle += spread_xy * (pr_cwbullet.Random2() / 255.); - slope += spread_z * (pr_cwbullet.Random2() / 255.); - } - - int damage = damageperbullet; - - if (!(flags & CBAF_NORANDOM)) - damage *= ((pr_cabullet()%3)+1); - - AActor *puff = P_LineAttack(self, angle, range, slope, damage, NAME_Hitscan, pufftype, laflags); - if (missile != nullptr && pufftype != nullptr) - { - double x = Spawnofs_xy * angle.Cos(); - double y = Spawnofs_xy * angle.Sin(); - - DVector3 pos = self->Pos(); - self->SetXYZ(self->Vec3Offset(x, y, 0.)); - AActor *proj = P_SpawnMissileAngleZSpeed(self, self->Z() + self->GetBobOffset() + Spawnheight, missile, self->Angles.Yaw, 0, GetDefaultByType(missile)->Speed, self, false); - self->SetXYZ(pos); - - if (proj) - { - bool temp = (puff == nullptr); - if (!puff) - { - puff = P_LineAttack(self, angle, range, slope, 0, NAME_Hitscan, pufftype, laflags | LAF_NOINTERACT); - } - if (puff) - { - AimBulletMissile(proj, puff, flags, temp, true); - } - } - } - } - } - return 0; -} - //========================================================================== // // A fully customizable melee attack @@ -1732,177 +1625,6 @@ DEFINE_ACTION_FUNCTION(AStateProvider, A_JumpIfNoAmmo) } -//========================================================================== -// -// An even more customizable hitscan attack -// -//========================================================================== -enum FB_Flags -{ - FBF_USEAMMO = 1, - FBF_NORANDOM = 2, - FBF_EXPLICITANGLE = 4, - FBF_NOPITCH = 8, - FBF_NOFLASH = 16, - FBF_NORANDOMPUFFZ = 32, - FBF_PUFFTARGET = 64, - FBF_PUFFMASTER = 128, - FBF_PUFFTRACER = 256, -}; - -static void AimBulletMissile(AActor *proj, AActor *puff, int flags, bool temp, bool cba) -{ - if (proj && puff) - { - if (proj) - { - // FAF_BOTTOM = 1 - // Aim for the base of the puff as that's where blood puffs will spawn... roughly. - - A_Face(proj, puff, 0., 0., 0., 0., 1); - proj->Vel3DFromAngle(proj->Angles.Pitch, proj->Speed); - - if (!temp) - { - if (cba) - { - if (flags & CBAF_PUFFTARGET) proj->target = puff; - if (flags & CBAF_PUFFMASTER) proj->master = puff; - if (flags & CBAF_PUFFTRACER) proj->tracer = puff; - } - else - { - if (flags & FBF_PUFFTARGET) proj->target = puff; - if (flags & FBF_PUFFMASTER) proj->master = puff; - if (flags & FBF_PUFFTRACER) proj->tracer = puff; - } - } - } - } - if (puff && temp) - { - puff->Destroy(); - } -} - -DEFINE_ACTION_FUNCTION(AStateProvider, A_FireBullets) -{ - PARAM_ACTION_PROLOGUE(AStateProvider); - PARAM_ANGLE (spread_xy); - PARAM_ANGLE (spread_z); - PARAM_INT (numbullets); - PARAM_INT (damageperbullet); - PARAM_CLASS (pufftype, AActor); - PARAM_INT (flags); - PARAM_FLOAT (range); - PARAM_CLASS (missile, AActor); - PARAM_FLOAT (Spawnheight); - PARAM_FLOAT (Spawnofs_xy); - - if (!self->player) return 0; - - player_t *player = self->player; - AWeapon *weapon = player->ReadyWeapon; - - int i; - DAngle bangle; - DAngle bslope = 0.; - int laflags = (flags & FBF_NORANDOMPUFFZ)? LAF_NORANDOMPUFFZ : 0; - - if ((flags & FBF_USEAMMO) && weapon && ACTION_CALL_FROM_PSPRITE()) - { - if (!weapon->DepleteAmmo(weapon->bAltFire, true)) - return 0; // out of ammo - } - - if (range == 0) range = PLAYERMISSILERANGE; - - if (!(flags & FBF_NOFLASH)) static_cast(self)->PlayAttacking2 (); - - if (!(flags & FBF_NOPITCH)) bslope = P_BulletSlope(self); - bangle = self->Angles.Yaw; - - if (pufftype == NULL) pufftype = PClass::FindActor(NAME_BulletPuff); - - if (weapon != NULL) - { - S_Sound(self, CHAN_WEAPON, weapon->AttackSound, 1, ATTN_NORM); - } - - if ((numbullets == 1 && !player->refire) || numbullets == 0) - { - int damage = damageperbullet; - - if (!(flags & FBF_NORANDOM)) - damage *= ((pr_cwbullet()%3)+1); - - AActor *puff = P_LineAttack(self, bangle, range, bslope, damage, NAME_Hitscan, pufftype, laflags); - - if (missile != nullptr) - { - bool temp = false; - DAngle ang = self->Angles.Yaw - 90; - DVector2 ofs = ang.ToVector(Spawnofs_xy); - AActor *proj = P_SpawnPlayerMissile(self, ofs.X, ofs.Y, Spawnheight, missile, bangle, nullptr, nullptr, false, true); - if (proj) - { - if (!puff) - { - temp = true; - puff = P_LineAttack(self, bangle, range, bslope, 0, NAME_Hitscan, pufftype, laflags | LAF_NOINTERACT); - } - AimBulletMissile(proj, puff, flags, temp, false); - } - } - } - else - { - if (numbullets < 0) - numbullets = 1; - for (i = 0; i < numbullets; i++) - { - DAngle angle = bangle; - DAngle slope = bslope; - - if (flags & FBF_EXPLICITANGLE) - { - angle += spread_xy; - slope += spread_z; - } - else - { - angle += spread_xy * (pr_cwbullet.Random2() / 255.); - slope += spread_z * (pr_cwbullet.Random2() / 255.); - } - - int damage = damageperbullet; - - if (!(flags & FBF_NORANDOM)) - damage *= ((pr_cwbullet()%3)+1); - - AActor *puff = P_LineAttack(self, angle, range, slope, damage, NAME_Hitscan, pufftype, laflags); - - if (missile != nullptr) - { - bool temp = false; - DAngle ang = self->Angles.Yaw - 90; - DVector2 ofs = ang.ToVector(Spawnofs_xy); - AActor *proj = P_SpawnPlayerMissile(self, ofs.X, ofs.Y, Spawnheight, missile, angle, nullptr, nullptr, false, true); - if (proj) - { - if (!puff) - { - temp = true; - puff = P_LineAttack(self, angle, range, slope, 0, NAME_Hitscan, pufftype, laflags | LAF_NOINTERACT); - } - AimBulletMissile(proj, puff, flags, temp, false); - } - } - } - } - return 0; -} - //========================================================================== // diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index 0cc9c8f6b0..6c9df6c72c 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -5,6 +5,7 @@ version "3.7" #include "zscript/dynarrays.txt" #include "zscript/constants.txt" #include "zscript/actor.txt" +#include "zscript/actor_attacks.txt" #include "zscript/actor_checks.txt" #include "zscript/events.txt" #include "zscript/destructible.txt" diff --git a/wadsrc/static/zscript/actor.txt b/wadsrc/static/zscript/actor.txt index 4b710f2ab6..2e9f4be15f 100644 --- a/wadsrc/static/zscript/actor.txt +++ b/wadsrc/static/zscript/actor.txt @@ -1067,7 +1067,6 @@ class Actor : Thinker native native void A_SeekerMissile(int threshold, int turnmax, int flags = 0, int chance = 50, int distance = 10); native action state A_Jump(int chance, statelabel label, ...); native Actor A_SpawnProjectile(class missiletype, double spawnheight = 32, double spawnofs_xy = 0, double angle = 0, int flags = 0, double pitch = 0, int ptr = AAPTR_TARGET); - native void A_CustomBulletAttack(double spread_xy, double spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", double range = 0, int flags = 0, int ptr = AAPTR_TARGET, class missile = null, double Spawnheight = 32, double Spawnofs_xy = 0); native void A_CustomRailgun(int damage, int spawnofs_xy = 0, color color1 = 0, color color2 = 0, int flags = 0, int aim = 0, double maxdiff = 0, class pufftype = "BulletPuff", double spread_xy = 0, double spread_z = 0, double range = 0, int duration = 0, double sparsity = 1.0, double driftspeed = 1.0, class spawnclass = null, double spawnofs_z = 0, int spiraloffset = 270, int limit = 0, double veleffect = 3); native bool A_SetInventory(class itemtype, int amount, int ptr = AAPTR_DEFAULT, bool beyondMax = false); native bool A_GiveInventory(class itemtype, int amount = 0, int giveto = AAPTR_DEFAULT); diff --git a/wadsrc/static/zscript/actor_attacks.txt b/wadsrc/static/zscript/actor_attacks.txt new file mode 100644 index 0000000000..3c6c16d0c2 --- /dev/null +++ b/wadsrc/static/zscript/actor_attacks.txt @@ -0,0 +1,120 @@ +extend class Actor +{ + //--------------------------------------------------------------------------- + // + // Used by A_CustomBulletAttack and A_FireBullets + // + //--------------------------------------------------------------------------- + + static void AimBulletMissile(Actor proj, Actor puff, int flags, bool temp, bool cba) + { + if (proj && puff) + { + // FAF_BOTTOM = 1 + // Aim for the base of the puff as that's where blood puffs will spawn... roughly. + + proj.A_Face(puff, 0., 0., 0., 0., 1); + proj.Vel3DFromAngle(proj.Speed, proj.Angle, proj.Pitch); + + if (!temp) + { + if (cba) + { + if (flags & CBAF_PUFFTARGET) proj.target = puff; + if (flags & CBAF_PUFFMASTER) proj.master = puff; + if (flags & CBAF_PUFFTRACER) proj.tracer = puff; + } + else + { + if (flags & FBF_PUFFTARGET) proj.target = puff; + if (flags & FBF_PUFFMASTER) proj.master = puff; + if (flags & FBF_PUFFTRACER) proj.tracer = puff; + } + } + } + if (puff && temp) + { + puff.Destroy(); + } + } + + //--------------------------------------------------------------------------- + // + // + // + //--------------------------------------------------------------------------- + + void A_CustomBulletAttack(double spread_xy, double spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", double range = 0, int flags = 0, int ptr = AAPTR_TARGET, class missile = null, double Spawnheight = 32, double Spawnofs_xy = 0) + { + let ref = GetPointer(ptr); + + if (range == 0) + range = MISSILERANGE; + + int i; + double bangle; + double bslope = 0.; + int laflags = (flags & CBAF_NORANDOMPUFFZ)? LAF_NORANDOMPUFFZ : 0; + + if (ref != NULL || (flags & CBAF_AIMFACING)) + { + if (!(flags & CBAF_AIMFACING)) + { + A_Face(ref); + } + bangle = self.Angle; + + if (!(flags & CBAF_NOPITCH)) bslope = AimLineAttack (bangle, MISSILERANGE); + if (pufftype == null) pufftype = 'BulletPuff'; + + A_PlaySound(AttackSound, CHAN_WEAPON); + for (i = 0; i < numbullets; i++) + { + double pangle = bangle; + double slope = bslope; + + if (flags & CBAF_EXPLICITANGLE) + { + pangle += spread_xy; + slope += spread_z; + } + else + { + pangle += spread_xy * Random2[cwbullet]() / 255.; + slope += spread_z * Random2[cwbullet]() / 255.; + } + + int damage = damageperbullet; + + if (!(flags & CBAF_NORANDOM)) + damage *= random[cwbullet](1, 3); + + let puff = LineAttack(pangle, range, slope, damage, 'Hitscan', pufftype, laflags); + if (missile != null && pufftype != null) + { + double x = Spawnofs_xy * cos(pangle); + double y = Spawnofs_xy * sin(pangle); + + SetXYZ(Vec3Offset(x, y, 0.)); + let proj = SpawnMissileAngleZSpeed(Pos.Z + GetBobOffset() + Spawnheight, missile, self.Angle, 0, GetDefaultByType(missile).Speed, self, false); + SetXYZ(pos); + + if (proj) + { + bool temp = (puff == null); + if (!puff) + { + puff = LineAttack(pangle, range, slope, 0, 'Hitscan', pufftype, laflags | LAF_NOINTERACT); + } + if (puff) + { + AimBulletMissile(proj, puff, flags, temp, true); + } + } + } + } + } + } + + +} diff --git a/wadsrc/static/zscript/inventory/stateprovider.txt b/wadsrc/static/zscript/inventory/stateprovider.txt index abbc8db71c..ee056aea3a 100644 --- a/wadsrc/static/zscript/inventory/stateprovider.txt +++ b/wadsrc/static/zscript/inventory/stateprovider.txt @@ -3,11 +3,123 @@ class StateProvider : Inventory native { action native state A_JumpIfNoAmmo(statelabel label); action native void A_CustomPunch(int damage, bool norandom = false, int flags = CPF_USEAMMO, class pufftype = "BulletPuff", double range = 0, double lifesteal = 0, int lifestealmax = 0, class armorbonustype = "ArmorBonus", sound MeleeSound = 0, sound MissSound = ""); - action native void A_FireBullets(double spread_xy, double spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", int flags = 1, double range = 0, class missile = null, double Spawnheight = 32, double Spawnofs_xy = 0); action native Actor A_FireProjectile(class missiletype, double angle = 0, bool useammo = true, double spawnofs_xy = 0, double spawnheight = 0, int flags = 0, double pitch = 0); action native void A_RailAttack(int damage, int spawnofs_xy = 0, bool useammo = true, color color1 = 0, color color2 = 0, int flags = 0, double maxdiff = 0, class pufftype = "BulletPuff", double spread_xy = 0, double spread_z = 0, double range = 0, int duration = 0, double sparsity = 1.0, double driftspeed = 1.0, class spawnclass = "none", double spawnofs_z = 0, int spiraloffset = 270, int limit = 0); action native void A_WeaponReady(int flags = 0); + //--------------------------------------------------------------------------- + // + // + // + //--------------------------------------------------------------------------- + + action void A_FireBullets(double spread_xy, double spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", int flags = 1, double range = 0, class missile = null, double Spawnheight = 32, double Spawnofs_xy = 0) + { + let player = self.player; + if (!player) return; + + let pawn = PlayerPawn(self); + let weapon = player.ReadyWeapon; + + int i; + double bangle; + double bslope = 0.; + int laflags = (flags & FBF_NORANDOMPUFFZ)? LAF_NORANDOMPUFFZ : 0; + + if ((flags & FBF_USEAMMO) && weapon && stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + if (!weapon.DepleteAmmo(weapon.bAltFire, true)) + return; // out of ammo + } + + if (range == 0) range = PLAYERMISSILERANGE; + + if (!(flags & FBF_NOFLASH)) pawn.PlayAttacking2 (); + + if (!(flags & FBF_NOPITCH)) bslope = BulletSlope(); + bangle = self.Angle; + + if (pufftype == NULL) pufftype = 'BulletPuff'; + + if (weapon != NULL) + { + A_PlaySound(weapon.AttackSound, CHAN_WEAPON); + } + + if ((numbullets == 1 && !player.refire) || numbullets == 0) + { + int damage = damageperbullet; + + if (!(flags & FBF_NORANDOM)) + damage *= random[cabullet](1, 3); + + let puff = LineAttack(bangle, range, bslope, damage, 'Hitscan', pufftype, laflags); + + if (missile != null) + { + bool temp = false; + double ang = self.Angle - 90; + Vector2 ofs = AngleToVector(Spawnofs_xy); + Actor proj = SpawnPlayerMissile(missile, bangle, ofs.X, ofs.Y, Spawnheight); + if (proj) + { + if (!puff) + { + temp = true; + puff = LineAttack(bangle, range, bslope, 0, 'Hitscan', pufftype, laflags | LAF_NOINTERACT); + } + AimBulletMissile(proj, puff, flags, temp, false); + } + } + } + else + { + if (numbullets < 0) + numbullets = 1; + for (i = 0; i < numbullets; i++) + { + double pangle = bangle; + double slope = bslope; + + if (flags & FBF_EXPLICITANGLE) + { + pangle += spread_xy; + slope += spread_z; + } + else + { + pangle += spread_xy * Random2[cabullet]() / 255.; + slope += spread_z * Random2[cabullet]() / 255.; + } + + int damage = damageperbullet; + + if (!(flags & FBF_NORANDOM)) + damage *= random[cabullet](1, 3); + + let puff = LineAttack(pangle, range, slope, damage, 'Hitscan', pufftype, laflags); + + if (missile != null) + { + bool temp = false; + double ang = self.Angle - 90; + Vector2 ofs = AngleToVector(Spawnofs_xy); + Actor proj = SpawnPlayerMissile(missile, bangle, ofs.X, ofs.Y, Spawnheight); + if (proj) + { + if (!puff) + { + temp = true; + puff = LineAttack(bangle, range, bslope, 0, 'Hitscan', pufftype, laflags | LAF_NOINTERACT); + } + AimBulletMissile(proj, puff, flags, temp, false); + } + } + } + } + } + + //--------------------------------------------------------------------------- // // PROC A_ReFire