From 483c1f6dcf053149d2dd6f7ddca69412f1e3d2c9 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 1 Jul 2021 16:37:03 +0200 Subject: [PATCH] - MBF21: added the weapon functions. --- src/gamedata/d_dehacked.cpp | 22 ++- wadsrc/static/dehsupp.txt | 9 ++ wadsrc/static/zscript.txt | 2 +- wadsrc/static/zscript/actors/mbf21.zs | 219 ++++++++++++++++++++++++++ 4 files changed, 244 insertions(+), 8 deletions(-) diff --git a/src/gamedata/d_dehacked.cpp b/src/gamedata/d_dehacked.cpp index 3f0c4b19a..2ea7cbbb4 100644 --- a/src/gamedata/d_dehacked.cpp +++ b/src/gamedata/d_dehacked.cpp @@ -142,14 +142,20 @@ static TArray StyleNames; static TArray AmmoNames; static TArray WeaponNames; +struct MBFArgs +{ + int64_t args[8]; + int argsused; +}; +static TMap stateargs; + // DeHackEd trickery to support MBF-style parameters // List of states that are hacked to use a codepointer struct MBFParamState { FState *state; int pointer; - int64_t args[8]; - int argsused; + MBFArgs args; }; static TArray MBFParamStates; // Data on how to correctly modify the codepointers @@ -1508,8 +1514,7 @@ DehBits sbits[] = { static int PatchFrame (int frameNum) { - int args[8]{}; - int argsused = 0; + MBFArgs args{}; int result; int tics, misc1, frame; FState *info, dummy; @@ -1542,7 +1547,8 @@ static int PatchFrame (int frameNum) while ((result = GetLine ()) == 1) { - int val = atoi (Line2); + int64_t val64 = atoll(Line2); + int val = int(val64); size_t keylen = strlen (Line1); if (keylen == 8 && stricmp (Line1, "Duration") == 0) @@ -1600,8 +1606,8 @@ static int PatchFrame (int frameNum) } else { - args[arg] = val; - argsused |= (1 << arg); + args.args[arg] = val64; + args.argsused |= (1 << arg); } } else if (stricmp(Line1, "MBF21 Bits") == 0) @@ -1671,6 +1677,7 @@ static int PatchFrame (int frameNum) info->Frame = frame & 0x3f; if (frame & 0x8000) info->StateFlags |= STF_FULLBRIGHT; else info->StateFlags &= ~STF_FULLBRIGHT; + stateargs.Insert(info, args); } return result; @@ -2905,6 +2912,7 @@ static void UnloadDehSupp () { SetDehParams(MBFParamStates[i].state, MBFParamStates[i].pointer, disasmdump, &MBFParamStates[i]); } + stateargs.Clear(); MBFParamStates.Clear(); MBFParamStates.ShrinkToFit(); MBFCodePointers.Clear(); diff --git a/wadsrc/static/dehsupp.txt b/wadsrc/static/dehsupp.txt index 68c322ce1..fb3637427 100644 --- a/wadsrc/static/dehsupp.txt +++ b/wadsrc/static/dehsupp.txt @@ -1208,4 +1208,13 @@ Aliases A_JumpIfTracerCloser, MBF21_JumpIfTracerCloser, A_JumpIfTracerInSight, MBF21_JumpIfTracerInSight, A_JumpIfTracerCloser, MBF21_JumpIfTracerCloser, + A_WeaponProjectile, MBF21_WeaponProjectile, + A_WeaponBulletAttack, MBF21_WeaponBulletAttack, + A_WeaponMeleeAttack, MBF21_WeaponMeleeAttack, + A_WeaponSound, A_PlayWeaponSound, + A_WeaponJump, MBF21_WeaponJump, + A_ConsumeAmmo, MBF21_ConsumeAmmo, + A_CheckAmmo, MBF21_CheckAmmo, + A_RefireTo, MBF21_RefireTo, + A_GunFlashTo, MBF21_GunFlashTo, }; diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index ce07c7bba..e9f617dfe 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -46,7 +46,6 @@ version "4.5" #include "zscript/actors/actions.zs" #include "zscript/actors/attacks.zs" #include "zscript/actors/morph.zs" -#include "zscript/actors/mbf21.zs" #include "zscript/actors/inventory/inventory.zs" #include "zscript/actors/inventory/inv_misc.zs" @@ -292,3 +291,4 @@ version "4.5" #include "zscript/compatibility.zs" #include "zscript/scriptutil/scriptutil.zs" +#include "zscript/actors/mbf21.zs" diff --git a/wadsrc/static/zscript/actors/mbf21.zs b/wadsrc/static/zscript/actors/mbf21.zs index 8a44c81d0..b55848116 100644 --- a/wadsrc/static/zscript/actors/mbf21.zs +++ b/wadsrc/static/zscript/actors/mbf21.zs @@ -168,6 +168,15 @@ extend class Actor targ.TraceBleed(newdam > 0 ? newdam : damage, self); } + // + // A_NoiseAlert + // Alerts nearby monsters (via sound) to the calling actor's target's presence. + // + void A_NoiseAlert() + { + if (target) SoundAlert(target); + } + // // A_HealChase // A parameterized version of A_VileChase. @@ -285,4 +294,214 @@ extend class Actor deprecated("2.3", "for Dehacked use only") native void MBF21_JumpIfFlagsSet(State tstate, int flags, int flags2); deprecated("2.3", "for Dehacked use only") native void MBF21_AddFlags(int flags, int flags2); deprecated("2.3", "for Dehacked use only") native void MBF21_RemoveFlags(int flags, int flags2); +} + +extend class Weapon +{ + // + // A_WeaponProjectile + // A parameterized player weapon projectile attack. Does not consume ammo. + // args[0]: Type of actor to spawn + // args[1]: Angle (degrees, in fixed point), relative to calling player's angle + // args[2]: Pitch (degrees, in fixed point), relative to calling player's pitch; approximated + // args[3]: X/Y spawn offset, relative to calling player's angle + // args[4]: Z spawn offset, relative to player's default projectile fire height + // + deprecated("2.3", "for Dehacked use only") + void MBF21_WeaponProjectile(class type, double angle, double pitch, double Spawnofs_xy, double Spawnofs_z) + { + if (!player || !type) + return; + + FTranslatedLineTarget t; + + angle += self.angle; + double x = Spawnofs_xy * cos(angle); + double y = Spawnofs_xy * sin(angle); + let pos = self.Vec3Offset(x, y, Spawnofs_z); + + let mo = SpawnPlayerMissile(type, angle, pos.X, pos.Y, pos.Z, pLineTarget: t); + if (!mo) return; + + Pitch += mo.PitchFromVel(); + mo.Vel3DFromAngle(mo.Speed, mo.angle, Pitch); + + // set tracer to the player's autoaim target, + // so player seeker missiles prioritizing the + // baddie the player is actually aiming at. ;) + mo.tracer = t.linetarget; + } + + // + // A_WeaponBulletAttack + // A parameterized player weapon bullet attack. Does not consume ammo. + // args[0]: Horizontal spread (degrees, in fixed point) + // args[1]: Vertical spread (degrees, in fixed point) + // args[2]: Number of bullets to fire; if not set, defaults to 1 + // args[3]: Base damage of attack (e.g. for 5d3, customize the 5); if not set, defaults to 5 + // args[4]: Attack damage modulus (e.g. for 5d3, customize the 3); if not set, defaults to 3 + // + deprecated("2.3", "for Dehacked use only") + void MBF21_WeaponBulletAttack(double hspread, double vspread, int numbullets, int damagebase, int damagemod) + { + let bangle = angle; + let slope = BulletSlope(); + + for (int i = 0; i < numbullets; i++) + { + int damage = (random[mbf21]() % damagemod + 1) * damagebase; + let pangle = bangle + hspread * Random2[mbf21]() / 255.; + let pslope = slope + vspread * Random2[mbf21]() / 255.; + LineAttack(pangle, PLAYERMISSILERANGE, pslope, damage, "Hitscan", "Bulletpuff"); + } + } + + + // + // A_WeaponMeleeAttack + // A parameterized player weapon melee attack. + // args[0]: Base damage of attack (e.g. for 2d10, customize the 2); if not set, defaults to 2 + // args[1]: Attack damage modulus (e.g. for 2d10, customize the 10); if not set, defaults to 10 + // args[2]: Berserk damage multiplier (fixed point); if not set, defaults to 1.0 (no change). + // args[3]: Sound to play if attack hits + // args[4]: Range (fixed point); if not set, defaults to player mobj's melee range + // + deprecated("2.3", "for Dehacked use only") + void MBF21_WeaponMeleeAttack(int damagebase, int damagemod, double zerkfactor, Sound hitsound, double range) + { + if (range == 0) + range = meleerange; + + int damage = (Random[mbf21]() % damagemod + 1) * damagebase; + if (FindInventory("PowerStrength")) + damage = int(damage * zerkfactor); + + // slight randomization; weird vanillaism here. :P + FTranslatedLineTarget t; + double ang = angle + Random2[mbf21]() * (5.625 / 256); + double pitch = AimLineAttack(ang, MeleeRange, t, 0., ALF_CHECK3D); + LineAttack(ang, range, pitch, damage, 'Melee', "BulletPuff", LAF_ISMELEEATTACK, t); + + // turn to face target + if (t.linetarget) + { + A_StartSound(hitsound, CHAN_WEAPON); + angle = t.angleFromSource; + } + } + + // + // A_WeaponAlert + // Alerts monsters to the player's presence. Handy when combined with WPF_SILENT. + // + void A_WeaponAlert() + { + SoundAlert(self); + } + + // + // A_WeaponJump + // Jumps to the specified state, with variable random chance. + // Basically the same as A_RandomJump, but for weapons. + // args[0]: State number + // args[1]: Chance, out of 255, to make the jump + // + deprecated("2.3", "for Dehacked use only") + action void MBF21_WeaponJump(State tstate, int chance) + { + if (stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + let player = self.player; + if (player == null) return; + if (random[mbf21]() < chance) + player.SetPSprite(stateinfo.mPSPIndex, tstate); + } + } + + // + // A_ConsumeAmmo + // Subtracts ammo from the player's "inventory". 'Nuff said. + // args[0]: Amount of ammo to consume. If zero, use the weapon's ammo-per-shot amount. + // + deprecated("2.3", "for Dehacked use only") + void MBF21_ConsumeAmmo(int consume) + { + let player = self.player; + if (!player) return; + let weap = player.ReadyWeapon; + if (!weap) return; + + if (consume == 0) consume = -1; + weap.DepleteAmmo(weap.bAltFire, false, consume); + } + + // + // A_CheckAmmo + // Jumps to a state if the player's ammo is lower than the specified amount. + // args[0]: State to jump to + // args[1]: Minimum required ammo to NOT jump. If zero, use the weapon's ammo-per-shot amount. + // + deprecated("2.3", "for Dehacked use only") + action void MBF21_CheckAmmo(State tstate, int amount) + { + if (stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + let player = self.player; + if (player == null) return; + let weap = player.ReadyWeapon; + if (!weap) return; + + if (amount == 0) amount = -1; + if (!weap.CheckAmmo(weap.bAltFire ? AltFire : PrimaryFire, false, false, amount)) + player.SetPSprite(stateinfo.mPSPIndex, tstate); + } + } + + // + // A_RefireTo + // Jumps to a state if the player is holding down the fire button + // args[0]: State to jump to + // args[1]: If nonzero, skip the ammo check + // + deprecated("2.3", "for Dehacked use only") + action void MBF21_RefireTo(State tstate, int skipcheck) + { + if (stateinfo != null && stateinfo.mStateType == STATE_Psprite) + { + let player = self.player; + if (player == null) return; + let weap = player.ReadyWeapon; + if (!weap) return; + + let pending = player.PendingWeapon != WP_NOCHANGE && (player.WeaponState & WF_REFIRESWITCHOK); + + if (!skipcheck && !weap.CheckAmmo(weap.bAltFire ? AltFire : PrimaryFire, false, false)) return; + + if ((player.cmd.buttons & BT_ATTACK) + && !player.ReadyWeapon.bAltFire && !pending && player.health > 0) + { + player.SetPSprite(stateinfo.mPSPIndex, tstate); + } + } + } + + // + // A_GunFlashTo + // Sets the weapon flash layer to the specified state. + // args[0]: State number + // args[1]: If nonzero, don't change the player actor state + // + deprecated("2.3", "for Dehacked use only") + void MBF21_GunFlashTo(State tstate, int dontchangeplayer) + { + let player = self.player; + if (player == null) return; + Weapon weapon = player.ReadyWeapon; + if (!weapon) return; + + if (!dontchangeplayer) player.mo.PlayAttacking2(); + player.SetPsprite(PSP_FLASH, tstate); + } + + } \ No newline at end of file