Ground follower mode

This commit is contained in:
Sally Coolatta 2022-05-23 15:51:00 -04:00
parent 6e3c4dbc34
commit 4b70a64b3f
6 changed files with 134 additions and 15 deletions

View file

@ -3819,6 +3819,7 @@ void readfollower(MYFILE *f)
s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
// Ready the default variables for followers. We will overwrite them as we go! We won't set the name or states RIGHT HERE as this is handled down instead.
followers[numfollowers].mode = FOLLOWERMODE_FLOAT;
followers[numfollowers].scale = FRACUNIT;
followers[numfollowers].bubblescale = 0; // No bubble by default
followers[numfollowers].atangle = FixedAngle(230 * FRACUNIT);
@ -3865,6 +3866,18 @@ void readfollower(MYFILE *f)
strcpy(followers[numfollowers].name, word2);
nameset = true;
}
else if (fastcmp(word, "MODE"))
{
if (word2)
strupr(word2);
if (fastcmp(word2, "FLOAT") || fastcmp(word2, "DEFAULT"))
followers[numfollowers].mode = FOLLOWERMODE_FLOAT;
else if (fastcmp(word2, "GROUND"))
followers[numfollowers].mode = FOLLOWERMODE_GROUND;
else
deh_warning("Follower %d: unknown follower mode '%s'", numfollowers, word2);
}
else if (fastcmp(word, "DEFAULTCOLOR"))
{
followers[numfollowers].defaultcolor = get_number(word2);
@ -3997,11 +4010,18 @@ void readfollower(MYFILE *f)
// fallbacks for variables
// Print a warning if the variable is on a weird value and set it back to the minimum available if that's the case.
if (followers[numfollowers].mode < FOLLOWERMODE_FLOAT || followers[numfollowers].mode >= FOLLOWERMODE__MAX)
{
followers[numfollowers].mode = FOLLOWERMODE_FLOAT;
deh_warning("Follower '%s': Value for 'mode' should be between %d and %d.", dname, FOLLOWERMODE_FLOAT, FOLLOWERMODE__MAX-1);
}
#define FALLBACK(field, field2, threshold, set) \
if ((signed)followers[numfollowers].field < threshold) \
{ \
followers[numfollowers].field = set; \
deh_warning("Follower '%s': Value for '%s' is too low! Minimum should be %d. Value was overwritten to %d.", dname, field2, set, set); \
deh_warning("Follower '%s': Value for '%s' is too low! Minimum should be %d. Value was overwritten to %d.", dname, field2, threshold, set); \
} \
FALLBACK(dist, "DIST", 0, 0);
@ -4016,6 +4036,8 @@ if ((signed)followers[numfollowers].field < threshold) \
FALLBACK(scale, "SCALE", 1, 1); // No null/negative scale
FALLBACK(bubblescale, "BUBBLESCALE", 0, 0); // No negative scale
#undef FALLBACK
// Special case for color I suppose
if (followers[numfollowers].defaultcolor > (unsigned)(numskincolors-1))
{
@ -4023,8 +4045,6 @@ if ((signed)followers[numfollowers].field < threshold) \
deh_warning("Follower \'%s\': Value for 'color' should be between 1 and %d.\n", dname, numskincolors-1);
}
#undef FALLBACK
// also check if we forgot states. If we did, we will set any missing state to the follower's idlestate.
// Print a warning in case we don't have a fallback and set the state to S_INVISIBLE (rather than S_NULL) if unavailable.

View file

@ -1308,7 +1308,7 @@ void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt)
K_BotItemGenericOrbitShield(player, cmd);
}
else if (player->position != 1) // Hold onto orbiting items when in 1st :)
/* FALL-THRU */
/* FALLTHRU */
case KITEM_BALLHOG:
{
K_BotItemOrbinaut(player, cmd);

View file

@ -7,6 +7,7 @@
#include "doomdef.h"
#include "g_game.h"
#include "g_demo.h"
#include "r_main.h"
#include "r_skins.h"
#include "p_local.h"
#include "p_mobj.h"
@ -185,7 +186,9 @@ void K_HandleFollower(player_t *player)
follower_t fl;
angle_t an;
fixed_t zoffs;
fixed_t ourheight;
fixed_t sx, sy, sz, deltaz;
fixed_t fh = INT32_MIN, ch = INT32_MAX;
UINT16 color;
fixed_t bubble; // bubble scale (0 if no bubble)
@ -235,17 +238,39 @@ void K_HandleFollower(player_t *player)
deltaz = (player->mo->z - player->mo->old_z);
// for the z coordinate, don't be a doof like Steel and forget that MFE_VERTICALFLIP exists :P
sz = player->mo->z + player->mo->momz + FixedMul(player->mo->scale, zoffs) * P_MobjFlip(player->mo);
sz = player->mo->z + player->mo->momz + FixedMul(player->mo->scale, zoffs * P_MobjFlip(player->mo));
ourheight = FixedMul(fl.height, player->mo->scale);
if (player->mo->eflags & MFE_VERTICALFLIP)
{
sz += FixedMul(fl.height, player->mo->scale);
sz += ourheight;
}
// finally, add a cool floating effect to the z height.
// not stolen from k_kart I swear!!
fh = player->mo->floorz;
ch = player->mo->ceilingz - ourheight;
switch (fl.mode)
{
fixed_t sine = FixedMul(fl.bobamp, FINESINE(((FixedMul(4 * M_TAU_FIXED, fl.bobspeed) * leveltime) >> ANGLETOFINESHIFT) & FINEMASK));
sz += FixedMul(player->mo->scale, sine) * P_MobjFlip(player->mo);
case FOLLOWERMODE_GROUND:
{
if (player->mo->eflags & MFE_VERTICALFLIP)
{
sz = ch;
}
else
{
sz = fh;
}
break;
}
case FOLLOWERMODE_FLOAT:
default:
{
// finally, add a cool floating effect to the z height.
// not stolen from k_kart I swear!!
fixed_t sine = FixedMul(fl.bobamp, FINESINE(((FixedMul(4 * M_TAU_FIXED, fl.bobspeed) * leveltime) >> ANGLETOFINESHIFT) & FINEMASK));
sz += FixedMul(player->mo->scale, sine) * P_MobjFlip(player->mo);
break;
}
}
// Set follower colour
@ -317,11 +342,39 @@ void K_HandleFollower(player_t *player)
}
// move the follower next to us (yes, this is really basic maths but it looks pretty damn clean in practice)!
// 02/09/2021: cast lag to int32 otherwise funny things happen since it was changed to uint32 in the struct
player->follower->momx = FixedDiv(sx - player->follower->x, fl.horzlag);
player->follower->momy = FixedDiv(sy - player->follower->y, fl.horzlag);
player->follower->z += FixedDiv(deltaz, fl.vertlag);
player->follower->momz = FixedDiv(sz - player->follower->z, fl.vertlag);
if (fl.mode == FOLLOWERMODE_GROUND)
{
sector_t *sec = R_PointInSubsector(sx, sy)->sector;
fh = min(fh, P_GetFloorZ(player->follower, sec, sx, sy, NULL));
ch = max(ch, P_GetCeilingZ(player->follower, sec, sx, sy, NULL) - ourheight);
if (P_IsObjectOnGround(player->mo) == false)
{
// In the air, match their momentum.
player->follower->momz = player->mo->momz;
}
else
{
fixed_t fg = P_GetMobjGravity(player->mo);
fixed_t fz = P_GetMobjZMovement(player->follower);
player->follower->momz = fz;
// Player is on the ground ... try to get the follower
// back to the ground also if it is above it.
player->follower->momz += FixedDiv(fg * 6, fl.vertlag); // Scaled against the default value of vertlag
}
}
else
{
player->follower->momz = FixedDiv(sz - player->follower->z, fl.vertlag);
}
if (player->mo->colorized)
{
@ -347,7 +400,15 @@ void K_HandleFollower(player_t *player)
}
// if we're moving let's make the angle the direction we're moving towards. This is to avoid drifting / reverse looking awkward.
destAngle = K_MomentumAngle(player->follower);
if (FixedHypot(player->follower->momx, player->follower->momy) >= player->mo->scale)
{
destAngle = R_PointToAngle2(0, 0, player->follower->momx, player->follower->momy);
}
else
{
// Face the player's angle when standing still.
destAngle = player->mo->angle;
}
// Sal: Turn the follower around when looking backwards.
if ( player->cmd.buttons & BT_LOOKBACK )
@ -363,6 +424,35 @@ void K_HandleFollower(player_t *player)
player->follower->angle += FixedDiv(angleDiff, fl.anglelag);
}
// Ground follower slope rotation
if (fl.mode == FOLLOWERMODE_GROUND)
{
if (player->follower->z <= fh)
{
player->follower->z = fh;
if (player->follower->momz < 0)
{
player->follower->momz = 0;
}
}
else if (player->follower->z >= ch)
{
player->follower->z = ch;
if (player->follower->momz > 0)
{
player->follower->momz = 0;
}
}
K_CalculateBananaSlope(
player->follower,
player->follower->x, player->follower->y, player->follower->z,
player->follower->radius, ourheight,
(player->mo->eflags & MFE_VERTICALFLIP),
false
);
}
// Finally, if the follower has bubbles, move them, set their scale, etc....
// This is what I meant earlier by it being easier, now we can just use this weird lil loop to get the job done!

View file

@ -22,6 +22,13 @@
extern CV_PossibleValue_t Followercolor_cons_t[]; // follower colours table, not a duplicate because of the "Match" option.
typedef enum
{
FOLLOWERMODE_FLOAT, // Default behavior, floats in the position you set it to.
FOLLOWERMODE_GROUND, // Snaps to the ground & rotates with slopes.
FOLLOWERMODE__MAX
} followermode_t;
//
// We'll define these here because they're really just a mobj that'll follow some rules behind a player
//
@ -31,6 +38,7 @@ typedef struct follower_s
char name[SKINNAMESIZE+1]; // Name. This is used for the menus. We'll just follow the same rules as skins for this.
skincolornum_t defaultcolor; // default color for menus.
followermode_t mode; // Follower behavior modifier.
fixed_t scale; // Scale relative to the player's.
fixed_t bubblescale; // Bubble scale relative to the player scale. If not set, no bubble will spawn (default)

View file

@ -3347,7 +3347,7 @@ fixed_t K_3dKartMovement(player_t *player)
angle_t K_MomentumAngle(mobj_t *mo)
{
if (mo->momx || mo->momy)
if (FixedHypot(mo->momx, mo->momy) >= mo->scale)
{
return R_PointToAngle2(0, 0, mo->momx, mo->momy);
}
@ -6244,7 +6244,7 @@ static fixed_t K_BananaSlopeZ(pslope_t *slope, fixed_t x, fixed_t y, fixed_t z,
return P_GetZAt(slope, testx, testy, z);
}
static void K_CalculateBananaSlope(mobj_t *mobj, fixed_t x, fixed_t y, fixed_t z, fixed_t radius, fixed_t height, boolean flip, boolean player)
void K_CalculateBananaSlope(mobj_t *mobj, fixed_t x, fixed_t y, fixed_t z, fixed_t radius, fixed_t height, boolean flip, boolean player)
{
fixed_t newz;
sector_t *sec;

View file

@ -94,6 +94,7 @@ void K_KillBananaChain(mobj_t *banana, mobj_t *inflictor, mobj_t *source);
void K_UpdateHnextList(player_t *player, boolean clean);
void K_DropHnextList(player_t *player, boolean keepshields);
void K_RepairOrbitChain(mobj_t *orbit);
void K_CalculateBananaSlope(mobj_t *mobj, fixed_t x, fixed_t y, fixed_t z, fixed_t radius, fixed_t height, boolean flip, boolean player);
player_t *K_FindJawzTarget(mobj_t *actor, player_t *source);
INT32 K_GetKartRingPower(player_t *player, boolean boosted);
void K_UpdateDistanceFromFinishLine(player_t *const player);