From 8ab2962830d31937f029d14d19bf74578c0069a1 Mon Sep 17 00:00:00 2001 From: James R Date: Fri, 17 Feb 2023 23:55:28 -0800 Subject: [PATCH 1/3] Nullify Garden Top friction at +200% --- src/k_kart.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index 787c4aff9..b8d06ef25 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -9929,7 +9929,8 @@ void K_AdjustPlayerFriction(player_t *player) // Less friction on Top unless grinding if (player->curshield == KSHIELD_TOP && - K_GetForwardMove(player) > 0) + K_GetForwardMove(player) > 0 && + player->speed < 2 * K_GetKartSpeed(player, false, false)) { player->mo->friction += 1024; } From ecec400ca4a86a3542e30d00fef8a6dd78ca94f0 Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 18 Feb 2023 01:21:22 -0800 Subject: [PATCH 2/3] NULL check Garden Top when throwing backward --- src/k_kart.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index b8d06ef25..d44036001 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -10602,9 +10602,12 @@ void K_MoveKartPlayer(player_t *player, boolean onground) P_InstaThrust(player->mo, angle, player->speed + (80 * mapobjectscale)); P_SetObjectMomZ(player->mo, player->mo->info->height / 8, true); - top->momx = player->mo->momx; - top->momy = player->mo->momy; - top->momz = player->mo->momz; + if (top != NULL) + { + top->momx = player->mo->momx; + top->momy = player->mo->momy; + top->momz = player->mo->momz; + } } else { From b1fac18844652926f434e72109102644db25ee2b Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 18 Feb 2023 01:22:55 -0800 Subject: [PATCH 3/3] Add Garden Top arrows Two arrows. One above the player, floating. One below the player, on the ground. Both arrows use the player's facing angle. Arrows are only visible to their own player (other players can't see them). The floating arrow is a papersprite. You can see the arrow turn with you as you turn your camera. The grounded arrow is a splat with additive blending. It tilts to match the slope of the ground you're driving on. --- src/deh_tables.c | 2 + src/info.c | 29 ++++++++ src/info.h | 3 + src/k_objects.h | 1 + src/objects/gardentop.c | 153 ++++++++++++++++++++++++++++++++++++---- src/p_mobj.c | 5 ++ 6 files changed, 180 insertions(+), 13 deletions(-) diff --git a/src/deh_tables.c b/src/deh_tables.c index 19a5e4dde..16134fe68 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -3776,6 +3776,7 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_GARDENTOP_SINKING3", "S_GARDENTOP_DEAD", "S_GARDENTOPSPARK", + "S_GARDENTOPARROW", // Caked-Up Booty-Sheet Ghost "S_HYUDORO", @@ -5389,6 +5390,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_BUBBLESHIELDTRAP", "MT_GARDENTOP", "MT_GARDENTOPSPARK", + "MT_GARDENTOPARROW", "MT_HYUDORO", "MT_HYUDORO_CENTER", diff --git a/src/info.c b/src/info.c index 063c48220..cdfa6f088 100644 --- a/src/info.c +++ b/src/info.c @@ -586,6 +586,7 @@ char sprnames[NUMSPRITES + 1][5] = "FLML", // Flame Shield speed lines "FLMF", // Flame Shield flash "GTOP", // Marble Garden Zone Spinning Top + "GTAR", // Garden Top Arrow "HYUU", // Hyudoro "GRWP", // Grow "POHB", // Shrink Poh-Bee @@ -4370,6 +4371,7 @@ state_t states[NUMSTATES] = {SPR_GTOP, 4, 1, {NULL}, 5, 1, S_GARDENTOP_SINKING1}, // S_GARDENTOP_SINKING3 {SPR_GTOP, FF_ANIMATE, 100, {A_Scream}, 5, 1, S_NULL}, // S_GARDENTOP_DEAD {SPR_BDRF, FF_FULLBRIGHT|FF_PAPERSPRITE|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 5, 2, S_NULL}, // S_GARDENTOPSPARK + {SPR_GTAR, FF_FULLBRIGHT, -1, {NULL}, 5, 2, S_NULL}, // S_GARDENTOPARROW {SPR_HYUU, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_HYUDORO @@ -24036,6 +24038,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_GARDENTOPARROW + -1, // doomednum + S_GARDENTOPARROW, // 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 + 8, // speed + 8*FRACUNIT, // radius + 54*FRACUNIT, // height + 1, // display offset + 100, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_DONTENCOREMAP|MF_NOSQUISH, // flags + S_NULL // raisestate + }, + { // MT_HYUDORO -1, // doomednum S_HYUDORO, // spawnstate diff --git a/src/info.h b/src/info.h index fb932676d..f4771bd9c 100644 --- a/src/info.h +++ b/src/info.h @@ -1137,6 +1137,7 @@ typedef enum sprite SPR_FLML, // Flame Shield speed lines SPR_FLMF, // Flame Shield flash SPR_GTOP, // Marble Garden Zone Spinning Top + SPR_GTAR, // Garden Top Arrow SPR_HYUU, // Hyudoro SPR_GRWP, // Grow SPR_POHB, // Shrink Poh-Bee @@ -4808,6 +4809,7 @@ typedef enum state S_GARDENTOP_SINKING3, S_GARDENTOP_DEAD, S_GARDENTOPSPARK, + S_GARDENTOPARROW, // Caked-Up Booty-Sheet Ghost S_HYUDORO, @@ -6457,6 +6459,7 @@ typedef enum mobj_type MT_BUBBLESHIELDTRAP, MT_GARDENTOP, MT_GARDENTOPSPARK, + MT_GARDENTOPARROW, MT_HYUDORO, MT_HYUDORO_CENTER, diff --git a/src/k_objects.h b/src/k_objects.h index b1fe2014b..be73d4949 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -19,6 +19,7 @@ mobj_t *Obj_GardenTopThrow(player_t *player); mobj_t *Obj_GardenTopDestroy(player_t *player); void Obj_GardenTopThink(mobj_t *top); void Obj_GardenTopSparkThink(mobj_t *spark); +void Obj_GardenTopArrowThink(mobj_t *arrow); boolean Obj_GardenTopPlayerIsGrinding(player_t *player); /* Shrink */ diff --git a/src/objects/gardentop.c b/src/objects/gardentop.c index 3d55e03d1..6b8cf780a 100644 --- a/src/objects/gardentop.c +++ b/src/objects/gardentop.c @@ -51,6 +51,14 @@ enum { #define spark_top(o) ((o)->target) #define spark_angle(o) ((o)->movedir) +enum { + ARROW_OVERHEAD, + ARROW_IN_FRONT, +}; + +#define arrow_top(o) ((o)->target) +#define arrow_kind(o) ((o)->reactiontime) + static inline player_t * get_rider_player (mobj_t *rider) { @@ -204,6 +212,49 @@ spawn_grind_spark (mobj_t *top) } } +static mobj_t * +spawn_arrow +( mobj_t * top, + UINT32 ff, + UINT8 kind) +{ + mobj_t *arrow = P_SpawnMobjFromMobj( + top, 0, 0, 0, MT_GARDENTOPARROW); + + P_SetTarget(&arrow_top(arrow), top); + arrow_kind(arrow) = kind; + + arrow->frame |= ff; + + return arrow; +} + +static void +spawn_arrow_pair (mobj_t *top) +{ + { + mobj_t *x = spawn_arrow(top, + FF_PAPERSPRITE, ARROW_OVERHEAD); + + // overhead arrow is slightly smaller + P_SetScale(x, (x->destscale = 3 * x->scale / 4)); + } + + { + mobj_t *x = spawn_arrow(top, + FF_FLOORSPRITE | FF_ADD, ARROW_IN_FRONT); + + x->renderflags |= RF_SLOPESPLAT | RF_NOSPLATBILLBOARD; + + // Let splat be flat, useful later for + // Obj_GardenTopArrowThink reverse gravity. + x->height = 0; + + // Make the arrow wider (sprite length is horizontal). + x->spriteyscale = 2*FRACUNIT; + } +} + static void loop_sfx ( mobj_t * top, @@ -361,6 +412,25 @@ tilt (mobj_t *top) } } +static void +anchor +( mobj_t * us, + mobj_t * them, + angle_t angle, + fixed_t radius) +{ + const fixed_t x = P_ReturnThrustX(us, angle, radius); + const fixed_t y = P_ReturnThrustY(us, angle, radius); + + /* FIXME: THIS FUNCTION FUCKING SUCKS */ + K_FlipFromObject(us, them); + + P_MoveOrigin(us, them->x + x, them->y + y, + them->z + K_FlipZOffset(us, them)); + + us->angle = angle; +} + static void anchor_top (mobj_t *top) { @@ -375,8 +445,7 @@ anchor_top (mobj_t *top) tilt(top); - P_MoveOrigin(top, rider->x, rider->y, - rider->z + K_FlipZOffset(top, rider)); + anchor(top, rider, rider->angle, 0); K_GenericExtraFlagsNoZAdjust(top, rider); @@ -447,17 +516,8 @@ anchor_spark (mobj_t *spark) mobj_t *rider = top_rider(top); player_t *player = get_rider_player(rider); - const angle_t angle = top->angle + spark_angle(spark); - const fixed_t x = P_ReturnThrustX(top, angle, spark->scale); - const fixed_t y = P_ReturnThrustY(top, angle, spark->scale); - - /* FIXME: THIS FUNCTION FUCKING SUCKS */ - K_FlipFromObject(spark, top); - - P_MoveOrigin(spark, top->x + x, top->y + y, - top->z + K_FlipZOffset(spark, top)); - - spark->angle = angle; + anchor(spark, top, + (top->angle + spark_angle(spark)), spark->scale); if (player) { @@ -472,6 +532,39 @@ anchor_spark (mobj_t *spark) } } +static void +anchor_arrow_overhead (mobj_t *arrow) +{ + mobj_t *top = arrow_top(arrow); + mobj_t *rider = top_rider(top); + + const fixed_t height = + top->height + rider->height + (3 * arrow->height / 4); + + arrow->sprzoff = top->sprzoff + + (height * P_MobjFlip(arrow)); + + anchor(arrow, top, rider->angle + ANGLE_180, 0); +} + +static void +anchor_arrow_in_front (mobj_t *arrow) +{ + mobj_t *top = arrow_top(arrow); + mobj_t *rider = top_rider(top); + + anchor(arrow, top, rider->angle, 2 * rider->radius); + + arrow->angle += ANGLE_90; + + if (P_IsObjectFlipped(arrow)) + { + arrow->angle += ANGLE_180; + } + + arrow->floorspriteslope = rider->standingslope; +} + void Obj_GardenTopDeploy (mobj_t *rider) { @@ -497,6 +590,8 @@ Obj_GardenTopDeploy (mobj_t *rider) } spawn_spark_circle(top, 6); + + spawn_arrow_pair(top); } mobj_t * @@ -605,6 +700,38 @@ Obj_GardenTopSparkThink (mobj_t *spark) } } +void +Obj_GardenTopArrowThink (mobj_t *arrow) +{ + mobj_t *top = arrow_top(arrow); + mobj_t *rider = top ? top_rider(top) : NULL; + + if (!rider) + { + P_RemoveMobj(arrow); + return; + } + + switch (arrow_kind(arrow)) + { + case ARROW_OVERHEAD: + anchor_arrow_overhead(arrow); + break; + + case ARROW_IN_FRONT: + anchor_arrow_in_front(arrow); + break; + } + + if (rider->player) + { + // Don't show for other players + arrow->renderflags = + (arrow->renderflags & ~(RF_DONTDRAW)) | + (RF_DONTDRAW & ~(K_GetPlayerDontDrawFlag(rider->player))); + } +} + boolean Obj_GardenTopPlayerIsGrinding (player_t *player) { diff --git a/src/p_mobj.c b/src/p_mobj.c index f8c6ec400..bd50a9a51 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8394,6 +8394,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj) Obj_GardenTopSparkThink(mobj); break; } + case MT_GARDENTOPARROW: + { + Obj_GardenTopArrowThink(mobj); + break; + } case MT_HYUDORO: { Obj_HyudoroThink(mobj);