mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Ground follower mode
This commit is contained in:
parent
6e3c4dbc34
commit
4b70a64b3f
6 changed files with 134 additions and 15 deletions
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
108
src/k_follower.c
108
src/k_follower.c
|
|
@ -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!
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue