From 98cdcf85933c2e3f0a738f3c9d6ecc4ce25ac617 Mon Sep 17 00:00:00 2001 From: NepDisk <16447892+NepDisk@users.noreply.github.com> Date: Mon, 29 Jul 2024 02:34:56 -0400 Subject: [PATCH] Reapply "Replace shitty item box pop with flying debris and dust clouds" This reverts commit e4f8b0119d08fc99d4cdef0b0867877d43e1e863. --- src/deh_tables.c | 9 ++ src/info.c | 61 +++++++++++ src/info.h | 11 ++ src/k_collide.c | 4 +- src/k_objects.h | 6 ++ src/objects/Sourcefile | 1 + src/objects/item-debris.c | 207 ++++++++++++++++++++++++++++++++++++++ src/p_enemy.c | 131 +++++++++++++++--------- src/p_mobj.c | 17 ++++ 9 files changed, 396 insertions(+), 51 deletions(-) create mode 100644 src/objects/item-debris.c diff --git a/src/deh_tables.c b/src/deh_tables.c index 47a6ca515..12911c27a 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -337,6 +337,7 @@ actionpointer_t actionpointers[] = {{A_ReaperThinker}, "A_REAPERTHINKER"}, {{A_FlameShieldPaper}, "A_FLAMESHIELDPAPER"}, {{A_InvincSparkleRotate}, "A_INVINCSPARKLEROTATE"}, + {{A_SpawnItemDebrisCloud}, "A_SPAWNITEMDEBRISCLOUD"}, {{NULL}, "NONE"}, @@ -3277,6 +3278,12 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_RANDOMITEMPOP4", //} + "S_ITEM_DEBRIS", + "S_ITEM_DEBRIS_CLOUD_SPAWNER_INIT", + "S_ITEM_DEBRIS_CLOUD_SPAWNER1", + "S_ITEM_DEBRIS_CLOUD_SPAWNER2", + "S_ITEM_DEBRIS_CLOUD_SPAWNER3", + "S_ITEMICON", // Item capsules @@ -5287,6 +5294,8 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_BRAKEDRIFT", "MT_BRAKEDUST", "MT_DRIFTDUST", + "MT_ITEM_DEBRIS", + "MT_ITEM_DEBRIS_CLOUD_SPAWNER", "MT_DRIFTELECTRICITY", "MT_DRIFTELECTRICSPARK", "MT_JANKSPARK", diff --git a/src/info.c b/src/info.c index 983ad50bc..559202d75 100644 --- a/src/info.c +++ b/src/info.c @@ -530,6 +530,7 @@ char sprnames[NUMSPRITES + 1][5] = "RNDM", // Random Item Box "SBOX", // Sphere Box (for Battle) "RPOP", // Random Item Box Pop + "ITRI", // Item Box Debris "SGNS", // Signpost sparkle "FAST", // Speed boost trail "DSHR", // Speed boost dust release @@ -3864,6 +3865,12 @@ state_t states[NUMSTATES] = {SPR_RPOP, FF_FULLBRIGHT|2, 5, {NULL}, 0, 0, S_RANDOMITEMPOP4}, // S_RANDOMITEMPOP3 {SPR_RPOP, FF_FULLBRIGHT|3, 5, {NULL}, 0, 0, S_NULL}, // S_RANDOMITEMPOP4 + {SPR_ITRI, FF_FULLBRIGHT, -1, {NULL}, 19, 1, S_NULL}, // S_ITEM_DEBRIS + {SPR_NULL, 0, 1, {NULL}, 0, 0, S_ITEM_DEBRIS_CLOUD_SPAWNER1}, // S_ITEM_DEBRIS_CLOUD_SPAWNER_INIT + {SPR_NULL, 0, 1, {A_Repeat}, 4, S_ITEM_DEBRIS_CLOUD_SPAWNER2, S_NULL}, // S_ITEM_DEBRIS_CLOUD_SPAWNER1 + {SPR_NULL, 4, 2, {A_SpawnItemDebrisCloud}, 1, 10, S_ITEM_DEBRIS_CLOUD_SPAWNER3}, // S_ITEM_DEBRIS_CLOUD_SPAWNER2 + {SPR_NULL, 4, 5, {A_SpawnItemDebrisCloud}, 0, 2, S_ITEM_DEBRIS_CLOUD_SPAWNER1}, // S_ITEM_DEBRIS_CLOUD_SPAWNER3 + {SPR_NULL, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMICON {SPR_ICAP, FF_ADD|0, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMCAPSULE @@ -23091,6 +23098,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_ITEM_DEBRIS + -1, // doomednum + S_ITEM_DEBRIS, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 32*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + + { // MT_ITEM_DEBRIS_CLOUD_SPAWNER + -1, // doomednum + S_ITEM_DEBRIS_CLOUD_SPAWNER_INIT, // spawnstate + 1, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 32*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // display offset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOSECTOR|MF_NOBLOCKMAP, // flags + S_NULL // raisestate + }, + { // MT_DRIFTELECTRICITY -1, // doomednum S_DRIFTELECTRICITY, // spawnstate diff --git a/src/info.h b/src/info.h index ab1867973..2f0bc535f 100644 --- a/src/info.h +++ b/src/info.h @@ -290,6 +290,7 @@ enum actionnum A_REAPERTHINKER, A_FLAMESHIELDPAPER, A_INVINCSPARKLEROTATE, + A_SPAWNITEMDEBRISCLOUD, NUMACTIONS }; @@ -563,6 +564,7 @@ void A_ReaperThinker(); void A_MementosTPParticles(); void A_FlameShieldPaper(); void A_InvincSparkleRotate(); +void A_SpawnItemDebrisCloud(); extern boolean actionsoverridden[NUMACTIONS]; @@ -1076,6 +1078,7 @@ typedef enum sprite SPR_RNDM, // Random Item Box SPR_SBOX, // Sphere Box (for Battle) SPR_RPOP, // Random Item Box Pop + SPR_ITRI, // Item Box Debris SPR_SGNS, // Signpost sparkle SPR_FAST, // Speed boost trail SPR_DSHR, // Speed boost dust release @@ -4267,6 +4270,12 @@ typedef enum state S_RANDOMITEMPOP4, //} + S_ITEM_DEBRIS, + S_ITEM_DEBRIS_CLOUD_SPAWNER_INIT, + S_ITEM_DEBRIS_CLOUD_SPAWNER1, + S_ITEM_DEBRIS_CLOUD_SPAWNER2, + S_ITEM_DEBRIS_CLOUD_SPAWNER3, + S_ITEMICON, // Item capsules @@ -6313,6 +6322,8 @@ typedef enum mobj_type MT_BRAKEDRIFT, MT_BRAKEDUST, MT_DRIFTDUST, + MT_ITEM_DEBRIS, + MT_ITEM_DEBRIS_CLOUD_SPAWNER, MT_DRIFTELECTRICITY, MT_DRIFTELECTRICSPARK, MT_JANKSPARK, diff --git a/src/k_collide.c b/src/k_collide.c index 128364cfc..0658edb5f 100644 --- a/src/k_collide.c +++ b/src/k_collide.c @@ -11,6 +11,7 @@ #include "hu_stuff.h" // Sink snipe print #include "doomdef.h" // Sink snipe print #include "g_game.h" // Sink snipe print +#include "k_objects.h" angle_t K_GetCollideAngle(mobj_t *t1, mobj_t *t2) { @@ -265,8 +266,7 @@ boolean K_EggItemCollide(mobj_t *t1, mobj_t *t2) } else { - mobj_t *poof = P_SpawnMobj(t1->x, t1->y, t1->z, MT_EXPLODE); - S_StartSound(poof, t1->info->deathsound); + Obj_SpawnItemDebrisEffects(t1, t2); #if 0 // Eggbox snipe! diff --git a/src/k_objects.h b/src/k_objects.h index 45f9df78c..e32801942 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -8,4 +8,10 @@ void Obj_HyudoroThink(mobj_t *actor); void Obj_HyudoroCenterThink(mobj_t *actor); void Obj_HyudoroCollide(mobj_t *special, mobj_t *toucher); +/* Item Debris */ +fixed_t Obj_GetItemDebrisSpeed(mobj_t *collector, fixed_t min_speed); +void Obj_SpawnItemDebrisEffects(mobj_t *collectible, mobj_t *collector); +void Obj_ItemDebrisThink(mobj_t *debris); +fixed_t Obj_ItemDebrisBounce(mobj_t *debris, fixed_t momz); + #endif/*k_objects_H*/ diff --git a/src/objects/Sourcefile b/src/objects/Sourcefile index f7e4f2491..66480688f 100644 --- a/src/objects/Sourcefile +++ b/src/objects/Sourcefile @@ -1 +1,2 @@ hyudoro.c +item-debris.c diff --git a/src/objects/item-debris.c b/src/objects/item-debris.c new file mode 100644 index 000000000..dcb1950d7 --- /dev/null +++ b/src/objects/item-debris.c @@ -0,0 +1,207 @@ +#include "../doomdef.h" +#include "../d_player.h" +#include "../m_random.h" +#include "../k_kart.h" +#include "../k_objects.h" +#include "../p_local.h" +#include "../s_sound.h" + +// TODO: general function +static fixed_t K_GetPlayerSpeedRatio(player_t *player) +{ + return FixedDiv(player->speed, + K_GetKartSpeed(player, false, false)); +} + +#define debris_type(o) ((o)->extravalue1) +#define debris_bouncesleft(o) ((o)->threshold) + +enum { + DEBRIS_ALPHA, + DEBRIS_BETA, + + NUM_DEBRIS_TYPES +}; + +struct debris_config { + mobj_t * origin; + angle_t angle; + fixed_t speed; + fixed_t scale; + UINT8 type; +}; + +static fixed_t +get_speed_ratio (mobj_t *thing) +{ + return thing->player ? + K_GetPlayerSpeedRatio(thing->player) : FRACUNIT; +} + +static void +spawn_debris +( const struct debris_config * config, + INT32 angle) +{ + const fixed_t height_table[NUM_DEBRIS_TYPES] = { + 50*FRACUNIT, + 35*FRACUNIT, + }; + + mobj_t *debris = P_SpawnMobjFromMobj( + config->origin, 0, 0, 0, MT_ITEM_DEBRIS); + + const state_t *st = debris->state; + + debris_type(debris) = config->type; + debris_bouncesleft(debris) = 1; + + // Start at a random frame of animation + debris->frame = (debris->frame & ~(FF_FRAMEMASK)) | + P_RandomRange((st->frame & FF_FRAMEMASK), st->var1); + + P_InstaThrust(debris, + config->angle + angle, + config->speed); + + P_SetObjectMomZ(debris, + FixedMul(config->scale, + height_table[config->type]), + false); + + debris->destscale = + FixedMul(config->scale, 3 * debris->scale); + P_SetScale(debris, debris->destscale); + + // Pass down color to dust particles + debris->color = config->origin->color; +} + +static void +spawn_cloud +( mobj_t * collectible, + mobj_t * collector) +{ + mobj_t *spawner = P_SpawnMobjFromMobj(collectible, + 0, 0, 0, MT_ITEM_DEBRIS_CLOUD_SPAWNER); + + P_SetTarget(&spawner->target, collector); + + S_StartSound(spawner, sfx_kc2e); + S_StartSound(spawner, sfx_s1c9); +} + +static void +rotate3d (mobj_t *debris) +{ + const UINT8 steps = 30; + + debris->rollangle = + M_RandomKey(steps) * (ANGLE_MAX / steps); +} + +fixed_t +Obj_GetItemDebrisSpeed +( mobj_t * collector, + fixed_t min_speed) +{ + const fixed_t base_speed = FixedMul( + 75 * mapobjectscale, + get_speed_ratio(collector)); + + return max(base_speed, min_speed); +} + +void +Obj_SpawnItemDebrisEffects +( mobj_t * collectible, + mobj_t * collector) +{ + const fixed_t min_speed = 80 * collectible->scale; + + const fixed_t speed = + Obj_GetItemDebrisSpeed(collector, min_speed); + + struct debris_config config = { + .origin = collectible, + .angle = K_MomentumAngle(collector), + .speed = speed, + .scale = FixedDiv(speed, min_speed), + }; + + config.type = DEBRIS_ALPHA; + + spawn_debris(&config, ANGLE_11hh); + spawn_debris(&config, -(ANGLE_11hh)); + + config.type = DEBRIS_BETA; + + spawn_debris(&config, 3*ANGLE_22h/2); + spawn_debris(&config, 3*ANGLE_22h/4); + spawn_debris(&config, 0); + spawn_debris(&config, -(3*ANGLE_22h/4)); + spawn_debris(&config, -(3*ANGLE_22h/2)); + + spawn_cloud(collectible, collector); +} + +void +Obj_ItemDebrisThink (mobj_t *debris) +{ + const UINT8 frame = (debris->frame & FF_FRAMEMASK); + + if (debris->momz == 0) + { + P_KillMobj(debris, NULL, NULL, DMG_NORMAL); + return; + } + + rotate3d(debris); + + if (frame % 3 == 1) + { + mobj_t *ghost = P_SpawnGhostMobj(debris); + + ghost->fuse = 3; + } + + if (debris_type(debris) == DEBRIS_ALPHA) + { + mobj_t *dust = P_SpawnMobjFromMobj( + debris, 0, 0, 0, MT_SPINDASHDUST); + + P_SetScale(dust, (dust->destscale /= 3)); + + dust->color = debris->color; + dust->colorized = true; + + dust->momx = debris->momx / 4; + dust->momy = debris->momy / 4; + dust->momz = debris->momz / 4; + } +} + +fixed_t +Obj_ItemDebrisBounce +( mobj_t * debris, + fixed_t momz) +{ + if (debris_bouncesleft(debris) <= 0) + { + P_KillMobj(debris, NULL, NULL, DMG_NORMAL); + return 0; + } + + momz = -(momz); + + if (debris_type(debris) == DEBRIS_BETA) + { + momz /= 2; + } + + debris_bouncesleft(debris)--; + + S_StartSound(debris, sfx_cdfm47); + + return momz; +} diff --git a/src/p_enemy.c b/src/p_enemy.c index 60d98effb..263ed763d 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -32,6 +32,7 @@ #include "k_battle.h" #include "k_respawn.h" #include "k_collide.h" +#include "k_objects.h" #ifdef HW3SOUND #include "hardware/hw3sound.h" @@ -326,6 +327,7 @@ void A_ReaperThinker(mobj_t *actor); void A_MementosTPParticles(mobj_t *actor); void A_FlameShieldPaper(mobj_t *actor); void A_InvincSparkleRotate(mobj_t *actor); +void A_SpawnItemDebrisCloud(mobj_t *actor); //for p_enemy.c @@ -13176,9 +13178,6 @@ void A_ItemPop(mobj_t *actor) { INT32 locvar1 = var1; - mobj_t *remains; - mobjtype_t explode; - if (LUA_CallAction(A_ITEMPOP, actor)) return; @@ -13201,58 +13200,13 @@ void A_ItemPop(mobj_t *actor) actor->color = SKINCOLOR_GREY; actor->colorized = true; - // item explosion - explode = mobjinfo[actor->info->damage].mass; - remains = P_SpawnMobj(actor->x, actor->y, - ((actor->eflags & MFE_VERTICALFLIP) ? (actor->z + 3*(actor->height/4) - FixedMul(mobjinfo[explode].height, actor->scale)) : (actor->z + actor->height/4)), explode); - if (actor->eflags & MFE_VERTICALFLIP) - { - remains->eflags |= MFE_VERTICALFLIP; - remains->flags2 |= MF2_OBJECTFLIP; - } - remains->destscale = actor->destscale; - P_SetScale(remains, actor->scale); - - remains = P_SpawnMobj(actor->x, actor->y, actor->z, actor->info->damage); - remains->type = actor->type; // Transfer type information - P_UnsetThingPosition(remains); - if (sector_list) - { - P_DelSeclist(sector_list); - sector_list = NULL; - } - P_SetThingPosition(remains); - remains->destscale = actor->destscale; - P_SetScale(remains, actor->scale); - remains->flags = actor->flags; // Transfer flags - remains->flags2 = actor->flags2; // Transfer flags2 - remains->fuse = actor->fuse; // Transfer respawn timer - remains->cvmem = leveltime; - remains->threshold = actor->threshold; - if (remains->threshold != 69 && remains->threshold != 70) - { - remains->threshold = 68; - } - // To insure this information doesn't have to be rediscovered every time you look at this function... - // A threshold of 0 is for a "living", ordinary random item. - // 68 means regular popped random item debris. - // 69 used to mean old Karma Item behaviour (now you can replicate this with MF2_DONTRESPAWN). - // 70 is a powered up Overtime item. - remains->skin = NULL; - remains->spawnpoint = actor->spawnpoint; - - P_SetTarget(&tmthing, remains); - - if (actor->info->deathsound) - S_StartSound(remains, actor->info->deathsound); + Obj_SpawnItemDebrisEffects(actor, actor->target); if (locvar1 == 1) P_GivePlayerSpheres(actor->target->player, actor->extravalue1); else if (locvar1 == 0) actor->target->player->itemroulette = 1; - remains->flags2 &= ~MF2_AMBUSH; - // Here at mapload in battle? if ((gametyperules & GTR_BUMPERS) && (actor->flags2 & MF2_BOSSNOTRAP)) { @@ -14545,3 +14499,82 @@ void A_InvincSparkleRotate(mobj_t *actor) ghost->fuse = 4; } } + +// Function: A_SpawnItemDebrisCloud +// +// Description: Spawns a particle effect relative to the location of the actor +// +// var1 = If 1, scale size and momentum by extravalue2 / frame. +// var2 = Number of particles to spawn. +// +void +A_SpawnItemDebrisCloud (mobj_t *actor) +{ + INT32 locvar1 = var1; + INT32 locvar2 = var2; + + const fixed_t min_speed = 90 * actor->scale; + const INT16 spacing = (actor->radius / 2) / actor->scale; + + fixed_t fade = FRACUNIT; + fixed_t scale_fade = FRACUNIT; + + mobj_t *target = actor->target; + + fixed_t speed; + fixed_t scale; + + INT32 i; + + if (target == NULL) + { + return; + } + + if (locvar1) + { + const UINT8 frame = (actor->frame & FF_FRAMEMASK); + fixed_t frac; + + if (frame == 0) + { + return; // div by zero + } + + // extravalue2 from A_Repeat + frac = fade / frame; + fade = actor->extravalue2 * frac; + scale_fade = fade + frac; + } + + speed = Obj_GetItemDebrisSpeed(target, min_speed); + scale = 2 * FixedMul(FixedDiv(speed, min_speed), scale_fade); + + // Most of this code is from p_inter.c, MT_ITEMCAPSULE + + // dust effects + for (i = 0; i < locvar2; i++) + { + mobj_t *puff = P_SpawnMobjFromMobj( + target, + P_RandomRange(-spacing, spacing) * FRACUNIT, + P_RandomRange(-spacing, spacing) * FRACUNIT, + P_RandomRange(0, 4 * spacing) * FRACUNIT, + MT_SPINDASHDUST + ); + + puff->color = target->color; + puff->colorized = true; + + puff->destscale = FixedMul(puff->destscale, scale); + P_SetScale(puff, puff->destscale); + + puff->momz = puff->scale * P_MobjFlip(puff); + + P_Thrust(puff, R_PointToAngle2(target->x, target->y, puff->x, puff->y), 3 * puff->scale); + + puff->momx += FixedMul(target->momx, fade); + puff->momy += FixedMul(target->momy, fade); + puff->momz += FixedMul(target->momz, fade); + } +} diff --git a/src/p_mobj.c b/src/p_mobj.c index e695bdbca..471440ac9 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1209,6 +1209,9 @@ fixed_t P_GetMobjGravity(mobj_t *mo) case MT_KARMAFIREWORK: gravityadd /= 3; break; + case MT_ITEM_DEBRIS: + gravityadd *= 6; + break; default: break; } @@ -2339,6 +2342,15 @@ boolean P_ZMovement(mobj_t *mo) mom.z = P_MobjFlip(mo)*FixedMul(5*FRACUNIT, mo->scale); else if (mo->type == MT_SPINFIRE) // elemental shield fire is another exception here ; + else if (mo->type == MT_ITEM_DEBRIS) + { + mom.z = Obj_ItemDebrisBounce(mo, mom.z); + + if (mom.z == 0) + { + return false; + } + } else if (mo->type == MT_DRIFTCLIP) { mom.z = -mom.z/2; @@ -7886,6 +7898,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj) Obj_HyudoroCenterThink(mobj); break; } + case MT_ITEM_DEBRIS: + { + Obj_ItemDebrisThink(mobj); + break; + } case MT_ROCKETSNEAKER: if (!mobj->target || !mobj->target->health) {