From 897feac6516d4702cb057bce86cd63d02af4f0c4 Mon Sep 17 00:00:00 2001 From: Latapostrophe Date: Fri, 20 Mar 2020 14:59:38 +0100 Subject: [PATCH 1/2] Make SPB spawn damaging dust and sliptides while it moves around --- src/dehacked.c | 1 + src/info.c | 27 +++++++++++++++ src/info.h | 1 + src/p_enemy.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 119 insertions(+), 1 deletion(-) diff --git a/src/dehacked.c b/src/dehacked.c index 31986e942..2e4b89d41 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -7999,6 +7999,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s "MT_KARMAFIREWORK", "MT_RINGSPARKS", "MT_DRAFTDUST", + "MT_SPBDUST", "MT_TIREGREASE", "MT_OVERTIMEFOG", diff --git a/src/info.c b/src/info.c index b1d95859b..fb56abcfa 100644 --- a/src/info.c +++ b/src/info.c @@ -20293,6 +20293,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_SPBDUST + -1, // doomednum + S_DRAFTDUST1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // 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 + 16<floorz; + angle_t sa = mo->angle - ANG1*60; + INT32 i; + + if (mo->eflags & MFE_VERTICALFLIP) + sz = mo->ceilingz; + + if (leveltime & 1 && abs(mo->z - sz) < FRACUNIT*32) // Only ever other frame. Also don't spawn it if we're way above the ground. + { + // Determine spawning position next to the SPB: + for (i=0; i < 2; i++) + { + sx = mo->x + FixedMul((mo->scale*96), FINECOSINE((sa)>>ANGLETOFINESHIFT)); + sy = mo->y + FixedMul((mo->scale*96), FINESINE((sa)>>ANGLETOFINESHIFT)); + + dust = P_SpawnMobj(sx, sy, sz, MT_SPBDUST); + dust->momx = mo->momx/2; + dust->momy = mo->momy/2; + dust->momz = mo->momz/2; // Give some of the momentum to the dust + P_SetScale(dust, mo->scale*2); + dust->colorized = true; + dust->color = SKINCOLOR_RED; + dust->angle = mo->angle - FixedAngle(FRACUNIT*90 - FRACUNIT*180*i); // The first one will spawn to the right of the spb, the second one to the left. + P_Thrust(dust, dust->angle, 6*dust->scale); + + K_MatchGenericExtraFlags(dust, mo); + + sa += ANG1*120; // Add 120 degrees to get to mo->angle + ANG1*60 + } + } +} + +// Spawns SPB slip tide. To be used when the SPB is turning. +// Modified version of K_SpawnAIZDust. Maybe we could merge those to be cleaner? + +// dir should be either 1 or -1 to determine where to spawn the dust. + +static void SpawnSPBAIZDust(mobj_t *mo, INT32 dir) +{ + fixed_t newx; + fixed_t newy; + mobj_t *spark; + angle_t travelangle; + + travelangle = R_PointToAngle2(0, 0, mo->momx, mo->momy); + if (leveltime & 1) + { + newx = mo->x + P_ReturnThrustX(mo, travelangle - (dir*ANGLE_45), FixedMul(24*FRACUNIT, mo->scale)); + newy = mo->y + P_ReturnThrustY(mo, travelangle - (dir*ANGLE_45), FixedMul(24*FRACUNIT, mo->scale)); + spark = P_SpawnMobj(newx, newy, mo->z, MT_AIZDRIFTSTRAT); + spark->colorized = true; + spark->color = SKINCOLOR_RED; + spark->flags = MF_NOGRAVITY|MF_PAIN; + P_SetTarget(&spark->target, mo); + + spark->angle = travelangle+(dir*ANGLE_90); + P_SetScale(spark, (spark->destscale = mo->scale*3/2)); + + spark->momx = (6*mo->momx)/5; + spark->momy = (6*mo->momy)/5; + + K_MatchGenericExtraFlags(spark, mo); + } +} + void A_SPBChase(mobj_t *actor) { player_t *player = NULL; @@ -8703,6 +8775,12 @@ void A_SPBChase(mobj_t *actor) spbplace = bestrank; dist = P_AproxDistance(P_AproxDistance(actor->x-actor->tracer->x, actor->y-actor->tracer->y), actor->z-actor->tracer->z); + /* + K_GetBestWaypointForMobj returns the waypoint closest to the object that isn't its current waypoint. While this is usually good enough, + in cases where the track overlaps, this means that the SPB will sometimes target a waypoint on an earlier/later portion of the track instead of following along. + For this reason, we're going to try and make sure to avoid these situations. + */ + // Move along the waypoints until you get close enough if (actor->cusval > -1 && actor->extravalue2 > 0) { @@ -8770,6 +8848,8 @@ void A_SPBChase(mobj_t *actor) // Smoothly rotate horz angle angle_t input = hang - actor->angle; boolean invert = (input > ANGLE_180); + INT32 turnangle; + if (invert) input = InvAngle(input); @@ -8782,6 +8862,15 @@ void A_SPBChase(mobj_t *actor) input = InvAngle(input); actor->angle += input; + // If input is small enough, spawn dust. Otherwise, spawn a slip tide! + turnangle = AngleFixed(input)/FRACUNIT; + + // The SPB is really turning if that value is >= 3 and <= 357. This looks pretty bad check-wise so feel free to change it for something that isn't as terrible. + if (turnangle >= 3 && turnangle <= 357) + SpawnSPBAIZDust(actor, turnangle < 180 ? 1 : -1); // 1 if turning left, -1 if turning right. Angles work counterclockwise, remember! + else + SpawnSPBDust(actor); // if we're mostly going straight, then spawn the V dust cone! + // Smoothly rotate vert angle input = vang - actor->movedir; invert = (input > ANGLE_180); @@ -8830,7 +8919,7 @@ void A_SPBChase(mobj_t *actor) // Spawn a trail of rings behind the SPB! SpawnSPBTrailRings(actor); - if (dist <= (1024*actor->tracer->scale)) // Close enough to target? + if (dist <= (1024*actor->tracer->scale) && !actor->reactiontime) // Close enough to target? Reactiontime is used for debug purposes. { S_StartSound(actor, actor->info->attacksound); actor->extravalue1 = 1; // TARGET ACQUIRED From 366fff9942baeb9530d474fd4784a066af467294 Mon Sep 17 00:00:00 2001 From: Latapostrophe Date: Fri, 20 Mar 2020 21:58:14 +0100 Subject: [PATCH 2/2] Red rings, fuse, and spb game speed support --- src/k_kart.c | 19 ++++++++++++++----- src/k_kart.h | 1 + src/p_enemy.c | 51 +++++++++++++++++++++++++++++++-------------------- src/p_mobj.c | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 81 insertions(+), 25 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 27a4b1e1f..fd280f86e 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -2499,20 +2499,29 @@ static void K_GetKartBoostPower(player_t *player) player->kartstuff[k_numboosts] = numboosts; } -fixed_t K_GetKartSpeed(player_t *player, boolean doboostpower) +// Returns kart speed from a stat. Boost power and scale are NOT taken into account, no player or object is necessary. +fixed_t K_GetKartSpeedFromStat(UINT8 kartspeed) { const fixed_t xspd = (3*FRACUNIT)/64; fixed_t g_cc = K_GetKartGameSpeedScalar(gamespeed) + xspd; fixed_t k_speed = 150; - UINT8 kartspeed = player->kartspeed; fixed_t finalspeed; - if (G_BattleGametype() && player->kartstuff[k_bumper] <= 0) - kartspeed = 1; - k_speed += kartspeed*3; // 153 - 177 finalspeed = FixedMul(k_speed<<14, g_cc); + return finalspeed; +} + +fixed_t K_GetKartSpeed(player_t *player, boolean doboostpower) +{ + fixed_t finalspeed; + UINT8 kartspeed = player->kartspeed; + + if (G_BattleGametype() && player->kartstuff[k_bumper] <= 0) + kartspeed = 1; + + finalspeed = K_GetKartSpeedFromStat(kartspeed); if (player->mo && !P_MobjWasRemoved(player->mo)) finalspeed = FixedMul(finalspeed, player->mo->scale); diff --git a/src/k_kart.h b/src/k_kart.h index ff6f6fafc..988b1b8ad 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -62,6 +62,7 @@ void K_DropItems(player_t *player); void K_StripItems(player_t *player); void K_StripOther(player_t *player); void K_MomentumToFacing(player_t *player); +fixed_t K_GetKartSpeedFromStat(UINT8 kartspeed); fixed_t K_GetKartSpeed(player_t *player, boolean doboostpower); fixed_t K_GetKartAccel(player_t *player); UINT16 K_GetKartFlashing(player_t *player); diff --git a/src/p_enemy.c b/src/p_enemy.c index 0aa6a49ac..8c33aba3e 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -8449,12 +8449,14 @@ static void SpawnSPBTrailRings(mobj_t *actor) { if (actor != NULL) { - if (leveltime % 6 == 0) + if (leveltime % (actor->extravalue1 == 2 ? 6 : 3) == 0) // Extravalue1 == 2 is seeking mode. Because the SPB is about twice as fast as normal in that mode, also spawn the rings twice as often to make up for it! { mobj_t *ring = P_SpawnMobj(actor->x - actor->momx, actor->y - actor->momy, actor->z - actor->momz + (24*mapobjectscale), MT_RING); ring->threshold = 10; - ring->fuse = 120*TICRATE; + ring->fuse = 35*TICRATE; + ring->colorized = true; + ring->color = SKINCOLOR_RED; } } } @@ -8473,7 +8475,7 @@ static void SpawnSPBDust(mobj_t *mo) if (mo->eflags & MFE_VERTICALFLIP) sz = mo->ceilingz; - if (leveltime & 1 && abs(mo->z - sz) < FRACUNIT*32) // Only ever other frame. Also don't spawn it if we're way above the ground. + if (leveltime & 1 && abs(mo->z - sz) < FRACUNIT*64) // Only ever other frame. Also don't spawn it if we're way above the ground. { // Determine spawning position next to the SPB: for (i=0; i < 2; i++) @@ -8509,13 +8511,17 @@ static void SpawnSPBAIZDust(mobj_t *mo, INT32 dir) fixed_t newy; mobj_t *spark; angle_t travelangle; + fixed_t sz = mo->floorz; + + if (mo->eflags & MFE_VERTICALFLIP) + sz = mo->ceilingz; travelangle = R_PointToAngle2(0, 0, mo->momx, mo->momy); - if (leveltime & 1) + if (leveltime & 1 && abs(mo->z - sz) < FRACUNIT*64) { newx = mo->x + P_ReturnThrustX(mo, travelangle - (dir*ANGLE_45), FixedMul(24*FRACUNIT, mo->scale)); newy = mo->y + P_ReturnThrustY(mo, travelangle - (dir*ANGLE_45), FixedMul(24*FRACUNIT, mo->scale)); - spark = P_SpawnMobj(newx, newy, mo->z, MT_AIZDRIFTSTRAT); + spark = P_SpawnMobj(newx, newy, sz, MT_AIZDRIFTSTRAT); spark->colorized = true; spark->color = SKINCOLOR_RED; spark->flags = MF_NOGRAVITY|MF_PAIN; @@ -8531,6 +8537,21 @@ static void SpawnSPBAIZDust(mobj_t *mo, INT32 dir) } } +// Used for seeking and when SPB is trailing its target from way too close! +static void SpawnSPBSpeedLines(mobj_t *actor) +{ + mobj_t *fast = P_SpawnMobj(actor->x + (P_RandomRange(-24,24) * actor->scale), + actor->y + (P_RandomRange(-24,24) * actor->scale), + actor->z + (actor->height/2) + (P_RandomRange(-24,24) * actor->scale), + MT_FASTLINE); + + fast->angle = R_PointToAngle2(0, 0, actor->momx, actor->momy); + fast->color = SKINCOLOR_RED; + fast->colorized = true; + K_MatchGenericExtraFlags(fast, actor); +} + + void A_SPBChase(mobj_t *actor) { player_t *player = NULL; @@ -8549,7 +8570,7 @@ void A_SPBChase(mobj_t *actor) #endif // Default speed - wspeed = actor->movefactor; + wspeed = FixedMul(mapobjectscale, K_GetKartSpeedFromStat(5)*2); // Go at twice the average speed a player would be going at! if (actor->threshold) // Just fired, go straight. { @@ -8701,19 +8722,7 @@ void A_SPBChase(mobj_t *actor) if (R_PointToDist2(0, 0, actor->momx, actor->momy) > (actor->tracer->player ? (16*actor->tracer->player->speed)/15 : (16*R_PointToDist2(0, 0, actor->tracer->momx, actor->tracer->momy))/15) // Going faster than the target && xyspeed > K_GetKartSpeed(actor->tracer->player, false)/4) // Don't display speedup lines at pitifully low speeds - { - mobj_t *fast = P_SpawnMobj(actor->x + (P_RandomRange(-24,24) * actor->scale), - actor->y + (P_RandomRange(-24,24) * actor->scale), - actor->z + (actor->height/2) + (P_RandomRange(-24,24) * actor->scale), - MT_FASTLINE); - fast->angle = R_PointToAngle2(0, 0, actor->momx, actor->momy); - //fast->momx = (3*actor->momx)/4; - //fast->momy = (3*actor->momy)/4; - //fast->momz = (3*actor->momz)/4; - fast->color = SKINCOLOR_RED; - fast->colorized = true; - K_MatchGenericExtraFlags(fast, actor); - } + SpawnSPBSpeedLines(actor); return; } @@ -8871,6 +8880,8 @@ void A_SPBChase(mobj_t *actor) else SpawnSPBDust(actor); // if we're mostly going straight, then spawn the V dust cone! + SpawnSPBSpeedLines(actor); // Always spawn speed lines while seeking + // Smoothly rotate vert angle input = vang - actor->movedir; invert = (input > ANGLE_180); @@ -8919,7 +8930,7 @@ void A_SPBChase(mobj_t *actor) // Spawn a trail of rings behind the SPB! SpawnSPBTrailRings(actor); - if (dist <= (1024*actor->tracer->scale) && !actor->reactiontime) // Close enough to target? Reactiontime is used for debug purposes. + if (dist <= (1024*actor->tracer->scale) && !(actor->flags2 & MF2_AMBUSH)) // Close enough to target? Use Ambush flag to disable targetting so I can have an easier time testing stuff... { S_StartSound(actor, actor->info->attacksound); actor->extravalue1 = 1; // TARGET ACQUIRED diff --git a/src/p_mobj.c b/src/p_mobj.c index 4ef291c82..2fcc99a08 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -3982,6 +3982,9 @@ void P_PrecipThinker(precipmobj_t *mobj) static void P_RingThinker(mobj_t *mobj) { + + mobj_t *spark; // Ring Fuse + if (mobj->momx || mobj->momy) { P_RingXYMovement(mobj); @@ -4001,6 +4004,38 @@ static void P_RingThinker(mobj_t *mobj) return; } + // This thinker splits apart before the regular fuse handling so we need to handle it here instead. + if (mobj->fuse) + { + mobj->fuse--; + + if (mobj->fuse < TICRATE*3) + { + if (leveltime & 1) + mobj->flags2 |= MF2_DONTDRAW; + else + mobj->flags2 &= ~MF2_DONTDRAW; + } + + if (!mobj->fuse) + { +#ifdef HAVE_BLUA + if (!LUAh_MobjFuse(mobj)) +#endif + { + mobj->flags2 &= ~MF2_DONTDRAW; + spark = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_SIGNSPARKLE); // Spawn a fancy sparkle + K_MatchGenericExtraFlags(spark, mobj); + spark->colorized = true; + spark->color = mobj->color ? : SKINCOLOR_YELLOW; // Use yellow if the ring doesn't use a skin color. (It should be red for SPB rings, but let normal rings look fancy too!) + P_RemoveMobj(mobj); // Adieu, monde cruel! + return; + } + + } + + } + P_CycleMobjState(mobj); }