Podium cutscene basics

- Bots follow a slightly more strict path via waypoints
- Bots decide their starting waypoint path depending on their position. (The 1st place winner will start by chasing waypoint ID 1, etc)
- The map used for podium sequence can be decided via `PodiumMap = x` in MainCfg.

TODO:
- Camera work
- Add Lose / Win animation states when stopping at final waypoint
- Adjust physics so that the bots can follow the path more strictly in this mode
- Actually go to it after GP
This commit is contained in:
Sally Coolatta 2022-12-10 17:28:41 -05:00
parent 9f46c705f0
commit 4a8dd02320
9 changed files with 218 additions and 1 deletions

View file

@ -2842,6 +2842,10 @@ void readmaincfg(MYFILE *f, boolean mainfile)
{
tutorialmap = Z_StrDup(word2);
}
else if (fastcmp(word, "PODIUMMAP"))
{
podiummap = Z_StrDup(word2);
}
else
deh_warning("Maincfg: unknown word '%s'", word);
}

View file

@ -210,6 +210,8 @@ extern char * bootmap; //bootmap for loading a map on startup
extern char * tutorialmap; // map to load for tutorial
extern boolean tutorialmode; // are we in a tutorial right now?
extern char * podiummap; // map to load for podium
extern boolean looptitle;
// CTF colors.

View file

@ -164,6 +164,8 @@ char * bootmap = NULL; //bootmap for loading a map on startup
char * tutorialmap = NULL; // map to load for tutorial
boolean tutorialmode = false; // are we in a tutorial right now?
char * podiummap = NULL; // map to load for podium
boolean looptitle = true;
UINT16 skincolor_redteam = SKINCOLOR_RED;

View file

@ -261,6 +261,9 @@ void K_UpdateMatchRaceBots(void)
--------------------------------------------------*/
boolean K_PlayerUsesBotMovement(player_t *player)
{
if (K_PodiumSequence() == true)
return true;
if (player->exiting)
return true;
@ -1264,6 +1267,54 @@ static INT32 K_HandleBotReverse(player_t *player, ticcmd_t *cmd, botprediction_t
return turnamt;
}
/*--------------------------------------------------
static void K_BotPodiumTurning(player_t *player, ticcmd_t *cmd)
Calculates bot turning for the podium cutscene.
--------------------------------------------------*/
static void K_BotPodiumTurning(player_t *player, ticcmd_t *cmd)
{
const angle_t destAngle = R_PointToAngle2(
player->mo->x, player->mo->y,
player->currentwaypoint->mobj->x, player->currentwaypoint->mobj->y
);
const INT32 delta = AngleDeltaSigned(destAngle, player->mo->angle);
const INT16 handling = K_GetKartTurnValue(player, KART_FULLTURN);
fixed_t mul = FixedDiv(delta, (angle_t)(handling << TICCMD_REDUCE));
if (mul > FRACUNIT)
{
mul = FRACUNIT;
}
if (mul < -FRACUNIT)
{
mul = -FRACUNIT;
}
cmd->turning = FixedMul(mul, KART_FULLTURN);
}
/*--------------------------------------------------
static void K_BuildBotPodiumTiccmd(player_t *player, ticcmd_t *cmd)
Calculates all bot movement for the podium cutscene.
--------------------------------------------------*/
static void K_BuildBotPodiumTiccmd(player_t *player, ticcmd_t *cmd)
{
if (player->currentwaypoint == NULL)
{
// We've reached the end of our path.
// Simply stop moving.
return;
}
cmd->forwardmove = MAXPLMOVE;
cmd->buttons |= BT_ACCELERATE;
K_BotPodiumTurning(player, cmd);
}
/*--------------------------------------------------
void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
@ -1294,6 +1345,12 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd)
return;
}
if (K_PodiumSequence() == true)
{
K_BuildBotPodiumTiccmd(player, cmd);
return;
}
if (!(gametyperules & GTR_BOTS) // No bot behaviors
|| K_GetNumWaypoints() == 0 // No waypoints
|| leveltime <= introtime // During intro camera
@ -1556,12 +1613,21 @@ void K_UpdateBotGameplayVars(player_t *player)
{
const line_t *botController;
player->botvars.controller = UINT16_MAX;
player->botvars.rubberband = FRACUNIT;
if (gamestate != GS_LEVEL || !player->mo)
{
// Not in the level.
return;
}
if (K_PodiumSequence() == true)
{
// We don't want these during podium.
return;
}
botController = K_FindBotController(player->mo);
player->botvars.controller = botController ? (botController - lines) : UINT16_MAX;

View file

@ -51,6 +51,19 @@
// comeback is Battle Mode's karma comeback, also bool
// mapreset is set when enough players fill an empty server
boolean K_PodiumSequence(void)
{
// FIXME: Cache so we don't have to iterate all map headers every time
INT32 podiumMapNum = nummapheaders;
if (podiummap && ((podiumMapNum = G_MapNumber(podiummap)) < nummapheaders))
{
return (gamemap == podiumMapNum+1);
}
return false;
}
boolean K_IsDuelItem(mobjtype_t type)
{
switch (type)
@ -354,6 +367,12 @@ boolean K_IsPlayerLosing(player_t *player)
INT32 winningpos = 1;
UINT8 i, pcount = 0;
if (K_PodiumSequence() == true)
{
// Need to be in top 3 to win.
return (player->position > 3);
}
if (player->pflags & PF_NOCONTEST)
return true;
@ -8449,6 +8468,59 @@ static waypoint_t *K_GetPlayerNextWaypoint(player_t *player)
return bestwaypoint;
}
static void K_UpdatePodiumWaypoint(player_t *const player, waypoint_t *const waypoint)
{
// Set the new waypoint.
player->currentwaypoint = waypoint;
if ((waypoint == NULL)
|| (waypoint->nextwaypoints == NULL)
|| (waypoint->numnextwaypoints == 0U))
{
// No waypoint, or no next waypoint.
player->nextwaypoint = NULL;
return;
}
// Simply use the first available next waypoint.
// No need for split paths in these cutscenes.
player->nextwaypoint = waypoint->nextwaypoints[0];
}
static void K_UpdatePodiumWaypoints(player_t *const player)
{
if ((player != NULL) && (player->mo != NULL))
{
if ((player->currentwaypoint == NULL)
&& (player->position > 0 && player->position <= MAXPLAYERS)
&& (leveltime <= 2))
{
// Initialize our first waypoint to the one that
// matches our position.
K_UpdatePodiumWaypoint(player, K_GetWaypointFromID(player->position));
}
if (player->currentwaypoint != NULL)
{
const fixed_t xydist = P_AproxDistance(
player->mo->x - player->currentwaypoint->mobj->x,
player->mo->y - player->currentwaypoint->mobj->y
);
const fixed_t xyzdist = P_AproxDistance(
xydist,
player->mo->z - player->currentwaypoint->mobj->z
);
//const fixed_t speed = P_AproxDistance(player->mo->momx, player->mo->momy);
if (xyzdist <= player->mo->radius + player->currentwaypoint->mobj->radius)
{
// Reached waypoint, go to the next waypoint.
K_UpdatePodiumWaypoint(player, player->nextwaypoint);
}
}
}
}
/*--------------------------------------------------
void K_UpdateDistanceFromFinishLine(player_t *const player)
@ -8462,6 +8534,12 @@ static waypoint_t *K_GetPlayerNextWaypoint(player_t *player)
--------------------------------------------------*/
void K_UpdateDistanceFromFinishLine(player_t *const player)
{
if (K_PodiumSequence() == true)
{
K_UpdatePodiumWaypoints(player);
return;
}
if ((player != NULL) && (player->mo != NULL))
{
waypoint_t *finishline = K_GetFinishLineWaypoint();
@ -9261,7 +9339,28 @@ void K_KartUpdatePosition(player_t *player)
realplayers++;
if (gametyperules & GTR_CIRCUIT)
if (K_PodiumSequence() == true)
{
if (players[i].score > player->score)
{
// Final score is the important part.
position++;
}
else if (players[i].score == player->score)
{
if (players[i].bot == false && player->bot == true)
{
// Bots are never as important as players.
position++;
}
else if (i < player - players)
{
// Port priority is the final tie breaker.
position++;
}
}
}
else if (gametyperules & GTR_CIRCUIT)
{
if (player->exiting) // End of match standings
{

View file

@ -37,6 +37,8 @@ Make sure this matches the actual number of states
#define STUMBLE_STEEP_VAL ANG60
#define STUMBLE_STEEP_VAL_AIR (ANG30 + ANG10)
boolean K_PodiumSequence(void);
player_t *K_GetItemBoxPlayer(mobj_t *mobj);
angle_t K_ReflectAngle(angle_t angle, angle_t against, fixed_t maxspeed, fixed_t yourspeed);

View file

@ -235,6 +235,29 @@ INT32 K_GetWaypointID(waypoint_t *waypoint)
return waypointid;
}
/*--------------------------------------------------
waypoint_t *K_GetWaypointFromID(INT32 waypointID)
See header file for description.
--------------------------------------------------*/
waypoint_t *K_GetWaypointFromID(INT32 waypointID)
{
waypoint_t *waypoint = NULL;
size_t i = SIZE_MAX;
for (i = 0; i < numwaypoints; i++)
{
waypoint = &waypointheap[i];
if (K_GetWaypointID(waypoint) == waypointID)
{
return waypoint;
}
}
return NULL;
}
/*--------------------------------------------------
UINT32 K_GetCircuitLength(void)

View file

@ -141,9 +141,25 @@ INT32 K_GetWaypointNextID(waypoint_t *waypoint);
Return:-
The waypoint ID, -1 if there is no waypoint or mobj.
--------------------------------------------------*/
INT32 K_GetWaypointID(waypoint_t *waypoint);
/*--------------------------------------------------
waypoint_t *K_GetWaypointFromID(INT32 waypointID)
Returns the first waypoint with the specified ID.
Input Arguments:-
waypointID - The ID of the waypoint to get
Return:-
The first waypoint with this ID, NULL if the ID doesn't exist at all in the map
--------------------------------------------------*/
waypoint_t *K_GetWaypointFromID(INT32 waypointID);
/*--------------------------------------------------
UINT32 K_GetCircuitLength(void)

View file

@ -223,6 +223,9 @@ int LUA_PushGlobals(lua_State *L, const char *word)
} else if (fastcmp(word,"tutorialmode")) {
lua_pushboolean(L, tutorialmode);
return 1;
} else if (fastcmp(word,"podiummap")) {
lua_pushstring(L, podiummap);
return 1;
// end map vars
// begin CTF colors
} else if (fastcmp(word,"skincolor_redteam")) {