From 4d67cc6324593b1905b9e385043399360e6bb8dd Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 17 Sep 2022 06:34:11 -0700 Subject: [PATCH 1/6] Replace shitty item box pop with flying debris and dust clouds Debris flies forward and outward from the player in the direction of momentum. Debris particles bounce once then disappear when they hit the ground for the second time. Clouds spawn on and trail behind the player for a short duration. --- 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 5fe950e9e..37d1e0cc0 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 @@ -5297,6 +5304,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 b0a3becef..e0df17fa6 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 @@ -3867,6 +3868,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 @@ -23128,6 +23135,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 8acf73ba8..62daffb42 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 @@ -4270,6 +4273,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 @@ -6326,6 +6335,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 a23801ccc..9d582da59 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 cc80d2555..128c0f461 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -15,4 +15,10 @@ void Obj_ShrinkGunRemoved(mobj_t *gun); boolean Obj_ShrinkLaserCollide(mobj_t *gun, mobj_t *victim); void Obj_CreateShrinkPohbees(player_t *owner); +/* 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 94f7dd25b..d1e801471 100644 --- a/src/objects/Sourcefile +++ b/src/objects/Sourcefile @@ -1,2 +1,3 @@ hyudoro.c shrink.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 d5f999624..879d01350 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 @@ -13166,9 +13168,6 @@ void A_ItemPop(mobj_t *actor) { INT32 locvar1 = var1; - mobj_t *remains; - mobjtype_t explode; - if (LUA_CallAction(A_ITEMPOP, actor)) return; @@ -13185,58 +13184,13 @@ void A_ItemPop(mobj_t *actor) actor->flags |= MF_NOCLIP; P_SetThingPosition(actor); - // 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)) numgotboxes++; @@ -14525,3 +14479,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 0505d6bda..ee005d960 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; @@ -7845,6 +7857,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj) Obj_PohbeeThinker(mobj); break; } + case MT_ITEM_DEBRIS: + { + Obj_ItemDebrisThink(mobj); + break; + } case MT_ROCKETSNEAKER: if (!mobj->target || !mobj->target->health) { From c2b2cd9a43a1252983b7311d8f0f53a36338e267 Mon Sep 17 00:00:00 2001 From: James R Date: Mon, 19 Sep 2022 23:37:29 -0700 Subject: [PATCH 2/6] Reenable item box respawning Old code was shit so I removed it (4d67cc632). Turns out none of that bullshit actually mattered to make this box respawn and it just needs to go to an invisible state! Makes use of some nifty flickering code (that was already there but effectively disabled) shortly before it actually respawns. --- src/info.c | 2 +- src/p_enemy.c | 8 ++++++-- src/p_mobj.c | 4 ---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/info.c b/src/info.c index ce37b51ad..3c868d4c0 100644 --- a/src/info.c +++ b/src/info.c @@ -3849,7 +3849,7 @@ state_t states[NUMSTATES] = {SPR_RNDM, 18|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, 4, {NULL}, 1, 1, S_RANDOMITEM11}, // S_RANDOMITEM10 {SPR_RNDM, 20|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, 4, {NULL}, 1, 1, S_RANDOMITEM12}, // S_RANDOMITEM11 {SPR_RNDM, 22|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, 4, {NULL}, 1, 1, S_RANDOMITEM1}, // S_RANDOMITEM12 - {SPR_NULL, 0, 0, {A_ItemPop}, 0, 0, S_NULL}, // S_DEADRANDOMITEM + {SPR_NULL, 0, 0, {A_ItemPop}, 0, 0, S_RANDOMITEM1}, // S_DEADRANDOMITEM {SPR_SBOX, FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, 4, {NULL}, 1, 1, S_SPHEREBOX2}, // S_SPHEREBOX1 {SPR_SBOX, 2|FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM, 4, {NULL}, 1, 1, S_SPHEREBOX3}, // S_SPHEREBOX2 diff --git a/src/p_enemy.c b/src/p_enemy.c index 879d01350..901c2a2b2 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -13184,6 +13184,12 @@ void A_ItemPop(mobj_t *actor) actor->flags |= MF_NOCLIP; P_SetThingPosition(actor); + // RF_DONTDRAW will flicker as the object's fuse gets + // closer to running out (see P_FuseThink) + actor->renderflags |= RF_DONTDRAW|RF_TRANS50; + actor->color = SKINCOLOR_GREY; + actor->colorized = true; + Obj_SpawnItemDebrisEffects(actor, actor->target); if (locvar1 == 1) @@ -13194,8 +13200,6 @@ void A_ItemPop(mobj_t *actor) // Here at mapload in battle? if ((gametyperules & GTR_BUMPERS) && (actor->flags2 & MF2_BOSSNOTRAP)) numgotboxes++; - - P_RemoveMobj(actor); } void A_JawzChase(mobj_t *actor) diff --git a/src/p_mobj.c b/src/p_mobj.c index ee005d960..1c34a1b1e 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -12683,10 +12683,6 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean P_SetThingPosition(mobj); } } - else - { - P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_EXPLODE); - } break; } case MT_ITEMCAPSULE: From f6ef29cf03bca2898824e5011cea8f7dcf487da5 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 20 Sep 2022 05:24:48 -0700 Subject: [PATCH 3/6] Refactor item debris cloud - The "cloud" is stationary and spawned on the item box instead of the player. Still scales up with speed. - Single particles are spawned behind the player. No longer scales. Lasts longer but can end early if the player slows down. --- src/deh_tables.c | 2 - src/info.c | 10 ++--- src/info.h | 2 - src/k_objects.h | 1 - src/objects/item-debris.c | 90 +++++++++++++++++++++++++++------------ src/p_enemy.c | 69 +++++++++++++++--------------- 6 files changed, 101 insertions(+), 73 deletions(-) diff --git a/src/deh_tables.c b/src/deh_tables.c index 534b17db7..37ec83b7f 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -3279,10 +3279,8 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi //} "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", diff --git a/src/info.c b/src/info.c index 3c868d4c0..84edb3900 100644 --- a/src/info.c +++ b/src/info.c @@ -3871,10 +3871,8 @@ state_t states[NUMSTATES] = {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, 0, 0, {A_Repeat}, 16, S_ITEM_DEBRIS_CLOUD_SPAWNER2, S_NULL}, // S_ITEM_DEBRIS_CLOUD_SPAWNER1 + {SPR_NULL, 0, 7, {A_SpawnItemDebrisCloud}, 20, 0, S_ITEM_DEBRIS_CLOUD_SPAWNER1}, // S_ITEM_DEBRIS_CLOUD_SPAWNER2 {SPR_NULL, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMICON @@ -23178,7 +23176,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_ITEM_DEBRIS_CLOUD_SPAWNER -1, // doomednum - S_ITEM_DEBRIS_CLOUD_SPAWNER_INIT, // spawnstate + S_ITEM_DEBRIS_CLOUD_SPAWNER1, // spawnstate 1, // spawnhealth S_NULL, // seestate sfx_None, // seesound @@ -23199,7 +23197,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // mass 0, // damage sfx_None, // activesound - MF_NOSECTOR|MF_NOBLOCKMAP, // flags + MF_NOSECTOR|MF_NOBLOCKMAP|MF_RUNSPAWNFUNC, // flags S_NULL // raisestate }, diff --git a/src/info.h b/src/info.h index dceec967d..c5ed74daa 100644 --- a/src/info.h +++ b/src/info.h @@ -4276,10 +4276,8 @@ typedef enum state //} 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, diff --git a/src/k_objects.h b/src/k_objects.h index 128c0f461..775710c1a 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -16,7 +16,6 @@ boolean Obj_ShrinkLaserCollide(mobj_t *gun, mobj_t *victim); void Obj_CreateShrinkPohbees(player_t *owner); /* 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); diff --git a/src/objects/item-debris.c b/src/objects/item-debris.c index dcb1950d7..841650527 100644 --- a/src/objects/item-debris.c +++ b/src/objects/item-debris.c @@ -4,6 +4,7 @@ #include "../k_kart.h" #include "../k_objects.h" #include "../p_local.h" +#include "../r_main.h" #include "../s_sound.h" // TODO: general function @@ -80,15 +81,52 @@ spawn_debris static void spawn_cloud ( mobj_t * collectible, - mobj_t * collector) + mobj_t * collector, + fixed_t base_speed) { - mobj_t *spawner = P_SpawnMobjFromMobj(collectible, - 0, 0, 0, MT_ITEM_DEBRIS_CLOUD_SPAWNER); + const fixed_t min_speed = 90 * collectible->scale; - P_SetTarget(&spawner->target, collector); + const fixed_t scale = FixedDiv( + max(base_speed, min_speed), min_speed); - S_StartSound(spawner, sfx_kc2e); - S_StartSound(spawner, sfx_s1c9); + const INT16 spacing = + (collectible->radius / 2) / collectible->scale; + + INT32 i; + + // Most of this code is from p_inter.c, MT_ITEMCAPSULE + + // dust effects + for (i = 0; i < 10; i++) + { + mobj_t *puff = P_SpawnMobjFromMobj( + collectible, + P_RandomRange(-spacing, spacing) * FRACUNIT, + P_RandomRange(-spacing, spacing) * FRACUNIT, + P_RandomRange(0, 4 * spacing) * FRACUNIT, + MT_SPINDASHDUST + ); + + puff->color = collector->color; + puff->colorized = true; + + puff->destscale = FixedMul(puff->destscale, scale); + P_SetScale(puff, puff->destscale); + + puff->momz = puff->scale * P_MobjFlip(puff); + + P_InitAngle(puff, R_PointToAngle2( + collectible->x, + collectible->y, + puff->x, + puff->y)); + + P_Thrust(puff, puff->angle, 3 * puff->scale); + + puff->momx += collector->momx; + puff->momy += collector->momy; + puff->momz += collector->momz; + } } static void @@ -100,18 +138,6 @@ rotate3d (mobj_t *debris) 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, @@ -119,15 +145,22 @@ Obj_SpawnItemDebrisEffects { const fixed_t min_speed = 80 * collectible->scale; - const fixed_t speed = - Obj_GetItemDebrisSpeed(collector, min_speed); + fixed_t base_speed = FixedMul(75 * mapobjectscale, + get_speed_ratio(collector)); - struct debris_config config = { - .origin = collectible, - .angle = K_MomentumAngle(collector), - .speed = speed, - .scale = FixedDiv(speed, min_speed), - }; + struct debris_config config; + + // Delayed effect for puffs of smoke that stick to and + // glide off of the player + mobj_t *spawner = P_SpawnMobjFromMobj(collectible, + 0, 0, 0, MT_ITEM_DEBRIS_CLOUD_SPAWNER); + + P_SetTarget(&spawner->target, collector); + + config.origin = collectible; + config.angle = K_MomentumAngle(collector); + config.speed = max(base_speed, min_speed); + config.scale = FixedDiv(config.speed, min_speed); config.type = DEBRIS_ALPHA; @@ -142,7 +175,10 @@ Obj_SpawnItemDebrisEffects spawn_debris(&config, -(3*ANGLE_22h/4)); spawn_debris(&config, -(3*ANGLE_22h/2)); - spawn_cloud(collectible, collector); + spawn_cloud(collectible, collector, base_speed); + + S_StartSound(collectible, sfx_kc2e); + S_StartSound(collectible, sfx_s1c9); } void diff --git a/src/p_enemy.c b/src/p_enemy.c index 901c2a2b2..1a0c31c4b 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -14486,59 +14486,55 @@ void A_InvincSparkleRotate(mobj_t *actor) // Function: A_SpawnItemDebrisCloud // -// Description: Spawns a particle effect relative to the location of the actor +// Description: Spawns the poofs of an exploded item box. Target is a player to spawn the particles around. // -// var1 = If 1, scale size and momentum by extravalue2 / frame. -// var2 = Number of particles to spawn. +// var1 = Copy extravalue2 / var1 fraction of target's momentum. +// var2 = unused // 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; + player_t *player; - fixed_t speed; - fixed_t scale; + fixed_t kartspeed; + fixed_t fade; - INT32 i; - - if (target == NULL) + if (target == NULL || target->player == NULL) { return; } - if (locvar1) + player = target->player; + kartspeed = K_GetKartSpeed(player, false, false); + + // Scale around >50% top speed + fade = FixedMul(locvar1, (FixedDiv(player->speed, + kartspeed) - FRACUNIT/2) * 2); + + if (fade < 1) { - 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; + fade = 1; } - speed = Obj_GetItemDebrisSpeed(target, min_speed); - scale = 2 * FixedMul(FixedDiv(speed, min_speed), scale_fade); + if (actor->extravalue2 > fade) + { + actor->extravalue2 = fade; + } + + // MT_ITEM_DEBRIS_CLOUD_SPAWNER + // extravalue2 from A_Repeat + fade = actor->extravalue2 * FRACUNIT / locvar1; // Most of this code is from p_inter.c, MT_ITEMCAPSULE // dust effects - for (i = 0; i < locvar2; i++) { + const INT16 spacing = + (target->radius / 2) / target->scale; + mobj_t *puff = P_SpawnMobjFromMobj( target, P_RandomRange(-spacing, spacing) * FRACUNIT, @@ -14550,12 +14546,15 @@ A_SpawnItemDebrisCloud (mobj_t *actor) 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); + P_InitAngle(puff, R_PointToAngle2( + target->x, + target->y, + puff->x, + puff->y)); + + P_Thrust(puff, puff->angle, 3 * puff->scale); puff->momx += FixedMul(target->momx, fade); puff->momy += FixedMul(target->momy, fade); From 7d87f2e1a2fbe467a52fe0d2b90092560857d68b Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 20 Sep 2022 05:42:11 -0700 Subject: [PATCH 4/6] Fix item debris animation WHAT WERE THEY COOKING --- src/info.c | 2 +- src/objects/item-debris.c | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/info.c b/src/info.c index 84edb3900..861120d23 100644 --- a/src/info.c +++ b/src/info.c @@ -3870,7 +3870,7 @@ 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_ITRI, FF_FULLBRIGHT|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 19, 1, S_NULL}, // S_ITEM_DEBRIS {SPR_NULL, 0, 0, {A_Repeat}, 16, S_ITEM_DEBRIS_CLOUD_SPAWNER2, S_NULL}, // S_ITEM_DEBRIS_CLOUD_SPAWNER1 {SPR_NULL, 0, 7, {A_SpawnItemDebrisCloud}, 20, 0, S_ITEM_DEBRIS_CLOUD_SPAWNER1}, // S_ITEM_DEBRIS_CLOUD_SPAWNER2 diff --git a/src/objects/item-debris.c b/src/objects/item-debris.c index 841650527..941cdc24c 100644 --- a/src/objects/item-debris.c +++ b/src/objects/item-debris.c @@ -52,15 +52,9 @@ spawn_debris 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); From 81eb513ef14a5e5b56b6836e9cdd64a371827a1d Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 20 Sep 2022 06:08:00 -0700 Subject: [PATCH 5/6] Fix item pop sfx not playing for eggman boxes and playing TWICE for everything else The former is my bruh and the latter is probably not my brew. --- src/objects/item-debris.c | 4 ++-- src/p_inter.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/objects/item-debris.c b/src/objects/item-debris.c index 941cdc24c..a5ddd5842 100644 --- a/src/objects/item-debris.c +++ b/src/objects/item-debris.c @@ -171,8 +171,8 @@ Obj_SpawnItemDebrisEffects spawn_cloud(collectible, collector, base_speed); - S_StartSound(collectible, sfx_kc2e); - S_StartSound(collectible, sfx_s1c9); + S_StartSound(spawner, sfx_kc2e); + S_StartSound(spawner, sfx_s1c9); } void diff --git a/src/p_inter.c b/src/p_inter.c index 438909980..7898d0b8e 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -275,7 +275,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) special->momx = special->momy = special->momz = 0; P_SetTarget(&special->target, toucher); P_KillMobj(special, toucher, toucher, DMG_NORMAL); - break; + return; case MT_SPHEREBOX: if (!P_CanPickupItem(player, 0)) return; @@ -283,7 +283,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) special->momx = special->momy = special->momz = 0; P_SetTarget(&special->target, toucher); P_KillMobj(special, toucher, toucher, DMG_NORMAL); - break; + return; case MT_ITEMCAPSULE: if ((gametyperules & GTR_BUMPERS) && player->bumpers <= 0) return; From e7b0e223e1862ad10edd0300c9f45ac4c98039e3 Mon Sep 17 00:00:00 2001 From: James R Date: Tue, 20 Sep 2022 10:36:32 -0700 Subject: [PATCH 6/6] Fix respawning item boxes with P_RespawnBattlesBoxes --- src/info.c | 2 +- src/p_enemy.c | 6 ++++++ src/p_inter.c | 39 +++++++++++++++++++++++---------------- src/p_mobj.c | 24 +++++------------------- 4 files changed, 35 insertions(+), 36 deletions(-) diff --git a/src/info.c b/src/info.c index 861120d23..c1136d43d 100644 --- a/src/info.c +++ b/src/info.c @@ -22550,7 +22550,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = MT_RANDOMITEMPOP, // damage sfx_None, // activesound MF_SLIDEME|MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags - S_NULL // raisestate + S_RANDOMITEM1 // raisestate }, { // MT_SPHEREBOX diff --git a/src/p_enemy.c b/src/p_enemy.c index 1a0c31c4b..527dcf0b6 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -13199,7 +13199,13 @@ void A_ItemPop(mobj_t *actor) // Here at mapload in battle? if ((gametyperules & GTR_BUMPERS) && (actor->flags2 & MF2_BOSSNOTRAP)) + { numgotboxes++; + + // do not flicker back in just yet, handled by + // P_RespawnBattleBoxes eventually + P_SetMobjState(actor, S_INVISIBLE); + } } void A_JawzChase(mobj_t *actor) diff --git a/src/p_inter.c b/src/p_inter.c index 7898d0b8e..1edf9fcb2 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1037,27 +1037,34 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget { if (target->flags & MF_MONITOR || target->type == MT_RANDOMITEM) { - UINT8 i; - P_SetTarget(&target->target, source); - for (i = 0; i < MAXPLAYERS; i++) + if (gametyperules & GTR_BUMPERS) { - if (&players[i] == source->player) - { - continue; - } - - if (playeringame[i] && !players[i].spectator && players[i].lives != 0) - { - break; - } + target->fuse = 2; } - - if (i < MAXPLAYERS) + else { - // Respawn items in multiplayer, don't respawn them when alone - target->fuse = 2*TICRATE + 2; + UINT8 i; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (&players[i] == source->player) + { + continue; + } + + if (playeringame[i] && !players[i].spectator && players[i].lives != 0) + { + break; + } + } + + if (i < MAXPLAYERS) + { + // Respawn items in multiplayer, don't respawn them when alone + target->fuse = 2*TICRATE + 2; + } } } } diff --git a/src/p_mobj.c b/src/p_mobj.c index 1c34a1b1e..1d08d63e9 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -9229,7 +9229,7 @@ static boolean P_FuseThink(mobj_t *mobj) { ; } - else if ((gametyperules & GTR_BUMPERS) && (mobj->threshold != 70)) + else if ((gametyperules & GTR_BUMPERS) && (mobj->state == &states[S_INVISIBLE])) { break; } @@ -11072,7 +11072,6 @@ void P_RespawnBattleBoxes(void) for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) { mobj_t *box; - mobj_t *newmobj; if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) continue; @@ -11081,25 +11080,12 @@ void P_RespawnBattleBoxes(void) if (box->type != MT_RANDOMITEM || (box->flags2 & MF2_DONTRESPAWN) - || box->threshold != 68 - || box->fuse - || ((tic_t)box->cvmem+1 >= leveltime)) + || box->health > 0 + || box->fuse) continue; // only popped items - // Respawn from mapthing if you have one! - if (box->spawnpoint) - { - P_SpawnMapThing(box->spawnpoint); - newmobj = box->spawnpoint->mobj; // this is set to the new mobj in P_SpawnMapThing - } - else - { - newmobj = P_SpawnMobj(box->x, box->y, box->z, box->type); - } - - // Transfer flags2 (strongbox, objectflip, bossnotrap) - newmobj->flags2 = box->flags2; - P_RemoveMobj(box); // make sure they disappear + box->fuse = TICRATE; // flicker back in (A_ItemPop preps this effect) + P_SetMobjState(box, box->info->raisestate); if (numgotboxes > 0) numgotboxes--; // you've restored a box, remove it from the count