From 45a13527ef6f4b69288726f261f9d33ab1d337cd Mon Sep 17 00:00:00 2001 From: Xaser Acheron Date: Sat, 24 Apr 2021 21:00:46 -0500 Subject: [PATCH 01/10] new args for A_MonsterBulletAttack and A_WeaponBulletAttack --- prboom2/src/d_deh.c | 4 ++-- prboom2/src/p_enemy.c | 39 ++++++++++++++++++++++++++++----------- prboom2/src/p_pspr.c | 38 +++++++++++++++++++++++++++----------- 3 files changed, 57 insertions(+), 24 deletions(-) diff --git a/prboom2/src/d_deh.c b/prboom2/src/d_deh.c index 7b4fad904..9cc4d9c4d 100644 --- a/prboom2/src/d_deh.c +++ b/prboom2/src/d_deh.c @@ -1450,10 +1450,10 @@ static const deh_bexptr deh_bexptrs[] = // CPhipps - static const // [XA] New mbf21 codepointers {A_SpawnFacing, "A_SpawnFacing", 2}, {A_MonsterProjectile, "A_MonsterProjectile", 2}, - {A_MonsterBulletAttack, "A_MonsterBulletAttack", 2}, + {A_MonsterBulletAttack, "A_MonsterBulletAttack", 5}, {A_RadiusDamage, "A_RadiusDamage", 2}, {A_WeaponProjectile, "A_WeaponProjectile", 2}, - {A_WeaponBulletAttack, "A_WeaponBulletAttack", 2}, + {A_WeaponBulletAttack, "A_WeaponBulletAttack", 5}, {A_WeaponSound, "A_WeaponSound", 2}, {A_WeaponJump, "A_WeaponJump", 2}, {A_ConsumeAmmo, "A_ConsumeAmmo", 1}, diff --git a/prboom2/src/p_enemy.c b/prboom2/src/p_enemy.c index 5e7dfc202..39dfe350f 100644 --- a/prboom2/src/p_enemy.c +++ b/prboom2/src/p_enemy.c @@ -3041,30 +3041,47 @@ void A_MonsterProjectile(mobj_t *actor) // // A_MonsterBulletAttack // A parameterized monster bullet attack. -// args[0]: Damage of attack (times 1d5) -// args[1]: Horizontal spread (degrees, in fixed point); -// if negative, also use 2/3 of this value for vertical spread +// 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 3d5, customize the 3); if not set, defaults to 3 +// args[4]: Attack damage modulus (e.g. for 3d5, customize the 5); if not set, defaults to 5 // void A_MonsterBulletAttack(mobj_t *actor) { - int damage, angle, slope, t; + int hspread, vspread, numbullets, damagebase, damagemod; + int aimslope, i, damage, angle, slope; int_64_t spread; if (!mbf21 || !actor->target) return; + hspread = actor->state->args[0]; + vspread = actor->state->args[1]; + numbullets = actor->state->args[2]; + damagebase = actor->state->args[3]; + damagemod = actor->state->args[4]; + + if (numbullets == 0) + numbullets = 1; + if (damagebase == 0) + damagebase = 3; + if (damagemod == 0) + damagemod = 5; + A_FaceTarget(actor); S_StartSound(actor, actor->info->attacksound); - damage = (P_Random(pr_mbf21) % 5 + 1) * actor->state->args[0]; - - angle = (int)actor->angle + P_RandomHitscanAngle(pr_mbf21, actor->state->args[1]);; - slope = P_AimLineAttack(actor, angle, MISSILERANGE, 0); + aimslope = P_AimLineAttack(actor, actor->angle, MISSILERANGE, 0); - if (actor->state->args[1] < 0) - slope += P_RandomHitscanSlope(pr_mbf21, actor->state->args[1] * 2 / 3); + for (i = 0; i < numbullets; i++) + { + damage = (P_Random(pr_mbf21) % damagemod + 1) * damagebase; + angle = (int)actor->angle + P_RandomHitscanAngle(pr_mbf21, hspread); + slope = aimslope + P_RandomHitscanSlope(pr_mbf21, vspread); - P_LineAttack(actor, angle, MISSILERANGE, slope, damage); + P_LineAttack(actor, angle, MISSILERANGE, slope, damage); + } } // diff --git a/prboom2/src/p_pspr.c b/prboom2/src/p_pspr.c index bee5324db..1bd96eb51 100644 --- a/prboom2/src/p_pspr.c +++ b/prboom2/src/p_pspr.c @@ -1166,29 +1166,45 @@ void A_WeaponProjectile(player_t *player, pspdef_t *psp) // // A_WeaponBulletAttack // A parameterized player weapon bullet attack. Does not consume ammo. -// args[0]: Damage of attack (times 1d3) -// args[1]: Horizontal spread (degrees, in fixed point); -// if negative, also use 2/3 of this value for vertical spread +// 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 // void A_WeaponBulletAttack(player_t *player, pspdef_t *psp) { - int damage, angle, slope; + int hspread, vspread, numbullets, damagebase, damagemod; + int i, damage, angle, slope; CHECK_WEAPON_CODEPOINTER("A_WeaponBulletAttack", player); if (!mbf21 || !psp->state) return; - P_BulletSlope(player->mo); + hspread = psp->state->args[0]; + vspread = psp->state->args[1]; + numbullets = psp->state->args[2]; + damagebase = psp->state->args[3]; + damagemod = psp->state->args[4]; - damage = (P_Random(pr_mbf21) % 3 + 1) * psp->state->args[0]; - angle = (int)player->mo->angle + P_RandomHitscanAngle(pr_mbf21, psp->state->args[1]); - slope = bulletslope; + if (numbullets == 0) + numbullets = 1; + if (damagebase == 0) + damagebase = 5; + if (damagemod == 0) + damagemod = 3; - if (psp->state->args[1] < 0) - slope += P_RandomHitscanSlope(pr_mbf21, psp->state->args[1] * 2 / 3); + P_BulletSlope(player->mo); - P_LineAttack(player->mo, angle, MISSILERANGE, slope, damage); + for (i = 0; i < numbullets; i++) + { + damage = (P_Random(pr_mbf21) % damagemod + 1) * damagebase; + angle = (int)player->mo->angle + P_RandomHitscanAngle(pr_mbf21, hspread); + slope = bulletslope + P_RandomHitscanSlope(pr_mbf21, vspread); + + P_LineAttack(player->mo, angle, MISSILERANGE, slope, damage); + } } // From b309931c8d56b436e5361d5b5d3f743d372b5716 Mon Sep 17 00:00:00 2001 From: Xaser Acheron Date: Sat, 24 Apr 2021 23:31:05 -0500 Subject: [PATCH 02/10] add ARG_DEFAULT macro for nice n' clean code :P --- prboom2/src/doomtype.h | 3 +++ prboom2/src/p_enemy.c | 17 +++++------------ prboom2/src/p_pspr.c | 17 +++++------------ 3 files changed, 13 insertions(+), 24 deletions(-) diff --git a/prboom2/src/doomtype.h b/prboom2/src/doomtype.h index b4f0b60b4..a4e4066c2 100644 --- a/prboom2/src/doomtype.h +++ b/prboom2/src/doomtype.h @@ -175,4 +175,7 @@ enum patch_translation_e { VPT_NOOFFSET = 1024, }; +// [XA] Common macro for defining an arg's default value if zero +#define ARG_DEFAULT(x, y) ((x) == 0 ? (y) : (x)) + #endif diff --git a/prboom2/src/p_enemy.c b/prboom2/src/p_enemy.c index 39dfe350f..ebddd2ab1 100644 --- a/prboom2/src/p_enemy.c +++ b/prboom2/src/p_enemy.c @@ -3056,18 +3056,11 @@ void A_MonsterBulletAttack(mobj_t *actor) if (!mbf21 || !actor->target) return; - hspread = actor->state->args[0]; - vspread = actor->state->args[1]; - numbullets = actor->state->args[2]; - damagebase = actor->state->args[3]; - damagemod = actor->state->args[4]; - - if (numbullets == 0) - numbullets = 1; - if (damagebase == 0) - damagebase = 3; - if (damagemod == 0) - damagemod = 5; + hspread = ARG_DEFAULT(actor->state->args[0], 0); + vspread = ARG_DEFAULT(actor->state->args[1], 0); + numbullets = ARG_DEFAULT(actor->state->args[2], 1); + damagebase = ARG_DEFAULT(actor->state->args[3], 3); + damagemod = ARG_DEFAULT(actor->state->args[4], 5); A_FaceTarget(actor); S_StartSound(actor, actor->info->attacksound); diff --git a/prboom2/src/p_pspr.c b/prboom2/src/p_pspr.c index 1bd96eb51..67bd835e8 100644 --- a/prboom2/src/p_pspr.c +++ b/prboom2/src/p_pspr.c @@ -1182,18 +1182,11 @@ void A_WeaponBulletAttack(player_t *player, pspdef_t *psp) if (!mbf21 || !psp->state) return; - hspread = psp->state->args[0]; - vspread = psp->state->args[1]; - numbullets = psp->state->args[2]; - damagebase = psp->state->args[3]; - damagemod = psp->state->args[4]; - - if (numbullets == 0) - numbullets = 1; - if (damagebase == 0) - damagebase = 5; - if (damagemod == 0) - damagemod = 3; + hspread = ARG_DEFAULT(psp->state->args[0], 0); + vspread = ARG_DEFAULT(psp->state->args[1], 0); + numbullets = ARG_DEFAULT(psp->state->args[2], 1); + damagebase = ARG_DEFAULT(psp->state->args[3], 5); + damagemod = ARG_DEFAULT(psp->state->args[4], 3); P_BulletSlope(player->mo); From 6860d48ff5d521891f3338535a5dd9aac0165435 Mon Sep 17 00:00:00 2001 From: Xaser Acheron Date: Thu, 29 Apr 2021 15:46:10 -0500 Subject: [PATCH 03/10] new args for A_MonsterProjectile and A_WeaponProjectile --- prboom2/src/d_deh.c | 4 ++-- prboom2/src/p_enemy.c | 27 +++++++++++++++++++++++---- prboom2/src/p_pspr.c | 30 +++++++++++++++++++++++++----- prboom2/src/tables.h | 20 ++++++++++++++++++++ 4 files changed, 70 insertions(+), 11 deletions(-) diff --git a/prboom2/src/d_deh.c b/prboom2/src/d_deh.c index 9cc4d9c4d..fbde42279 100644 --- a/prboom2/src/d_deh.c +++ b/prboom2/src/d_deh.c @@ -1449,10 +1449,10 @@ static const deh_bexptr deh_bexptrs[] = // CPhipps - static const // [XA] New mbf21 codepointers {A_SpawnFacing, "A_SpawnFacing", 2}, - {A_MonsterProjectile, "A_MonsterProjectile", 2}, + {A_MonsterProjectile, "A_MonsterProjectile", 5}, {A_MonsterBulletAttack, "A_MonsterBulletAttack", 5}, {A_RadiusDamage, "A_RadiusDamage", 2}, - {A_WeaponProjectile, "A_WeaponProjectile", 2}, + {A_WeaponProjectile, "A_WeaponProjectile", 5}, {A_WeaponBulletAttack, "A_WeaponBulletAttack", 5}, {A_WeaponSound, "A_WeaponSound", 2}, {A_WeaponJump, "A_WeaponJump", 2}, diff --git a/prboom2/src/p_enemy.c b/prboom2/src/p_enemy.c index ebddd2ab1..3d5ac3be8 100644 --- a/prboom2/src/p_enemy.c +++ b/prboom2/src/p_enemy.c @@ -3013,26 +3013,46 @@ void A_SpawnFacing(mobj_t *actor) // A parameterized monster projectile attack. // args[0]: Type of actor to spawn // args[1]: Angle (degrees, in fixed point), relative to calling actor's angle +// args[2]: Pitch (degrees, in fixed point), relative to calling actor's pitch; approximated +// args[3]: X/Y spawn offset, relative to calling actor's angle +// args[4]: Z spawn offset, relative to actor's default projectile fire height // void A_MonsterProjectile(mobj_t *actor) { + int type, angle, pitch, spawnofs_xy, spawnofs_z; mobj_t *mo; int an; if (!mbf21 || !actor->target || !actor->state->args[0]) return; + type = ARG_DEFAULT(actor->state->args[0], 0) - 1; + angle = ARG_DEFAULT(actor->state->args[1], 0); + pitch = ARG_DEFAULT(actor->state->args[2], 0); + spawnofs_xy = ARG_DEFAULT(actor->state->args[3], 0); + spawnofs_z = ARG_DEFAULT(actor->state->args[4], 0); + A_FaceTarget(actor); - mo = P_SpawnMissile(actor, actor->target, actor->state->args[0] - 1); + mo = P_SpawnMissile(actor, actor->target, type); if (!mo) return; - // adjust the angle by args[1]; - mo->angle += (unsigned int)(((int_64_t)actor->state->args[1] << 16) / 360); + // adjust angle + mo->angle += (unsigned int)(((int_64_t)angle << 16) / 360); an = mo->angle >> ANGLETOFINESHIFT; mo->momx = FixedMul(mo->info->speed, finecosine[an]); mo->momy = FixedMul(mo->info->speed, finesine[an]); + // adjust pitch (approximated, using Doom's ye olde + // finetangent table; same method as monster aim) + mo->momz += FixedMul(mo->info->speed, DegToSlope(pitch)); + + // adjust position + an = (actor->angle - ANG90) >> ANGLETOFINESHIFT; + mo->x += FixedMul(spawnofs_xy, finecosine[an]); + mo->y += FixedMul(spawnofs_xy, finesine[an]); + mo->z += spawnofs_z; + // always set the 'tracer' field, so this pointer // can be used to fire seeker missiles at will. P_SetTarget(&mo->tracer, actor->target); @@ -3051,7 +3071,6 @@ void A_MonsterBulletAttack(mobj_t *actor) { int hspread, vspread, numbullets, damagebase, damagemod; int aimslope, i, damage, angle, slope; - int_64_t spread; if (!mbf21 || !actor->target) return; diff --git a/prboom2/src/p_pspr.c b/prboom2/src/p_pspr.c index 67bd835e8..254ec1551 100644 --- a/prboom2/src/p_pspr.c +++ b/prboom2/src/p_pspr.c @@ -1140,10 +1140,14 @@ void A_BFGsound(player_t *player, pspdef_t *psp) // 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 actor's angle +// 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 // void A_WeaponProjectile(player_t *player, pspdef_t *psp) { + int type, angle, pitch, spawnofs_xy, spawnofs_z; mobj_t *mo; int an; @@ -1152,15 +1156,31 @@ void A_WeaponProjectile(player_t *player, pspdef_t *psp) if (!mbf21 || !psp->state || !psp->state->args[0]) return; - mo = P_SpawnPlayerMissile(player->mo, psp->state->args[0] - 1); + type = ARG_DEFAULT(psp->state->args[0], 0) - 1; + angle = ARG_DEFAULT(psp->state->args[1], 0); + pitch = ARG_DEFAULT(psp->state->args[2], 0); + spawnofs_xy = ARG_DEFAULT(psp->state->args[3], 0); + spawnofs_z = ARG_DEFAULT(psp->state->args[4], 0); + + mo = P_SpawnPlayerMissile(player->mo, type); if (!mo) - return; + return; - // adjust the angle by args[1]; - mo->angle += (unsigned int)(((int_64_t)psp->state->args[1] << 16) / 360); + // adjust angle + mo->angle += (unsigned int)(((int_64_t)angle << 16) / 360); an = mo->angle >> ANGLETOFINESHIFT; mo->momx = FixedMul(mo->info->speed, finecosine[an]); mo->momy = FixedMul(mo->info->speed, finesine[an]); + + // adjust pitch (approximated, using Doom's ye olde + // finetangent table; same method as autoaim) + mo->momz += FixedMul(mo->info->speed, DegToSlope(pitch)); + + // adjust position + an = (player->mo->angle - ANG90) >> ANGLETOFINESHIFT; + mo->x += FixedMul(spawnofs_xy, finecosine[an]); + mo->y += FixedMul(spawnofs_xy, finesine[an]); + mo->z += spawnofs_z; } // diff --git a/prboom2/src/tables.h b/prboom2/src/tables.h index 7578b3224..ff5086a23 100644 --- a/prboom2/src/tables.h +++ b/prboom2/src/tables.h @@ -106,4 +106,24 @@ inline static fixed_t AngleToFixed(angle_t a) return (fixed_t)(((uint_64_t)a << FRACBITS) / ANG1); } +// [XA] Clamped angle->slope, for convenience +inline static fixed_t AngleToSlope(int a) +{ + if (a > ANG90) + return finetangent[0]; + else if (-a > ANG90) + return finetangent[FINEANGLES / 2 - 1]; + else + return finetangent[(ANG90 - a) >> ANGLETOFINESHIFT]; +} + +// [XA] Ditto, using fixed-point-degrees input +inline static fixed_t DegToSlope(fixed_t a) +{ + if (a >= 0) + return AngleToSlope(FixedToAngle(a)); + else + return AngleToSlope(-(int)FixedToAngle(-a)); +} + #endif From 9210d78a89cc682bca8b19724eebd2fc180530b9 Mon Sep 17 00:00:00 2001 From: Xaser Acheron Date: Fri, 30 Apr 2021 14:55:08 -0500 Subject: [PATCH 04/10] add a bunch of new args to A_SpawnFacing --- prboom2/src/d_deh.c | 2 +- prboom2/src/p_enemy.c | 52 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/prboom2/src/d_deh.c b/prboom2/src/d_deh.c index fbde42279..165ffbbef 100644 --- a/prboom2/src/d_deh.c +++ b/prboom2/src/d_deh.c @@ -1448,7 +1448,7 @@ static const deh_bexptr deh_bexptrs[] = // CPhipps - static const {A_Stop, "A_Stop"}, // [XA] New mbf21 codepointers - {A_SpawnFacing, "A_SpawnFacing", 2}, + {A_SpawnFacing, "A_SpawnFacing", 8}, {A_MonsterProjectile, "A_MonsterProjectile", 5}, {A_MonsterBulletAttack, "A_MonsterBulletAttack", 5}, {A_RadiusDamage, "A_RadiusDamage", 2}, diff --git a/prboom2/src/p_enemy.c b/prboom2/src/p_enemy.c index 3d5ac3be8..98c341a8b 100644 --- a/prboom2/src/p_enemy.c +++ b/prboom2/src/p_enemy.c @@ -2988,21 +2988,61 @@ void A_LineEffect(mobj_t *mo) // // A_SpawnFacing -// Spawns an actor facing the same direction as the caller. -// Basically just A_Spawn with a major quality-of-life tweak. +// Basically just A_Spawn with better behavior and more args. // args[0]: Type of actor to spawn -// args[1]: Height to spawn at, relative to calling actor +// args[1]: Angle (degrees, in fixed point), relative to calling actor's angle +// args[2]: X spawn offset (fixed point), relative to calling actor +// args[3]: Y spawn offset (fixed point), relative to calling actor +// args[4]: Z spawn offset (fixed point), relative to calling actor +// args[5]: X velocity (fixed point) +// args[6]: Y velocity (fixed point) +// args[7]: Z velocity (fixed point) // void A_SpawnFacing(mobj_t *actor) { + int type, angle, ofs_x, ofs_y, ofs_z, vel_x, vel_y, vel_z; + angle_t an; + int fan, dx, dy; mobj_t *mo; if (!mbf21 || !actor->state->args[0]) return; - mo = P_SpawnMobj(actor->x, actor->y, (actor->state->args[1] << FRACBITS) + actor->z, actor->state->args[0] - 1); - if (mo) - mo->angle = actor->angle; + type = ARG_DEFAULT(actor->state->args[0], 0) - 1; + angle = ARG_DEFAULT(actor->state->args[1], 0); + ofs_x = ARG_DEFAULT(actor->state->args[2], 0); + ofs_y = ARG_DEFAULT(actor->state->args[3], 0); + ofs_z = ARG_DEFAULT(actor->state->args[4], 0); + vel_x = ARG_DEFAULT(actor->state->args[5], 0); + vel_y = ARG_DEFAULT(actor->state->args[6], 0); + vel_z = ARG_DEFAULT(actor->state->args[7], 0); + + // calculate position offsets + an = actor->angle + (unsigned int)(((int_64_t)angle << 16) / 360); + fan = an >> ANGLETOFINESHIFT; + dx = FixedMul(ofs_x, finecosine[fan]) - FixedMul(ofs_y, finesine[fan] ); + dy = FixedMul(ofs_x, finesine[fan] ) + FixedMul(ofs_y, finecosine[fan]); + + // spawn it, yo + mo = P_SpawnMobj(actor->x + dx, actor->y + dy, actor->z + ofs_z, type); + if (!mo) + return; + + // angle dangle + mo->angle = an; + + // set velocity + mo->momx = FixedMul(vel_x, finecosine[fan]) - FixedMul(vel_y, finesine[fan] ); + mo->momy = FixedMul(vel_x, finesine[fan] ) + FixedMul(vel_y, finecosine[fan]); + mo->momz = vel_z; + + // copy target+tracer pointers for missiles, so + // they can use this to spawn sub-missiles safely + if (actor->flags & (MF_MISSILE | MF_BOUNCES)) + { + P_SetTarget(&mo->target, actor->target); + P_SetTarget(&mo->tracer, actor->tracer); + } // [XA] don't bother with the dont-inherit-friendliness hack // that exists in A_Spawn, 'cause WTF is that about anyway? From 27b45ea8a89fedbc7275c19591315b77053d701d Mon Sep 17 00:00:00 2001 From: Xaser Acheron Date: Fri, 30 Apr 2021 14:59:12 -0500 Subject: [PATCH 05/10] rename A_SpawnFacing to A_SpawnObject --- prboom2/src/d_deh.c | 2 +- prboom2/src/p_enemy.c | 4 ++-- prboom2/src/p_enemy.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/prboom2/src/d_deh.c b/prboom2/src/d_deh.c index 165ffbbef..bed374889 100644 --- a/prboom2/src/d_deh.c +++ b/prboom2/src/d_deh.c @@ -1448,7 +1448,7 @@ static const deh_bexptr deh_bexptrs[] = // CPhipps - static const {A_Stop, "A_Stop"}, // [XA] New mbf21 codepointers - {A_SpawnFacing, "A_SpawnFacing", 8}, + {A_SpawnObject, "A_SpawnObject", 8}, {A_MonsterProjectile, "A_MonsterProjectile", 5}, {A_MonsterBulletAttack, "A_MonsterBulletAttack", 5}, {A_RadiusDamage, "A_RadiusDamage", 2}, diff --git a/prboom2/src/p_enemy.c b/prboom2/src/p_enemy.c index 98c341a8b..c8de61534 100644 --- a/prboom2/src/p_enemy.c +++ b/prboom2/src/p_enemy.c @@ -2987,7 +2987,7 @@ void A_LineEffect(mobj_t *mo) // // -// A_SpawnFacing +// A_SpawnObject // Basically just A_Spawn with better behavior and more args. // args[0]: Type of actor to spawn // args[1]: Angle (degrees, in fixed point), relative to calling actor's angle @@ -2998,7 +2998,7 @@ void A_LineEffect(mobj_t *mo) // args[6]: Y velocity (fixed point) // args[7]: Z velocity (fixed point) // -void A_SpawnFacing(mobj_t *actor) +void A_SpawnObject(mobj_t *actor) { int type, angle, ofs_x, ofs_y, ofs_z, vel_x, vel_y, vel_z; angle_t an; diff --git a/prboom2/src/p_enemy.h b/prboom2/src/p_enemy.h index 572440a1c..6f3c9d402 100644 --- a/prboom2/src/p_enemy.h +++ b/prboom2/src/p_enemy.h @@ -122,7 +122,7 @@ void A_SkullPop(mobj_t *); // [XA] New mbf21 codepointers -void A_SpawnFacing(mobj_t *); +void A_SpawnObject(mobj_t *); void A_MonsterProjectile(mobj_t *); void A_MonsterBulletAttack(mobj_t *); void A_RadiusDamage(mobj_t *); From b391bdbfe40aac15424eb221d5090d72483d953e Mon Sep 17 00:00:00 2001 From: Xaser Acheron Date: Fri, 30 Apr 2021 22:16:11 -0500 Subject: [PATCH 06/10] improve A_SpawnObject's target+tracer transfer logic --- prboom2/src/p_enemy.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/prboom2/src/p_enemy.c b/prboom2/src/p_enemy.c index 7ceee9bf5..95c28a195 100644 --- a/prboom2/src/p_enemy.c +++ b/prboom2/src/p_enemy.c @@ -3037,12 +3037,21 @@ void A_SpawnObject(mobj_t *actor) mo->momy = FixedMul(vel_x, finesine[fan] ) + FixedMul(vel_y, finecosine[fan]); mo->momz = vel_z; - // copy target+tracer pointers for missiles, so - // they can use this to spawn sub-missiles safely - if (actor->flags & (MF_MISSILE | MF_BOUNCES)) + // if spawned object is a missile, set target+tracer + if (mo->flags & (MF_MISSILE | MF_BOUNCES)) { - P_SetTarget(&mo->target, actor->target); - P_SetTarget(&mo->tracer, actor->tracer); + // if spawner is also a missile, copy 'em + if (actor->flags & (MF_MISSILE | MF_BOUNCES)) + { + P_SetTarget(&mo->target, actor->target); + P_SetTarget(&mo->tracer, actor->tracer); + } + // otherwise, set 'em as if a monster fired 'em + else + { + P_SetTarget(&mo->target, actor); + P_SetTarget(&mo->tracer, actor->target); + } } // [XA] don't bother with the dont-inherit-friendliness hack From acaa54ecd2f9754cf1f5ac4a5cc5b4e6594ea8d6 Mon Sep 17 00:00:00 2001 From: Xaser Acheron Date: Fri, 30 Apr 2021 22:16:45 -0500 Subject: [PATCH 07/10] update mbf21.md codepointer documentation --- prboom2/src/mbf21.md | 138 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 124 insertions(+), 14 deletions(-) diff --git a/prboom2/src/mbf21.md b/prboom2/src/mbf21.md index 6c5215652..cdda67591 100644 --- a/prboom2/src/mbf21.md +++ b/prboom2/src/mbf21.md @@ -211,20 +211,130 @@ MBF21 defaults: #### New DEHACKED Codepointers - [PR](https://github.com/kraflab/dsda-doom/pull/20) - All new MBF21 pointers use the new "Args" fields for params, rather than misc1/misc2 fields -- Actor pointers: - - **A_SpawnFacing(type, height)** -- spawns an actor of `type` at `height` z units and sets its angle to the caller's angle. - - **A_MonsterProjectile(type, angle)** -- generic monster projectile attack; always sets `tracer` field. - - **A_MonsterBulletAttack(damage, spread)** -- generic monster bullet attack w/horizontal `spread`; if `spread` is negative, apply vertical spread equal to 2/3 of this value (approx. equal to SSG vert-spread) - - **A_RadiusDamage(damage, radius)** -- generic A_Explode, w/customizable damage and radius (helll yeah) -- Weapon pointers: - - **A_WeaponProjectile(type, angle)** -- generic weapon projectile attack; does not consume ammo - - **A_WeaponBulletAttack(damage, spread)** -- generic weapon bullet attack; does not consume ammo; same `spread` behavior as A_MonsterBulletAttack - - **A_WeaponSound(sound, fullvol)** -- same as A_PlaySound, but for weapons - - **A_WeaponJump(state, chance)** -- same as A_RandomJump, but for weapons - - **A_ConsumeAmmo(amount)** -- subtract `amount` units of ammo. if `amount` is zero, use the weapon slot's `ammopershot`. will not reduce ammo below zero. - - **A_CheckAmmo(state, amount)** -- jumps to `state` if ammo is below `amount`; if `amount` is zero, use the weapon slot's `ammopershot` value instead - - **A_RefireTo(state, noammocheck)** -- jumps to `state` if trigger is still held down; will also check ammo unless `noammocheck` is set - - **A_GunFlashTo(state, nothirdperson)** -- sets the weapon's flash state to `state`; also sets the player's 3rd-person sprite to the player actor's firing frame unless `nothirdperson` is set +- Arg fields are listed in order in the docs below, e.g. for `A_SpawnObject`, `type` is Args1, `angle` is Args2, etc. +- Although all args are integers internally, there are effectively the following types of args: + - `int`: An integer. 'Nuff said. + - `uint`: An unsigned integer. Must be greater than or equal to zero. + - `fixed` A [fixed-point](https://doomwiki.org/wiki/Fixed_point) number. + - For user-friendliness, a suggested convention for MBF21-supporting DEHACKED tools is to convert numbers with decimal points to their fixed-point representation when saving the patch (e.g. "1.0" gets saved as "65536"), so this doesn't get super-ugly on the user side of life. + +##### Actor pointers + +- **A_SpawnObject(type, angle, x_ofs, y_ofs, z_ofs, x_vel, y_vel, z_vel)** + - Generic actor spawn function. + - Args: + - `type (uint)`: Type (dehnum) of actor to spawn + - `angle (fixed)`: Angle (degrees), relative to calling actor's angle + - `x_ofs (fixed)`: X (forward/back) spawn position offset + - `y_ofs (fixed)`: Y (left/right) spawn position offset + - `z_ofs (fixed)`: Z (up/down) spawn position offset + - `x_vel (fixed)`: X (forward/back) velocity + - `y_vel (fixed)`: Y (left/right) velocity + - `z_vel (fixed)`: Z (up/down) velocity + - Notes: + - If the spawnee is a missile, the `tracer` and `target` pointers are set as follows: + - If spawner is also a missile, `tracer` and `target` are copied to spawnee + - Otherwise, spawnee's `target` is set to the spawner and `tracer` is set to the spawner's `target`. + +- **A_MonsterProjectile(type, angle, pitch, hoffset, voffset)** + - Generic monster projectile attack. + - Args: + - `type (uint)`: Type (dehnum) of actor to spawn + - `angle (fixed)`: Angle (degrees), relative to calling actor's angle + - `pitch (fixed)`: Pitch (degrees), relative to calling actor's pitch + - `hoffset (fixed)`: Horizontal spawn offset, relative to calling actor's angle + - `voffset (fixed)`: Vertical spawn offset, relative to actor's default projectile fire height + - Notes: + - The `pitch` arg uses the same approximated pitch calculation that Doom's monster aim / autoaim uses. Refer to the implementation for specifics. + - The spawned projectile's `tracer` pointer is always set to the spawner's `target`, for generic seeker missile support. + +- **A_MonsterBulletAttack(hspread, vspread, numbullets, damagebase, damagedice)** + - Generic monster bullet attack. + - Args: + - `hspread (fixed)`: Horizontal spread (degrees, in fixed point) + - `vspread (fixed)`: Vertical spread (degrees, in fixed point) + - `numbullets (int)`: Number of bullets to fire; if not set, defaults to 1 + - `damagebase (int)`: Base damage of attack; if not set, defaults to 3 + - `damagedice (int)`: Attack damage random multiplier; if not set, defaults to 5 + - Notes: + - Damage formula is: `damage = (damagebase * random(1, damagedice))` + - Damage arg defaults are identical to Doom's usual monster bullet attack values. + - Entering a negative value for `numbullets`, `damagebase`, and `damagedice` is undefined behavior (for now). + +- **A_RadiusDamage(damage, radius)** + - Generic A_Explode (hell yeah). + - Args: + - `damage (int)`: Max explosion damge + - `radius (int)`: Explosion radius + +##### Weapon pointers + +- **A_WeaponProjectile(type, angle)** + - Generic weapon projectile attack. + - Args: + - `type (uint)`: Type (dehnum) of actor to spawn + - `angle (fixed)`: Angle (degrees), relative to player's angle + - `pitch (fixed)`: Pitch (degrees), relative to player's pitch + - `hoffset (fixed)`: Horizontal spawn offset, relative to player's angle + - `voffset (fixed)`: Vertical spawn offset, relative to player's default projectile fire height + - Notes: + - Unlike native Doom attack codepointers, this function will not consume ammo, trigger the Flash state, or play a sound. + - The `pitch` arg uses the same approximated pitch calculation that Doom's monster aim / autoaim uses. Refer to the implementation for specifics. + +- **A_WeaponBulletAttack(damage, spread)** + - Generic weapon bullet attack. + - Args: + - `hspread (fixed)`: Horizontal spread (degrees, in fixed point) + - `vspread (fixed)`: Vertical spread (degrees, in fixed point) + - `numbullets (int)`: Number of bullets to fire; if not set, defaults to 1 + - `damagebase (int)`: Base damage of attack; if not set, defaults to 5 + - `damagedice (int)`: Attack damage random multiplier; if not set, defaults to 3 + - Notes: + - Unlike native Doom attack codepointers, this function will not consume ammo, trigger the Flash state, or play a sound. + - Damage formula is: `damage = (damagebase * random(1, damagedice))` + - Damage arg defaults are identical to Doom's usual monster bullet attack values. + - Note that these defaults are different for weapons and monsters (5d3 vs 3d5) -- yup, Doom did it this way. :P + +- **A_WeaponSound(sound, fullvol)** + - Generic playsound for weapons. + - Args: + - `sound (uint)`: DEH Index of sound to play. + - `fullvol (int)`: If nonzero, play this sound at full volume across the entire map. + +- **A_WeaponJump(state, chance)** + - Random state jump for weapons. + - Args: + - `state (uint)`: State index to jump to. + - `chance (int)`: Chance out of 256 to perform the jump. 0 never jumps, 256 always jumps. + +- **A_ConsumeAmmo(amount)** + - Subtracts ammo from the currently-selected weapon's ammo pool. + - Args: + - `amount (int)`: Amount of ammo to subtract. If zero, will default to the current weapon's `ammopershot` value. + - Notes: + - This function will not reduce ammo below zero. + - This function will no-op if the current weapon uses the `am_noammo` ("None"/"Infinite") ammotype. + +- **A_CheckAmmo(state, amount)** + - Jumps to `state` if ammo is below `amount`. + - Args: + - `state (uint)`: State index to jump to. + - `amount (int)`: Amount of ammo to check. If zero, will default to the current weapon's `ammopershot` value. + - Notes: + - The jump will only occur if ammo is BELOW the given value -- e.g. `A_CheckAmmo(420, 695)` will jump to state 420 if ammo is 68 or lower. + - This function will no-op if the current weapon uses the `am_noammo` ("None"/"Infinite") ammotype. + +- **A_RefireTo(state, noammocheck)** + - Jumps to `state` if the fire button is currently being pressed and the weapon has enough ammo to fire. + - Args: + - `state (uint)`: State index to jump to. + - `noammocheck (int)`: If nonzero, skip the ammo check. + +- **A_GunFlashTo(state, nothirdperson)** + - Generic weapon muzzle flash. + - Args: + - `state (uint)`: State index to set the flash psprite to. + - `nothirdperson (int)`: If nonzero, do not change the 3rd-person player sprite to the player muzzleflash state. ## Miscellaneous From a84c1b3953965b3a29df59f9fa8bba495d30ed02 Mon Sep 17 00:00:00 2001 From: Xaser Acheron Date: Fri, 30 Apr 2021 22:19:50 -0500 Subject: [PATCH 08/10] whoops, missed a spot in the docs --- prboom2/src/mbf21.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/prboom2/src/mbf21.md b/prboom2/src/mbf21.md index cdda67591..8b5ba6481 100644 --- a/prboom2/src/mbf21.md +++ b/prboom2/src/mbf21.md @@ -269,7 +269,7 @@ MBF21 defaults: ##### Weapon pointers -- **A_WeaponProjectile(type, angle)** +- **A_WeaponProjectile(type, angle, pitch, hoffset, voffset)** - Generic weapon projectile attack. - Args: - `type (uint)`: Type (dehnum) of actor to spawn @@ -281,7 +281,7 @@ MBF21 defaults: - Unlike native Doom attack codepointers, this function will not consume ammo, trigger the Flash state, or play a sound. - The `pitch` arg uses the same approximated pitch calculation that Doom's monster aim / autoaim uses. Refer to the implementation for specifics. -- **A_WeaponBulletAttack(damage, spread)** +- **A_WeaponBulletAttack(hspread, vspread, numbullets, damagebase, damagedice)** - Generic weapon bullet attack. - Args: - `hspread (fixed)`: Horizontal spread (degrees, in fixed point) From 754b4d2ec3d1cb9a27775e27d09791d12d1167de Mon Sep 17 00:00:00 2001 From: Xaser Acheron Date: Fri, 30 Apr 2021 22:21:46 -0500 Subject: [PATCH 09/10] add latest mbf21 codepointer PR to mbf21.md --- prboom2/src/mbf21.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prboom2/src/mbf21.md b/prboom2/src/mbf21.md index 8b5ba6481..427c4f3df 100644 --- a/prboom2/src/mbf21.md +++ b/prboom2/src/mbf21.md @@ -209,7 +209,7 @@ MBF21 defaults: - For future-proofing, if more nonzero args are defined on a state than its action pointer expects (e.g. defining Args3 on a state that uses A_WeaponSound), an error will be thrown on startup. #### New DEHACKED Codepointers -- [PR](https://github.com/kraflab/dsda-doom/pull/20) +- [PR](https://github.com/kraflab/dsda-doom/pull/20), [PR](https://github.com/kraflab/dsda-doom/pull/38) - All new MBF21 pointers use the new "Args" fields for params, rather than misc1/misc2 fields - Arg fields are listed in order in the docs below, e.g. for `A_SpawnObject`, `type` is Args1, `angle` is Args2, etc. - Although all args are integers internally, there are effectively the following types of args: From 214355c16b75ada7bbb6a28c94b1e90599b57142 Mon Sep 17 00:00:00 2001 From: kraflab Date: Sat, 1 May 2021 14:20:36 +0200 Subject: [PATCH 10/10] Apply arg defaults in one pass --- prboom2/src/d_deh.c | 30 ++++++++++++++++++------------ prboom2/src/doomtype.h | 3 --- prboom2/src/p_enemy.c | 36 ++++++++++++++++++------------------ prboom2/src/p_pspr.c | 20 ++++++++++---------- 4 files changed, 46 insertions(+), 43 deletions(-) diff --git a/prboom2/src/d_deh.c b/prboom2/src/d_deh.c index de2a6aa6c..adec06bee 100644 --- a/prboom2/src/d_deh.c +++ b/prboom2/src/d_deh.c @@ -1361,6 +1361,7 @@ typedef struct { const char *lookup; // mnemonic lookup string to be specified in BEX // CPhipps - const* int argcount; // [XA] number of mbf21 args this action uses, if any + long default_args[MAXSTATEARGS]; // default values for mbf21 args } deh_bexptr; static const deh_bexptr deh_bexptrs[] = // CPhipps - static const @@ -1457,10 +1458,10 @@ static const deh_bexptr deh_bexptrs[] = // CPhipps - static const // [XA] New mbf21 codepointers {A_SpawnObject, "A_SpawnObject", 8}, {A_MonsterProjectile, "A_MonsterProjectile", 5}, - {A_MonsterBulletAttack, "A_MonsterBulletAttack", 5}, + {A_MonsterBulletAttack, "A_MonsterBulletAttack", 5, {0, 0, 1, 3, 5}}, {A_RadiusDamage, "A_RadiusDamage", 2}, {A_WeaponProjectile, "A_WeaponProjectile", 5}, - {A_WeaponBulletAttack, "A_WeaponBulletAttack", 5}, + {A_WeaponBulletAttack, "A_WeaponBulletAttack", 5, {0, 0, 1, 5, 3}}, {A_WeaponSound, "A_WeaponSound", 2}, {A_WeaponJump, "A_WeaponJump", 2}, {A_ConsumeAmmo, "A_ConsumeAmmo", 1}, @@ -3520,13 +3521,15 @@ dboolean deh_GetData(char *s, char *k, uint_64_t *l, char **strval, FILE *fpout) return(okrc); } +static deh_bexptr null_bexptr = { NULL, "(NULL)" }; + // // CheckDehConsistency // void CheckDehConsistency(void) { - int i, j, maxargs; - const char *bexptr_name; + int i, j; + const deh_bexptr *bexptr_match; // sanity-check bfgcells and bfg ammopershot if ( @@ -3536,24 +3539,27 @@ void CheckDehConsistency(void) ) I_Error("Mismatch between bfgcells and bfg ammo per shot modifications! Check your dehacked."); - // ensure states don't use more mbf21 args than their - // action pointer expects, for future-proofing's sake for (i = 0; i < num_states; i++) { - bexptr_name = "(NULL)"; - maxargs = 0; + bexptr_match = &null_bexptr; for (j = 0; deh_bexptrs[j].cptr != NULL; ++j) if (states[i].action == deh_bexptrs[j].cptr) { - bexptr_name = deh_bexptrs[j].lookup; - maxargs = deh_bexptrs[j].argcount; + bexptr_match = &deh_bexptrs[j]; break; } - for (j = MAXSTATEARGS - 1; j >= maxargs; j--) + // ensure states don't use more mbf21 args than their + // action pointer expects, for future-proofing's sake + for (j = MAXSTATEARGS - 1; j >= bexptr_match->argcount; j--) if (states[i].args[j] != 0) I_Error("Action %s on state %d expects no more than %d nonzero args (%d found). Check your dehacked.", - bexptr_name, i, maxargs, j+1); + bexptr_match->lookup, i, bexptr_match->argcount, j+1); + + // replace unset fields with default values + for (; j >= 0; j--) + if (states[i].args[j] == 0) + states[i].args[j] = bexptr_match->default_args[j]; } } diff --git a/prboom2/src/doomtype.h b/prboom2/src/doomtype.h index a4e4066c2..b4f0b60b4 100644 --- a/prboom2/src/doomtype.h +++ b/prboom2/src/doomtype.h @@ -175,7 +175,4 @@ enum patch_translation_e { VPT_NOOFFSET = 1024, }; -// [XA] Common macro for defining an arg's default value if zero -#define ARG_DEFAULT(x, y) ((x) == 0 ? (y) : (x)) - #endif diff --git a/prboom2/src/p_enemy.c b/prboom2/src/p_enemy.c index 95c28a195..447c2a13d 100644 --- a/prboom2/src/p_enemy.c +++ b/prboom2/src/p_enemy.c @@ -3009,14 +3009,14 @@ void A_SpawnObject(mobj_t *actor) if (!mbf21 || !actor->state->args[0]) return; - type = ARG_DEFAULT(actor->state->args[0], 0) - 1; - angle = ARG_DEFAULT(actor->state->args[1], 0); - ofs_x = ARG_DEFAULT(actor->state->args[2], 0); - ofs_y = ARG_DEFAULT(actor->state->args[3], 0); - ofs_z = ARG_DEFAULT(actor->state->args[4], 0); - vel_x = ARG_DEFAULT(actor->state->args[5], 0); - vel_y = ARG_DEFAULT(actor->state->args[6], 0); - vel_z = ARG_DEFAULT(actor->state->args[7], 0); + type = actor->state->args[0] - 1; + angle = actor->state->args[1]; + ofs_x = actor->state->args[2]; + ofs_y = actor->state->args[3]; + ofs_z = actor->state->args[4]; + vel_x = actor->state->args[5]; + vel_y = actor->state->args[6]; + vel_z = actor->state->args[7]; // calculate position offsets an = actor->angle + (unsigned int)(((int_64_t)angle << 16) / 360); @@ -3076,11 +3076,11 @@ void A_MonsterProjectile(mobj_t *actor) if (!mbf21 || !actor->target || !actor->state->args[0]) return; - type = ARG_DEFAULT(actor->state->args[0], 0) - 1; - angle = ARG_DEFAULT(actor->state->args[1], 0); - pitch = ARG_DEFAULT(actor->state->args[2], 0); - spawnofs_xy = ARG_DEFAULT(actor->state->args[3], 0); - spawnofs_z = ARG_DEFAULT(actor->state->args[4], 0); + type = actor->state->args[0] - 1; + angle = actor->state->args[1]; + pitch = actor->state->args[2]; + spawnofs_xy = actor->state->args[3]; + spawnofs_z = actor->state->args[4]; A_FaceTarget(actor); mo = P_SpawnMissile(actor, actor->target, type); @@ -3125,11 +3125,11 @@ void A_MonsterBulletAttack(mobj_t *actor) if (!mbf21 || !actor->target) return; - hspread = ARG_DEFAULT(actor->state->args[0], 0); - vspread = ARG_DEFAULT(actor->state->args[1], 0); - numbullets = ARG_DEFAULT(actor->state->args[2], 1); - damagebase = ARG_DEFAULT(actor->state->args[3], 3); - damagemod = ARG_DEFAULT(actor->state->args[4], 5); + hspread = actor->state->args[0]; + vspread = actor->state->args[1]; + numbullets = actor->state->args[2]; + damagebase = actor->state->args[3]; + damagemod = actor->state->args[4]; A_FaceTarget(actor); S_StartSound(actor, actor->info->attacksound); diff --git a/prboom2/src/p_pspr.c b/prboom2/src/p_pspr.c index 254ec1551..5a58fe6ee 100644 --- a/prboom2/src/p_pspr.c +++ b/prboom2/src/p_pspr.c @@ -1156,11 +1156,11 @@ void A_WeaponProjectile(player_t *player, pspdef_t *psp) if (!mbf21 || !psp->state || !psp->state->args[0]) return; - type = ARG_DEFAULT(psp->state->args[0], 0) - 1; - angle = ARG_DEFAULT(psp->state->args[1], 0); - pitch = ARG_DEFAULT(psp->state->args[2], 0); - spawnofs_xy = ARG_DEFAULT(psp->state->args[3], 0); - spawnofs_z = ARG_DEFAULT(psp->state->args[4], 0); + type = psp->state->args[0] - 1; + angle = psp->state->args[1]; + pitch = psp->state->args[2]; + spawnofs_xy = psp->state->args[3]; + spawnofs_z = psp->state->args[4]; mo = P_SpawnPlayerMissile(player->mo, type); if (!mo) @@ -1202,11 +1202,11 @@ void A_WeaponBulletAttack(player_t *player, pspdef_t *psp) if (!mbf21 || !psp->state) return; - hspread = ARG_DEFAULT(psp->state->args[0], 0); - vspread = ARG_DEFAULT(psp->state->args[1], 0); - numbullets = ARG_DEFAULT(psp->state->args[2], 1); - damagebase = ARG_DEFAULT(psp->state->args[3], 5); - damagemod = ARG_DEFAULT(psp->state->args[4], 3); + hspread = psp->state->args[0]; + vspread = psp->state->args[1]; + numbullets = psp->state->args[2]; + damagebase = psp->state->args[3]; + damagemod = psp->state->args[4]; P_BulletSlope(player->mo);