mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Merge branch 'master' of https://git.do.srb2.org/KartKrew/Kart into will-it-blend
# Conflicts: # src/k_podium.c
This commit is contained in:
commit
388b14e956
21 changed files with 1622 additions and 865 deletions
|
|
@ -142,8 +142,8 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
|
|||
k_profiles.c
|
||||
k_specialstage.c
|
||||
k_roulette.c
|
||||
k_podium.c
|
||||
k_rank.c
|
||||
k_podium.cpp
|
||||
k_rank.cpp
|
||||
k_vote.c
|
||||
k_serverstats.c
|
||||
k_zvote.c
|
||||
|
|
|
|||
|
|
@ -802,7 +802,7 @@ consvar_t cv_kartdebugwaypoints = OnlineCheat("debugwaypoints", "Off").values({{
|
|||
|
||||
extern CV_PossibleValue_t numlaps_cons_t[];
|
||||
void NumLaps_OnChange(void);
|
||||
consvar_t cv_numlaps = OnlineCheat("numlaps", "Map default").values(numlaps_cons_t).onchange(NumLaps_OnChange).save().description("Race maps always have the same number of laps");
|
||||
consvar_t cv_numlaps = OnlineCheat("numlaps", "Map default").values(numlaps_cons_t).onchange(NumLaps_OnChange).description("Race maps always have the same number of laps");
|
||||
|
||||
consvar_t cv_restrictskinchange = OnlineCheat("restrictskinchange", "Yes").yes_no().description("Don't let players change their skin in the middle of gameplay");
|
||||
consvar_t cv_spbtest = OnlineCheat("spbtest", "Off").on_off().description("SPB can never target a player");
|
||||
|
|
|
|||
11
src/g_game.c
11
src/g_game.c
|
|
@ -4199,7 +4199,10 @@ static void G_DoCompleted(void)
|
|||
if (intertype == int_none)
|
||||
{
|
||||
G_UpdateVisited();
|
||||
K_UpdateGPRank();
|
||||
if (grandprixinfo.gp == true)
|
||||
{
|
||||
K_UpdateGPRank(&grandprixinfo.rank);
|
||||
}
|
||||
G_AfterIntermission();
|
||||
}
|
||||
else
|
||||
|
|
@ -5857,7 +5860,13 @@ char *G_BuildMapTitle(INT32 mapnum)
|
|||
char *title = NULL;
|
||||
|
||||
if (!mapnum || mapnum > nummapheaders || !mapheaderinfo[mapnum-1])
|
||||
{
|
||||
#ifdef PARANOIA
|
||||
I_Error("G_BuildMapTitle: Internal map ID %d not found (nummapheaders = %d)", mapnum-1, nummapheaders);
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (strcmp(mapheaderinfo[mapnum-1]->lvlttl, ""))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -40,7 +40,23 @@ UINT8 numtargets = 0; // Capsules busted
|
|||
INT32 K_StartingBumperCount(void)
|
||||
{
|
||||
if (battleprisons)
|
||||
return 0; // always 1 hit in Prison Break
|
||||
{
|
||||
if (grandprixinfo.gp)
|
||||
{
|
||||
switch (grandprixinfo.gamespeed)
|
||||
{
|
||||
case KARTSPEED_HARD:
|
||||
return (grandprixinfo.masterbots == true) ? 0 : 1;
|
||||
case KARTSPEED_NORMAL:
|
||||
return 2;
|
||||
case KARTSPEED_EASY:
|
||||
return 3;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 2; // Normal
|
||||
}
|
||||
|
||||
return cv_kartbumpers.value;
|
||||
}
|
||||
|
|
|
|||
130
src/k_hud.c
130
src/k_hud.c
|
|
@ -1976,9 +1976,8 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT32 splitflags, U
|
|||
}
|
||||
}
|
||||
|
||||
static fixed_t K_DrawKartPositionNumPatch(UINT8 num, UINT8 *color, fixed_t x, fixed_t y, fixed_t scale, INT32 flags)
|
||||
static fixed_t K_DrawKartPositionNumPatch(UINT8 num, UINT8 splitIndex, UINT8 *color, fixed_t x, fixed_t y, fixed_t scale, INT32 flags)
|
||||
{
|
||||
const UINT8 splitIndex = (r_splitscreen > 0) ? 1 : 0;
|
||||
fixed_t w = FRACUNIT;
|
||||
fixed_t h = FRACUNIT;
|
||||
INT32 overlayFlags[2];
|
||||
|
|
@ -2023,14 +2022,76 @@ static fixed_t K_DrawKartPositionNumPatch(UINT8 num, UINT8 *color, fixed_t x, fi
|
|||
return x;
|
||||
}
|
||||
|
||||
void K_DrawKartPositionNumXY(
|
||||
UINT8 num,
|
||||
UINT8 splitIndex,
|
||||
fixed_t fx, fixed_t fy, fixed_t scale, INT32 fflags,
|
||||
tic_t counter, boolean subtract,
|
||||
boolean exit, boolean lastLap, boolean losing
|
||||
)
|
||||
{
|
||||
counter /= 3; // Alternate colors every three frames
|
||||
|
||||
UINT8 *color = NULL;
|
||||
if (exit && num == 1)
|
||||
{
|
||||
// 1st place winner? You get rainbows!!
|
||||
color = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_POSNUM_BEST1 + (counter % 6), GTC_CACHE);
|
||||
}
|
||||
else if (exit || lastLap)
|
||||
{
|
||||
// On the final lap, or already won.
|
||||
boolean useRedNums = losing;
|
||||
|
||||
if (subtract)
|
||||
{
|
||||
// Subtracting RED will look BLUE, and vice versa.
|
||||
useRedNums = !useRedNums;
|
||||
}
|
||||
|
||||
if (useRedNums == true)
|
||||
{
|
||||
color = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_POSNUM_LOSE1 + (counter % 3), GTC_CACHE);
|
||||
}
|
||||
else
|
||||
{
|
||||
color = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_POSNUM_WIN1 + (counter % 3), GTC_CACHE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
color = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_POSNUM, GTC_CACHE);
|
||||
}
|
||||
|
||||
if ((fflags & V_SNAPTORIGHT) == 0)
|
||||
{
|
||||
UINT8 adjustNum = num;
|
||||
do
|
||||
{
|
||||
fixed_t w = SHORT(kp_positionnum[adjustNum % 10][0][splitIndex]->width) * scale;
|
||||
fx += w;
|
||||
adjustNum /= 10;
|
||||
} while (adjustNum);
|
||||
}
|
||||
|
||||
// Draw the number
|
||||
do
|
||||
{
|
||||
fx = K_DrawKartPositionNumPatch(
|
||||
(num % 10), splitIndex, color,
|
||||
fx, fy, scale, V_SPLITSCREEN|fflags
|
||||
);
|
||||
num /= 10;
|
||||
} while (num);
|
||||
}
|
||||
|
||||
static void K_DrawKartPositionNum(UINT8 num)
|
||||
{
|
||||
const tic_t counter = (leveltime / 3); // Alternate colors every three frames
|
||||
UINT8 splitIndex = (r_splitscreen > 0) ? 1 : 0;
|
||||
fixed_t scale = FRACUNIT;
|
||||
fixed_t fx = 0, fy = 0;
|
||||
transnum_t trans = 0;
|
||||
INT32 fflags = 0;
|
||||
UINT8 *color = NULL;
|
||||
|
||||
if (stplyr->lives <= 0 && stplyr->playerstate == PST_DEAD)
|
||||
{
|
||||
|
|
@ -2110,57 +2171,16 @@ static void K_DrawKartPositionNum(UINT8 num)
|
|||
fflags |= (trans << V_ALPHASHIFT);
|
||||
}
|
||||
|
||||
if (stplyr->exiting && num == 1)
|
||||
{
|
||||
// 1st place winner? You get rainbows!!
|
||||
color = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_POSNUM_BEST1 + (counter % 6), GTC_CACHE);
|
||||
}
|
||||
else if (stplyr->laps >= numlaps || stplyr->exiting)
|
||||
{
|
||||
// On the final lap, or already won.
|
||||
boolean useRedNums = K_IsPlayerLosing(stplyr);
|
||||
|
||||
if ((mapheaderinfo[gamemap - 1]->levelflags & LF_SUBTRACTNUM) == LF_SUBTRACTNUM)
|
||||
{
|
||||
// Subtracting RED will look BLUE, and vice versa.
|
||||
useRedNums = !useRedNums;
|
||||
}
|
||||
|
||||
if (useRedNums == true)
|
||||
{
|
||||
color = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_POSNUM_LOSE1 + (counter % 3), GTC_CACHE);
|
||||
}
|
||||
else
|
||||
{
|
||||
color = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_POSNUM_WIN1 + (counter % 3), GTC_CACHE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
color = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_POSNUM, GTC_CACHE);
|
||||
}
|
||||
|
||||
if ((fflags & V_SNAPTORIGHT) == 0)
|
||||
{
|
||||
const UINT8 splitIndex = (r_splitscreen > 0) ? 1 : 0;
|
||||
UINT8 adjustNum = num;
|
||||
do
|
||||
{
|
||||
fixed_t w = SHORT(kp_positionnum[adjustNum % 10][0][splitIndex]->width) * scale;
|
||||
fx += w;
|
||||
adjustNum /= 10;
|
||||
} while (adjustNum);
|
||||
}
|
||||
|
||||
// Draw the number
|
||||
do
|
||||
{
|
||||
fx = K_DrawKartPositionNumPatch(
|
||||
(num % 10), color,
|
||||
fx, fy, scale, V_SPLITSCREEN|fflags
|
||||
);
|
||||
num /= 10;
|
||||
} while (num);
|
||||
K_DrawKartPositionNumXY(
|
||||
num,
|
||||
splitIndex,
|
||||
fx, fy, scale, fflags,
|
||||
leveltime,
|
||||
((mapheaderinfo[gamemap - 1]->levelflags & LF_SUBTRACTNUM) == LF_SUBTRACTNUM),
|
||||
stplyr->exiting,
|
||||
(stplyr->laps >= numlaps),
|
||||
K_IsPlayerLosing(stplyr)
|
||||
);
|
||||
}
|
||||
|
||||
static boolean K_drawKartPositionFaces(void)
|
||||
|
|
|
|||
|
|
@ -54,6 +54,14 @@ void K_drawButton(fixed_t x, fixed_t y, INT32 flags, patch_t *button[2], boolean
|
|||
void K_drawButtonAnim(INT32 x, INT32 y, INT32 flags, patch_t *button[2], tic_t animtic);
|
||||
void K_DrawSticker(INT32 x, INT32 y, INT32 width, INT32 flags, boolean isSmall);
|
||||
|
||||
void K_DrawKartPositionNumXY(
|
||||
UINT8 num,
|
||||
UINT8 splitIndex,
|
||||
fixed_t fx, fixed_t fy, fixed_t scale, INT32 fflags,
|
||||
tic_t counter, boolean subtract,
|
||||
boolean exit, boolean lastLap, boolean losing
|
||||
);
|
||||
|
||||
extern patch_t *kp_capsuletarget_arrow[2][2];
|
||||
extern patch_t *kp_capsuletarget_icon[2];
|
||||
extern patch_t *kp_capsuletarget_far[2][2];
|
||||
|
|
|
|||
53
src/k_kart.c
53
src/k_kart.c
|
|
@ -3128,7 +3128,7 @@ mobj_t *K_GetGardenTop(player_t *player)
|
|||
static fixed_t K_FlameShieldDashVar(INT32 val)
|
||||
{
|
||||
// 1 second = 75% + 50% top speed
|
||||
return (3*FRACUNIT/4) + (((val * FRACUNIT) / TICRATE) / 2);
|
||||
return (3*FRACUNIT/4) + (((val * FRACUNIT) / TICRATE));
|
||||
}
|
||||
|
||||
INT16 K_GetSpindashChargeTime(player_t *player)
|
||||
|
|
@ -4232,8 +4232,8 @@ void K_UpdateSliptideZipIndicator(player_t *player)
|
|||
mobj->angle = momentumAngle + ANGLE_90;
|
||||
P_SetScale(mobj, 3 * player->mo->scale / 2);
|
||||
|
||||
// No stored boost
|
||||
if (player->sliptideZip == 0)
|
||||
// No stored boost (or negligible enough that it might be a mistake)
|
||||
if (player->sliptideZip <= HIDEWAVEDASHCHARGE)
|
||||
{
|
||||
mobj->renderflags |= RF_DONTDRAW;
|
||||
mobj->frame = 7;
|
||||
|
|
@ -9892,7 +9892,7 @@ static void K_KartDrift(player_t *player, boolean onground)
|
|||
{
|
||||
if (!keepsliptide && K_IsLosingSliptideZip(player) && player->sliptideZip > 0)
|
||||
{
|
||||
if (!S_SoundPlaying(player->mo, sfx_waved2))
|
||||
if (player->sliptideZip > HIDEWAVEDASHCHARGE && !S_SoundPlaying(player->mo, sfx_waved2))
|
||||
S_StartSoundAtVolume(player->mo, sfx_waved2, 255); // Losing combo time, going to boost
|
||||
S_StopSoundByID(player->mo, sfx_waved1);
|
||||
S_StopSoundByID(player->mo, sfx_waved4);
|
||||
|
|
@ -9954,7 +9954,7 @@ static void K_KartDrift(player_t *player, boolean onground)
|
|||
player->sliptideZipDelay = 0;
|
||||
S_StopSoundByID(player->mo, sfx_waved2);
|
||||
S_StopSoundByID(player->mo, sfx_waved4);
|
||||
if (!S_SoundPlaying(player->mo, sfx_waved1))
|
||||
if (player->sliptideZip > HIDEWAVEDASHCHARGE && !S_SoundPlaying(player->mo, sfx_waved1))
|
||||
S_StartSoundAtVolume(player->mo, sfx_waved1, 255); // Charging
|
||||
}
|
||||
|
||||
|
|
@ -10193,7 +10193,7 @@ static INT32 K_FlameShieldMax(player_t *player)
|
|||
UINT32 distv = 1024; // Pre no-scams: 2048
|
||||
distv = distv * 16 / FLAMESHIELD_MAX; // Old distv was based on a 16-segment bar
|
||||
UINT8 numplayers = 0;
|
||||
UINT32 scamradius = 2000; // How close is close enough that we shouldn't be allowed to scam 1st?
|
||||
UINT32 scamradius = 1500; // How close is close enough that we shouldn't be allowed to scam 1st?
|
||||
UINT8 i;
|
||||
|
||||
if (gametyperules & GTR_CIRCUIT)
|
||||
|
|
@ -11709,29 +11709,31 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
if (player->flamelength < destlen)
|
||||
player->flamelength = min(destlen, player->flamelength + 7); // Allows gauge to grow quickly when first acquired. 120/16 = ~7
|
||||
|
||||
flamemax = player->flamelength;
|
||||
if (flamemax > 0)
|
||||
flamemax += TICRATE; // leniency period
|
||||
flamemax = player->flamelength + TICRATE; // TICRATE leniency period, but we block most effects at flamelength 0 down below
|
||||
|
||||
if ((cmd->buttons & BT_ATTACK) && (player->pflags & PF_HOLDREADY))
|
||||
{
|
||||
const INT32 incr = (gametyperules & GTR_CLOSERPLAYERS) ? 4 : 2;
|
||||
|
||||
if (player->flamedash == 0)
|
||||
{
|
||||
S_StartSound(player->mo, sfx_s3k43);
|
||||
K_PlayBoostTaunt(player->mo);
|
||||
}
|
||||
|
||||
player->flamedash += incr;
|
||||
player->flamemeter += incr;
|
||||
|
||||
if (!onground)
|
||||
if (player->flamelength)
|
||||
{
|
||||
P_Thrust(
|
||||
player->mo, K_MomentumAngle(player->mo),
|
||||
FixedMul(player->mo->scale, K_GetKartGameSpeedScalar(gamespeed))
|
||||
);
|
||||
|
||||
if (player->flamedash == 0)
|
||||
{
|
||||
S_StartSound(player->mo, sfx_s3k43);
|
||||
K_PlayBoostTaunt(player->mo);
|
||||
}
|
||||
|
||||
player->flamedash += incr;
|
||||
|
||||
if (!onground)
|
||||
{
|
||||
P_Thrust(
|
||||
player->mo, K_MomentumAngle(player->mo),
|
||||
FixedMul(player->mo->scale, K_GetKartGameSpeedScalar(gamespeed))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (player->flamemeter > flamemax)
|
||||
|
|
@ -12445,6 +12447,13 @@ tic_t K_TimeLimitForGametype(void)
|
|||
{
|
||||
if (battleprisons)
|
||||
{
|
||||
if (grandprixinfo.gp)
|
||||
{
|
||||
if (grandprixinfo.masterbots)
|
||||
return 15*TICRATE;
|
||||
else if (grandprixinfo.gamespeed == KARTSPEED_EASY)
|
||||
return 30*TICRATE;
|
||||
}
|
||||
return 20*TICRATE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,6 +54,10 @@ Make sure this matches the actual number of states
|
|||
#define RINGVOLUMEUSEPENALTY 15
|
||||
#define RINGVOLUMEREGEN 3
|
||||
|
||||
// Mispredicted turns can generate phantom sliptide inputs for a few tics.
|
||||
// Delay the wavedash visuals until we're reasonably sure that it's a deliberate turn.
|
||||
#define HIDEWAVEDASHCHARGE (60)
|
||||
|
||||
angle_t K_ReflectAngle(angle_t angle, angle_t against, fixed_t maxspeed, fixed_t yourspeed);
|
||||
|
||||
boolean K_IsDuelItem(mobjtype_t type);
|
||||
|
|
|
|||
|
|
@ -1158,6 +1158,7 @@ void M_DrawImageDef(void);
|
|||
void M_DrawCharacterSelect(void);
|
||||
boolean M_DrawCharacterSprite(INT16 x, INT16 y, INT16 skin, UINT8 spr2, UINT8 rotation, UINT32 frame, INT32 addflags, UINT8 *colormap);
|
||||
|
||||
void M_DrawCup(cupheader_t *cup, fixed_t x, fixed_t y, INT32 lockedTic, boolean isTrophy, UINT8 placement);
|
||||
void M_DrawCupSelect(void);
|
||||
void M_DrawLevelSelect(void);
|
||||
void M_DrawTimeAttack(void);
|
||||
|
|
|
|||
210
src/k_menudraw.c
210
src/k_menudraw.c
|
|
@ -2601,11 +2601,98 @@ fixed_t M_DrawCupWinData(INT32 rankx, INT32 ranky, cupheader_t *cup, UINT8 diffi
|
|||
return rankw;
|
||||
}
|
||||
|
||||
void M_DrawCup(cupheader_t *cup, fixed_t x, fixed_t y, INT32 lockedTic, boolean isTrophy, UINT8 placement)
|
||||
{
|
||||
patch_t *patch = NULL;
|
||||
UINT8 *colormap = NULL;
|
||||
INT16 icony = 7;
|
||||
char status = 'A';
|
||||
char monitor = '0';
|
||||
|
||||
if (isTrophy)
|
||||
{
|
||||
UINT16 col = SKINCOLOR_NONE;
|
||||
|
||||
switch (placement)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
col = SKINCOLOR_GOLD;
|
||||
status = 'B';
|
||||
break;
|
||||
case 2:
|
||||
col = SKINCOLOR_SILVER;
|
||||
status = 'B';
|
||||
break;
|
||||
case 3:
|
||||
col = SKINCOLOR_BRONZE;
|
||||
status = 'B';
|
||||
break;
|
||||
default:
|
||||
col = SKINCOLOR_BEIGE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (col != SKINCOLOR_NONE)
|
||||
colormap = R_GetTranslationColormap(TC_RAINBOW, col, GTC_MENUCACHE);
|
||||
else
|
||||
colormap = NULL;
|
||||
}
|
||||
|
||||
if (cup == &dummy_lostandfound)
|
||||
{
|
||||
// No cup? Lost and found!
|
||||
monitor = '0';
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cup->monitor < 10)
|
||||
{
|
||||
monitor = '0' + cup->monitor;
|
||||
|
||||
if (monitor == '2')
|
||||
{
|
||||
icony = 5; // by default already 7px down, so this is really 2px further up
|
||||
}
|
||||
else if (monitor == '3')
|
||||
{
|
||||
icony = 6;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
monitor = 'A' + (cup->monitor - 10);
|
||||
if (monitor == 'X')
|
||||
{
|
||||
icony = 11;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
patch = W_CachePatchName(va("CUPMON%c%c", monitor, status), PU_CACHE);
|
||||
V_DrawFixedPatch(x, y, FRACUNIT, 0, patch, colormap);
|
||||
|
||||
if (cup == &dummy_lostandfound)
|
||||
{
|
||||
; // Only ever placed on the list if valid
|
||||
}
|
||||
else if (lockedTic != 0)
|
||||
{
|
||||
patch_t *st = W_CachePatchName(va("ICONST0%d", (lockedTic % 4) + 1), PU_CACHE);
|
||||
V_DrawFixedPatch(x + (8 * FRACUNIT), y + (icony * FRACUNIT), FRACUNIT, 0, st, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
V_DrawFixedPatch(x + (8 * FRACUNIT), y + (icony * FRACUNIT), FRACUNIT, 0, W_CachePatchName(cup->icon, PU_CACHE), NULL);
|
||||
V_DrawFixedPatch(x + (8 * FRACUNIT), y + (icony * FRACUNIT), FRACUNIT, 0, W_CachePatchName("CUPBOX", PU_CACHE), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void M_DrawCupSelect(void)
|
||||
{
|
||||
UINT8 i, j, temp = 0;
|
||||
INT16 x, y;
|
||||
UINT8 *colormap = NULL;
|
||||
cupwindata_t *windata = NULL;
|
||||
levelsearch_t templevelsearch = levellist.levelsearch; // full copy
|
||||
|
||||
|
|
@ -2614,117 +2701,46 @@ void M_DrawCupSelect(void)
|
|||
for (j = 0; j < CUPMENU_ROWS; j++)
|
||||
{
|
||||
size_t id = (i + (j * CUPMENU_COLUMNS)) + (cupgrid.pageno * (CUPMENU_COLUMNS * CUPMENU_ROWS));
|
||||
patch_t *patch = NULL;
|
||||
INT16 icony = 7;
|
||||
char status = 'A';
|
||||
char monitor;
|
||||
|
||||
if (!cupgrid.builtgrid[id])
|
||||
break;
|
||||
|
||||
templevelsearch.cup = cupgrid.builtgrid[id];
|
||||
|
||||
if (cupgrid.grandprix
|
||||
&& (cv_dummygpdifficulty.value >= 0 && cv_dummygpdifficulty.value < KARTGP_MAX))
|
||||
{
|
||||
UINT16 col = SKINCOLOR_NONE;
|
||||
|
||||
windata = &templevelsearch.cup->windata[cv_dummygpdifficulty.value];
|
||||
|
||||
switch (windata->best_placement)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
col = SKINCOLOR_GOLD;
|
||||
status = 'B';
|
||||
break;
|
||||
case 2:
|
||||
col = SKINCOLOR_SILVER;
|
||||
status = 'B';
|
||||
break;
|
||||
case 3:
|
||||
col = SKINCOLOR_BRONZE;
|
||||
status = 'B';
|
||||
break;
|
||||
default:
|
||||
col = SKINCOLOR_BEIGE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (col != SKINCOLOR_NONE)
|
||||
colormap = R_GetTranslationColormap(TC_RAINBOW, col, GTC_MENUCACHE);
|
||||
else
|
||||
colormap = NULL;
|
||||
}
|
||||
|
||||
if (templevelsearch.cup == &dummy_lostandfound)
|
||||
{
|
||||
// No cup? Lost and found!
|
||||
monitor = '0';
|
||||
}
|
||||
else
|
||||
{
|
||||
if (templevelsearch.cup->monitor < 10)
|
||||
{
|
||||
monitor = '0' + templevelsearch.cup->monitor;
|
||||
|
||||
if (monitor == '2')
|
||||
{
|
||||
icony = 5; // by default already 7px down, so this is really 2px further up
|
||||
}
|
||||
else if (monitor == '3')
|
||||
{
|
||||
icony = 6;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
monitor = 'A' + (templevelsearch.cup->monitor - 10);
|
||||
if (monitor == 'X')
|
||||
{
|
||||
icony = 11;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
patch = W_CachePatchName(va("CUPMON%c%c", monitor, status), PU_CACHE);
|
||||
|
||||
x = 14 + (i*42);
|
||||
y = 20 + (j*44) - (30*menutransition.tics);
|
||||
|
||||
V_DrawFixedPatch((x)*FRACUNIT, (y)<<FRACBITS, FRACUNIT, 0, patch, colormap);
|
||||
|
||||
if (templevelsearch.cup == &dummy_lostandfound)
|
||||
; // Only ever placed on the list if valid
|
||||
else if (M_GetFirstLevelInList(&temp, &templevelsearch) == NEXTMAP_INVALID)
|
||||
const boolean isGP = (cupgrid.grandprix && (cv_dummygpdifficulty.value >= 0 && cv_dummygpdifficulty.value < KARTGP_MAX));
|
||||
if (isGP)
|
||||
{
|
||||
patch_t *st = W_CachePatchName(va("ICONST0%d", (cupgrid.previewanim % 4) + 1), PU_CACHE);
|
||||
V_DrawScaledPatch(x + 8, y + icony, 0, st);
|
||||
windata = &templevelsearch.cup->windata[cv_dummygpdifficulty.value];
|
||||
}
|
||||
else
|
||||
{
|
||||
V_DrawScaledPatch(x + 8, y + icony, 0, W_CachePatchName(templevelsearch.cup->icon, PU_CACHE));
|
||||
V_DrawScaledPatch(x + 8, y + icony, 0, W_CachePatchName("CUPBOX", PU_CACHE));
|
||||
|
||||
if (cupgrid.grandprix == true
|
||||
M_DrawCup(
|
||||
templevelsearch.cup,
|
||||
x * FRACUNIT, y * FRACUNIT,
|
||||
(M_GetFirstLevelInList(&temp, &templevelsearch) == NEXTMAP_INVALID) ? ((cupgrid.previewanim % 4) + 1) : 0,
|
||||
isGP,
|
||||
windata ? windata->best_placement : 0
|
||||
);
|
||||
|
||||
if (cupgrid.grandprix == true
|
||||
&& templevelsearch.cup == cupsavedata.cup
|
||||
&& id != CUPMENU_CURSORID)
|
||||
{
|
||||
V_DrawScaledPatch(x + 32, y + 32, 0, W_CachePatchName("CUPBKUP1", PU_CACHE));
|
||||
}
|
||||
{
|
||||
V_DrawScaledPatch(x + 32, y + 32, 0, W_CachePatchName("CUPBKUP1", PU_CACHE));
|
||||
}
|
||||
|
||||
if (windata && windata->best_placement != 0)
|
||||
{
|
||||
M_DrawCupWinData(
|
||||
x,
|
||||
8 + (j*100) - (30*menutransition.tics),
|
||||
templevelsearch.cup,
|
||||
cv_dummygpdifficulty.value,
|
||||
(cupgrid.previewanim & 1),
|
||||
false
|
||||
);
|
||||
}
|
||||
if (windata && windata->best_placement != 0)
|
||||
{
|
||||
M_DrawCupWinData(
|
||||
x,
|
||||
8 + (j*100) - (30*menutransition.tics),
|
||||
templevelsearch.cup,
|
||||
cv_dummygpdifficulty.value,
|
||||
(cupgrid.previewanim & 1),
|
||||
false
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
614
src/k_podium.c
614
src/k_podium.c
|
|
@ -1,614 +0,0 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) by Sally "TehRealSalt" Cochenour
|
||||
// Copyright (C) by Kart Krew
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
/// \file k_podium.c
|
||||
/// \brief Grand Prix podium cutscene
|
||||
|
||||
#include "k_podium.h"
|
||||
|
||||
#include "doomdef.h"
|
||||
#include "d_main.h"
|
||||
#include "d_netcmd.h"
|
||||
#include "f_finale.h"
|
||||
#include "g_game.h"
|
||||
#include "hu_stuff.h"
|
||||
#include "r_local.h"
|
||||
#include "s_sound.h"
|
||||
#include "i_time.h"
|
||||
#include "i_video.h"
|
||||
#include "v_video.h"
|
||||
#include "w_wad.h"
|
||||
#include "z_zone.h"
|
||||
#include "i_system.h"
|
||||
#include "i_threads.h"
|
||||
#include "dehacked.h"
|
||||
#include "g_input.h"
|
||||
#include "console.h"
|
||||
#include "m_random.h"
|
||||
#include "m_misc.h" // moviemode functionality
|
||||
#include "y_inter.h"
|
||||
#include "m_cond.h"
|
||||
#include "p_local.h"
|
||||
#include "p_saveg.h"
|
||||
#include "p_setup.h"
|
||||
#include "st_stuff.h" // hud hiding
|
||||
#include "fastcmp.h"
|
||||
|
||||
#include "lua_hud.h"
|
||||
#include "lua_hook.h"
|
||||
|
||||
#include "k_menu.h"
|
||||
#include "k_grandprix.h"
|
||||
#include "k_rank.h"
|
||||
|
||||
static struct podiumData_s
|
||||
{
|
||||
boolean ranking;
|
||||
gpRank_t rank;
|
||||
gp_rank_e grade;
|
||||
UINT8 state;
|
||||
UINT8 delay;
|
||||
UINT8 fade;
|
||||
} podiumData;
|
||||
|
||||
#define PODIUM_STATES (9) // TODO: enum when this actually gets made
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_PodiumSequence(void)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
boolean K_PodiumSequence(void)
|
||||
{
|
||||
return (gamestate == GS_CEREMONY);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_PodiumRanking(void)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
boolean K_PodiumRanking(void)
|
||||
{
|
||||
return (gamestate == GS_CEREMONY && podiumData.ranking == true);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_PodiumGrade(void)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
gp_rank_e K_PodiumGrade(void)
|
||||
{
|
||||
if (K_PodiumSequence() == false)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return podiumData.grade;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_PodiumHasEmerald(void)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
boolean K_PodiumHasEmerald(void)
|
||||
{
|
||||
if (K_PodiumSequence() == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return podiumData.rank.specialWon;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
UINT8 K_GetPodiumPosition(player_t *player)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
UINT8 K_GetPodiumPosition(player_t *player)
|
||||
{
|
||||
UINT8 position = 1;
|
||||
INT32 i;
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
player_t *other = NULL;
|
||||
if (playeringame[i] == false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
other = &players[i];
|
||||
if (other->bot == false && other->spectator == true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (other->score > player->score)
|
||||
{
|
||||
// Final score is the important part.
|
||||
position++;
|
||||
}
|
||||
else if (other->score == player->score)
|
||||
{
|
||||
if (other->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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static void K_SetPodiumWaypoint(player_t *const player, waypoint_t *const waypoint)
|
||||
|
||||
Changes the player's current and next waypoints, for
|
||||
use during the podium sequence.
|
||||
|
||||
Input Arguments:-
|
||||
player - The player to update the waypoints of.
|
||||
waypoint - The new current waypoint.
|
||||
|
||||
Return:-
|
||||
None
|
||||
--------------------------------------------------*/
|
||||
static void K_SetPodiumWaypoint(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];
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_InitializePodiumWaypoint(player_t *const player)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
void K_InitializePodiumWaypoint(player_t *const player)
|
||||
{
|
||||
if ((player != NULL) && (player->mo != NULL))
|
||||
{
|
||||
player->position = K_GetPodiumPosition(player);
|
||||
|
||||
if (player->position > 0 && player->position <= MAXPLAYERS)
|
||||
{
|
||||
// Initialize our first waypoint to the one that
|
||||
// matches our position.
|
||||
K_SetPodiumWaypoint(player, K_GetWaypointFromID(player->position));
|
||||
}
|
||||
else
|
||||
{
|
||||
// None does, so remove it if we happen to have one.
|
||||
K_SetPodiumWaypoint(player, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_UpdatePodiumWaypoints(player_t *const player)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
void K_UpdatePodiumWaypoints(player_t *const player)
|
||||
{
|
||||
if ((player != NULL) && (player->mo != NULL))
|
||||
{
|
||||
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_SetPodiumWaypoint(player, player->nextwaypoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
boolean K_StartCeremony(void)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
boolean K_StartCeremony(void)
|
||||
{
|
||||
if (grandprixinfo.gp == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
INT32 i;
|
||||
INT32 podiumMapNum = NEXTMAP_INVALID;
|
||||
|
||||
if (grandprixinfo.cup != NULL
|
||||
&& grandprixinfo.cup->cachedlevels[CUPCACHE_PODIUM] != NEXTMAP_INVALID)
|
||||
{
|
||||
podiumMapNum = grandprixinfo.cup->cachedlevels[CUPCACHE_PODIUM];
|
||||
}
|
||||
else if (podiummap)
|
||||
{
|
||||
podiumMapNum = G_MapNumber(podiummap);
|
||||
}
|
||||
|
||||
if (podiumMapNum < nummapheaders
|
||||
&& mapheaderinfo[podiumMapNum]
|
||||
&& mapheaderinfo[podiumMapNum]->lumpnum != LUMPERROR)
|
||||
{
|
||||
gamemap = podiumMapNum+1;
|
||||
|
||||
encoremode = grandprixinfo.encore;
|
||||
|
||||
if (savedata.lives > 0)
|
||||
{
|
||||
K_LoadGrandPrixSaveGame();
|
||||
savedata.lives = 0;
|
||||
}
|
||||
|
||||
// Make sure all of the GAME OVER'd players can spawn
|
||||
// and be present for the podium
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i])
|
||||
{
|
||||
if (players[i].lives < 1)
|
||||
players[i].lives = 1;
|
||||
|
||||
if (players[i].bot)
|
||||
players[i].spectator = false;
|
||||
}
|
||||
}
|
||||
|
||||
G_SetGametype(GT_RACE);
|
||||
G_DoLoadLevelEx(false, GS_CEREMONY);
|
||||
wipegamestate = GS_CEREMONY; // I don't know what else to do here
|
||||
|
||||
r_splitscreen = 0; // Only one screen for the ceremony
|
||||
R_ExecuteSetViewSize();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_FinishCeremony(void)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
void K_FinishCeremony(void)
|
||||
{
|
||||
if (K_PodiumSequence() == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
podiumData.ranking = true;
|
||||
|
||||
// Play the noise now (via G_UpdateVisited's concluding gamedata save)
|
||||
prevmap = gamemap-1;
|
||||
G_UpdateVisited();
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_ResetCeremony(void)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
void K_ResetCeremony(void)
|
||||
{
|
||||
SINT8 i;
|
||||
|
||||
memset(&podiumData, 0, sizeof(struct podiumData_s));
|
||||
|
||||
if (K_PodiumSequence() == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Establish rank and grade for this play session.
|
||||
podiumData.rank = grandprixinfo.rank;
|
||||
podiumData.grade = K_CalculateGPGrade(&podiumData.rank);
|
||||
|
||||
// Set up music for podium.
|
||||
{
|
||||
if (podiumData.rank.position <= 1)
|
||||
mapmusrng = 2;
|
||||
else if (podiumData.rank.position == 2
|
||||
|| podiumData.rank.position == 3)
|
||||
mapmusrng = 1;
|
||||
else
|
||||
mapmusrng = 0;
|
||||
|
||||
while (mapmusrng >= max(1, mapheaderinfo[gamemap-1]->musname_size))
|
||||
mapmusrng--;
|
||||
|
||||
mapmusflags |= MUSIC_RELOADRESET;
|
||||
}
|
||||
|
||||
if (!grandprixinfo.cup)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Write grade, position, and emerald-having-ness for later sessions!
|
||||
i = (grandprixinfo.masterbots) ? KARTGP_MASTER : grandprixinfo.gamespeed;
|
||||
|
||||
// All results populate downwards in difficulty. This prevents someone
|
||||
// who's just won on Normal from feeling obligated to complete Easy too.
|
||||
for (; i >= 0; i--)
|
||||
{
|
||||
boolean anymerit = false;
|
||||
|
||||
if ((grandprixinfo.cup->windata[i].best_placement == 0) // First run
|
||||
|| (podiumData.rank.position <= grandprixinfo.cup->windata[i].best_placement)) // Later, better run
|
||||
{
|
||||
grandprixinfo.cup->windata[i].best_placement = podiumData.rank.position;
|
||||
|
||||
// The following will not occur in unmodified builds, but pre-emptively sanitise gamedata if someone just changes MAXPLAYERS and calls it a day
|
||||
if (grandprixinfo.cup->windata[i].best_placement > 0x0F)
|
||||
grandprixinfo.cup->windata[i].best_placement = 0x0F;
|
||||
|
||||
anymerit = true;
|
||||
}
|
||||
|
||||
if (podiumData.grade >= grandprixinfo.cup->windata[i].best_grade)
|
||||
{
|
||||
grandprixinfo.cup->windata[i].best_grade = podiumData.grade;
|
||||
anymerit = true;
|
||||
}
|
||||
|
||||
if (podiumData.rank.specialWon == true)
|
||||
{
|
||||
grandprixinfo.cup->windata[i].got_emerald = true;
|
||||
anymerit = true;
|
||||
}
|
||||
|
||||
if (anymerit == true)
|
||||
{
|
||||
grandprixinfo.cup->windata[i].best_skin.id = podiumData.rank.skin;
|
||||
grandprixinfo.cup->windata[i].best_skin.unloaded = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Save before playing the noise
|
||||
G_SaveGameData();
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_CeremonyTicker(boolean run)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
void K_CeremonyTicker(boolean run)
|
||||
{
|
||||
// don't trigger if doing anything besides idling
|
||||
if (gameaction != ga_nothing || gamestate != GS_CEREMONY)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
P_TickAltView(&titlemapcam);
|
||||
|
||||
if (titlemapcam.mobj != NULL)
|
||||
{
|
||||
camera[0].x = titlemapcam.mobj->x;
|
||||
camera[0].y = titlemapcam.mobj->y;
|
||||
camera[0].z = titlemapcam.mobj->z;
|
||||
camera[0].angle = titlemapcam.mobj->angle;
|
||||
camera[0].aiming = titlemapcam.mobj->pitch;
|
||||
camera[0].subsector = titlemapcam.mobj->subsector;
|
||||
}
|
||||
|
||||
if (podiumData.ranking == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (run == true)
|
||||
{
|
||||
if (podiumData.fade < 16)
|
||||
{
|
||||
podiumData.fade++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (podiumData.state < PODIUM_STATES)
|
||||
{
|
||||
podiumData.delay++;
|
||||
|
||||
if (podiumData.delay > TICRATE/2)
|
||||
{
|
||||
podiumData.state++;
|
||||
podiumData.delay = 0;
|
||||
}
|
||||
}
|
||||
else if (podiumData.delay == TICRATE)
|
||||
{
|
||||
if (!menuactive && M_MenuConfirmPressed(0))
|
||||
{
|
||||
podiumData.delay++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (++podiumData.delay == 2*TICRATE)
|
||||
{
|
||||
if (grandprixinfo.gp == true
|
||||
&& grandprixinfo.cup != NULL
|
||||
&& grandprixinfo.cup->playcredits == true)
|
||||
{
|
||||
nextmap = NEXTMAP_CREDITS;
|
||||
}
|
||||
else
|
||||
{
|
||||
nextmap = NEXTMAP_TITLE;
|
||||
}
|
||||
|
||||
G_EndGame();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_CeremonyDrawer(void)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
void K_CeremonyDrawer(void)
|
||||
{
|
||||
if (podiumData.ranking == true)
|
||||
{
|
||||
char gradeChar = '?';
|
||||
INT32 x = 64;
|
||||
INT32 y = 48;
|
||||
INT32 i;
|
||||
|
||||
switch (podiumData.grade)
|
||||
{
|
||||
case GRADE_E: { gradeChar = 'E'; break; }
|
||||
case GRADE_D: { gradeChar = 'D'; break; }
|
||||
case GRADE_C: { gradeChar = 'C'; break; }
|
||||
case GRADE_B: { gradeChar = 'B'; break; }
|
||||
case GRADE_A: { gradeChar = 'A'; break; }
|
||||
case GRADE_S: { gradeChar = 'S'; break; }
|
||||
default: { break; }
|
||||
}
|
||||
|
||||
V_DrawFadeScreen(0xFF00, podiumData.fade);
|
||||
|
||||
for (i = 0; i <= podiumData.state; i++)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
V_DrawString(x, y, 0,
|
||||
va("POS: %d / %d", podiumData.rank.position, RANK_NEUTRAL_POSITION)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
V_DrawString(x, y, 0,
|
||||
va("PTS: %d / %d", podiumData.rank.winPoints, podiumData.rank.totalPoints)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
V_DrawString(x, y, 0,
|
||||
va("LAPS: %d / %d", podiumData.rank.laps, podiumData.rank.totalLaps)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
V_DrawString(x, y, 0,
|
||||
va("CONTINUES: %d", podiumData.rank.continuesUsed)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
V_DrawString(x, y, 0,
|
||||
va("PRISONS: %d / %d", podiumData.rank.prisons, podiumData.rank.totalPrisons)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
V_DrawString(x, y, 0,
|
||||
va("RINGS: %d / %d", podiumData.rank.rings, podiumData.rank.totalRings)
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 7:
|
||||
{
|
||||
const char *emeraldstr = "???";
|
||||
if (gamedata->everseenspecial == true)
|
||||
{
|
||||
emeraldstr =
|
||||
(grandprixinfo.gp == true
|
||||
&& grandprixinfo.cup != NULL
|
||||
&& grandprixinfo.cup->emeraldnum > 0)
|
||||
? "EMERALD"
|
||||
: "PRIZE";
|
||||
}
|
||||
|
||||
V_DrawString(x, y, 0,
|
||||
va("%s: %s",
|
||||
emeraldstr,
|
||||
(podiumData.rank.specialWon == true) ? "YES" : "NO")
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 8:
|
||||
{
|
||||
V_DrawString(x, y + 10, V_YELLOWMAP,
|
||||
va(" ** FINAL GRADE: %c", gradeChar)
|
||||
);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
y += 10;
|
||||
}
|
||||
}
|
||||
|
||||
// See d_main.c and V_DrawCustomFadeScreen for the hacks that prevents this being here
|
||||
/*if (timeinmap < 16)
|
||||
{
|
||||
// Level fade-in
|
||||
V_DrawCustomFadeScreen(((levelfadecol == 0) ? "FADEMAP1" : "FADEMAP0"), 31-(timeinmap*2));
|
||||
}*/
|
||||
|
||||
if (podiumData.state == PODIUM_STATES)
|
||||
{
|
||||
Y_DrawIntermissionButton(TICRATE - podiumData.delay, podiumData.delay - TICRATE);
|
||||
}
|
||||
}
|
||||
1136
src/k_podium.cpp
Normal file
1136
src/k_podium.cpp
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -80,6 +80,7 @@ gp_rank_e K_PodiumGrade(void);
|
|||
Return:-
|
||||
true if the Emerald/Prize was collected during the GP, otherwise false.
|
||||
--------------------------------------------------*/
|
||||
|
||||
boolean K_PodiumHasEmerald(void);
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -139,6 +139,7 @@ static void RankCapsules_LoadTextmap(void)
|
|||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*--------------------------------------------------
|
||||
static void RankCapsules_LoadThingsLump(UINT8 *data)
|
||||
|
||||
|
|
@ -175,6 +176,7 @@ static void RankCapsules_LoadThingsLump(UINT8 *data)
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*--------------------------------------------------
|
||||
static boolean RankCapsules_LoadMapData(const virtres_t *virt)
|
||||
|
|
@ -225,7 +227,11 @@ static boolean RankCapsules_LoadMapData(const virtres_t *virt)
|
|||
}
|
||||
else
|
||||
{
|
||||
#if 0
|
||||
RankCapsules_LoadThingsLump(virtthings->data);
|
||||
#else
|
||||
CONS_Printf("binary maps SMELL!!!!!\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -263,15 +269,16 @@ static UINT32 RankCapsules_CountFromMap(const virtres_t *virt)
|
|||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
void K_InitGrandPrixRank(gpRank_t *rankData)
|
||||
void gpRank_t::Init(void)
|
||||
{
|
||||
UINT8 numHumans = 0;
|
||||
UINT32 laps = 0;
|
||||
INT32 i;
|
||||
|
||||
memset(rankData, 0, sizeof(gpRank_t));
|
||||
memset(this, 0, sizeof(gpRank_t));
|
||||
skin = MAXSKINS;
|
||||
|
||||
if (grandprixinfo.cup == NULL)
|
||||
if (grandprixinfo.cup == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -288,20 +295,20 @@ void K_InitGrandPrixRank(gpRank_t *rankData)
|
|||
}
|
||||
|
||||
// Calculate players
|
||||
rankData->players = numHumans;
|
||||
rankData->totalPlayers = K_GetGPPlayerCount(numHumans);
|
||||
numPlayers = numHumans;
|
||||
totalPlayers = K_GetGPPlayerCount(numHumans);
|
||||
|
||||
// Initialize to the neutral value.
|
||||
rankData->position = RANK_NEUTRAL_POSITION;
|
||||
position = RANK_NEUTRAL_POSITION;
|
||||
|
||||
// Calculate total of points
|
||||
// (Should this account for all coop players?)
|
||||
for (i = 0; i < numHumans; i++)
|
||||
{
|
||||
rankData->totalPoints += grandprixinfo.cup->numlevels * K_CalculateGPRankPoints(i + 1, rankData->totalPlayers);
|
||||
totalPoints += grandprixinfo.cup->numlevels * K_CalculateGPRankPoints(i + 1, totalPlayers);
|
||||
}
|
||||
|
||||
rankData->totalRings = grandprixinfo.cup->numlevels * numHumans * 20;
|
||||
totalRings = grandprixinfo.cup->numlevels * numHumans * 20;
|
||||
|
||||
for (i = 0; i < grandprixinfo.cup->numlevels; i++)
|
||||
{
|
||||
|
|
@ -315,7 +322,7 @@ void K_InitGrandPrixRank(gpRank_t *rankData)
|
|||
// +1, since 1st place laps are worth 2 pts.
|
||||
for (i = 0; i < numHumans+1; i++)
|
||||
{
|
||||
rankData->totalLaps += laps;
|
||||
totalLaps += laps;
|
||||
}
|
||||
|
||||
// Search through all of the cup's bonus levels
|
||||
|
|
@ -339,42 +346,97 @@ void K_InitGrandPrixRank(gpRank_t *rankData)
|
|||
continue;
|
||||
}
|
||||
|
||||
rankData->totalPrisons += RankCapsules_CountFromMap(virt);
|
||||
totalPrisons += RankCapsules_CountFromMap(virt);
|
||||
vres_Free(virt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void K_InitGrandPrixRank(gpRank_t *rankData)
|
||||
{
|
||||
rankData->Init();
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_UpdateGPRank(void)
|
||||
void K_UpdateGPRank(gpRank_t *rankData)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
void K_UpdateGPRank(void)
|
||||
void gpRank_t::Update(void)
|
||||
{
|
||||
if (grandprixinfo.gp != true)
|
||||
return;
|
||||
gpRank_level_t *const lvl = &levels[numLevels];
|
||||
|
||||
prisons += numtargets;
|
||||
|
||||
position = MAXPLAYERS;
|
||||
skin = MAXSKINS;
|
||||
|
||||
lvl->id = gamemap;
|
||||
|
||||
if (grandprixinfo.gp == true)
|
||||
{
|
||||
lvl->event = grandprixinfo.eventmode;
|
||||
}
|
||||
else
|
||||
{
|
||||
lvl->event = (gametype != GT_RACE) ? GPEVENT_BONUS : GPEVENT_NONE;
|
||||
}
|
||||
|
||||
lvl->time = UINT32_MAX;
|
||||
lvl->totalLapPoints = K_RaceLapCount(gamemap - 1) * 2;
|
||||
lvl->totalPrisons = maptargets;
|
||||
|
||||
UINT8 i;
|
||||
|
||||
grandprixinfo.rank.prisons += numtargets;
|
||||
grandprixinfo.rank.position = MAXPLAYERS;
|
||||
grandprixinfo.rank.skin = MAXSKINS;
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i]
|
||||
|| players[i].spectator == true
|
||||
|| players[i].bot == true)
|
||||
if (playeringame[i] == false
|
||||
|| players[i].spectator == true
|
||||
|| players[i].bot == true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
UINT8 podiumposition = K_GetPodiumPosition(&players[i]);
|
||||
if (podiumposition >= grandprixinfo.rank.position) // port priority
|
||||
continue;
|
||||
player_t *const player = &players[i];
|
||||
|
||||
grandprixinfo.rank.position = podiumposition;
|
||||
grandprixinfo.rank.skin = players[i].skin;
|
||||
UINT8 podiumPosition = K_GetPodiumPosition(player);
|
||||
if (podiumPosition < position) // port priority
|
||||
{
|
||||
position = podiumPosition;
|
||||
skin = player->skin;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < numPlayers; i++)
|
||||
{
|
||||
if (playeringame[displayplayers[i]] == false
|
||||
|| players[displayplayers[i]].spectator == true
|
||||
|| players[displayplayers[i]].bot == true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const player_t *player = &players[displayplayers[i]]; // TODO: needs looked at for online GP
|
||||
gpRank_level_perplayer_t *const dta = &lvl->perPlayer[i];
|
||||
|
||||
if (player->realtime < lvl->time)
|
||||
{
|
||||
lvl->time = player->realtime;
|
||||
}
|
||||
|
||||
dta->position = player->tally.position;
|
||||
dta->rings = player->tally.rings;
|
||||
dta->lapPoints = player->tally.laps;
|
||||
dta->prisons = player->tally.prisons;
|
||||
dta->gotSpecialPrize = !!!(player->pflags & PF_NOCONTEST);
|
||||
dta->grade = static_cast<gp_rank_e>(player->tally.rank);
|
||||
}
|
||||
|
||||
numLevels++;
|
||||
}
|
||||
|
||||
void K_UpdateGPRank(gpRank_t *rankData)
|
||||
{
|
||||
rankData->Update();
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
|
|
@ -389,7 +451,7 @@ gp_rank_e K_CalculateGPGrade(gpRank_t *rankData)
|
|||
|
||||
if (cv_debugrank.value >= 2)
|
||||
{
|
||||
return GRADE_E + (cv_debugrank.value - 2);
|
||||
return static_cast<gp_rank_e>(GRADE_E + (cv_debugrank.value - 2));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -400,7 +462,7 @@ gp_rank_e K_CalculateGPGrade(gpRank_t *rankData)
|
|||
17*FRACUNIT/20 // A: 85% or higher
|
||||
};
|
||||
|
||||
gp_rank_e retGrade = GRADE_E;
|
||||
INT32 retGrade = GRADE_E;
|
||||
|
||||
const INT32 positionWeight = 150;
|
||||
const INT32 pointsWeight = 100;
|
||||
|
|
@ -459,7 +521,7 @@ gp_rank_e K_CalculateGPGrade(gpRank_t *rankData)
|
|||
retGrade++;
|
||||
}
|
||||
|
||||
return retGrade;
|
||||
return static_cast<gp_rank_e>(retGrade);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
|
|
@ -489,3 +551,32 @@ UINT16 K_GetGradeColor(gp_rank_e grade)
|
|||
|
||||
return SKINCOLOR_NONE;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
char K_GetGradeChar(gp_rank_e grade)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
char K_GetGradeChar(gp_rank_e grade)
|
||||
{
|
||||
switch (grade)
|
||||
{
|
||||
case GRADE_E:
|
||||
return 'E';
|
||||
case GRADE_D:
|
||||
return 'D';
|
||||
case GRADE_C:
|
||||
return 'C';
|
||||
case GRADE_B:
|
||||
return 'B';
|
||||
case GRADE_A:
|
||||
return 'A';
|
||||
case GRADE_S:
|
||||
return 'S';
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return '?';
|
||||
}
|
||||
|
||||
65
src/k_rank.h
65
src/k_rank.h
|
|
@ -16,14 +16,30 @@
|
|||
#include "doomdef.h"
|
||||
#include "doomstat.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Please also see P_ArchiveMisc
|
||||
struct gpRank_level_perplayer_t
|
||||
{
|
||||
UINT8 position;
|
||||
UINT8 rings;
|
||||
UINT16 lapPoints;
|
||||
UINT16 prisons;
|
||||
boolean gotSpecialPrize;
|
||||
gp_rank_e grade;
|
||||
};
|
||||
|
||||
struct gpRank_level_t
|
||||
{
|
||||
UINT16 id;
|
||||
INT32 event;
|
||||
UINT32 time;
|
||||
UINT16 totalLapPoints;
|
||||
UINT16 totalPrisons;
|
||||
gpRank_level_perplayer_t perPlayer[MAXSPLITSCREENPLAYERS];
|
||||
};
|
||||
|
||||
struct gpRank_t
|
||||
{
|
||||
UINT8 players;
|
||||
UINT8 numPlayers;
|
||||
UINT8 totalPlayers;
|
||||
|
||||
UINT8 position;
|
||||
|
|
@ -44,8 +60,20 @@ struct gpRank_t
|
|||
UINT32 totalRings;
|
||||
|
||||
boolean specialWon;
|
||||
|
||||
UINT8 numLevels;
|
||||
gpRank_level_t levels[8];
|
||||
|
||||
#ifdef __cplusplus
|
||||
void Init(void);
|
||||
void Update(void);
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// gp_rank_e was once defined here, but moved to doomstat.h to prevent circular dependency
|
||||
|
||||
// 3rd place is neutral, anything below is a penalty
|
||||
|
|
@ -68,18 +96,13 @@ void K_InitGrandPrixRank(gpRank_t *rankData);
|
|||
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_UpdateGPRank(void)
|
||||
void K_UpdateGPRank(gpRank_t *rankData)
|
||||
|
||||
Updates the best ranking across all human
|
||||
players.
|
||||
|
||||
Input Arguments:-
|
||||
N/A
|
||||
|
||||
Return:-
|
||||
N/A
|
||||
--------------------------------------------------*/
|
||||
void K_UpdateGPRank(void);
|
||||
|
||||
void K_UpdateGPRank(gpRank_t *rankData);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
|
|
@ -109,9 +132,25 @@ gp_rank_e K_CalculateGPGrade(gpRank_t *rankData);
|
|||
Return:-
|
||||
skincolor ID representing the achieved grade.
|
||||
--------------------------------------------------*/
|
||||
|
||||
UINT16 K_GetGradeColor(gp_rank_e grade);
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
char K_GetGradeChar(gp_rank_e grade)
|
||||
|
||||
Maps grades to a letter for strings.
|
||||
|
||||
Input Arguments:-
|
||||
grade - gp_rank_e representing an achieved ranking.
|
||||
|
||||
Return:-
|
||||
ASCII character for the grade.
|
||||
--------------------------------------------------*/
|
||||
|
||||
char K_GetGradeChar(gp_rank_e grade);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1337,32 +1337,9 @@ void level_tally_t::Draw(void)
|
|||
|| state == TALLY_ST_GRADE_VOICE
|
||||
|| state == TALLY_ST_DONE)
|
||||
{
|
||||
const char *grade_letter = "X";
|
||||
switch (rank)
|
||||
{
|
||||
case GRADE_E:
|
||||
grade_letter = "E";
|
||||
break;
|
||||
case GRADE_D:
|
||||
grade_letter = "D";
|
||||
break;
|
||||
case GRADE_C:
|
||||
grade_letter = "C";
|
||||
break;
|
||||
case GRADE_B:
|
||||
grade_letter = "B";
|
||||
break;
|
||||
case GRADE_A:
|
||||
grade_letter = "A";
|
||||
break;
|
||||
case GRADE_S:
|
||||
grade_letter = "S";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
char grade_letter = K_GetGradeChar( static_cast<gp_rank_e>(rank) );
|
||||
|
||||
patch_t *grade_img = static_cast<patch_t*>( W_CachePatchName(va("R_FINR%s%s", (r_splitscreen ? "S" : "N"), grade_letter), PU_CACHE) );
|
||||
patch_t *grade_img = static_cast<patch_t*>( W_CachePatchName(va("R_FINR%c%c", (r_splitscreen ? 'S' : 'N'), grade_letter), PU_CACHE) );
|
||||
srb2::Draw grade_drawer = drawer
|
||||
.xy(v_width * 0.5, v_height - (2.0 * frac) - (grade_img->height * 0.5))
|
||||
.colormap( static_cast<skincolornum_t>(K_GetGradeColor( static_cast<gp_rank_e>(rank) )) );
|
||||
|
|
|
|||
|
|
@ -1087,7 +1087,17 @@ static void P_AddBrokenPrison(mobj_t *target, mobj_t *inflictor, mobj_t *source)
|
|||
S_StartSound(NULL, sfx_s221);
|
||||
if (timelimitintics)
|
||||
{
|
||||
extratimeintics += 10*TICRATE;
|
||||
UINT16 bonustime = 10*TICRATE;
|
||||
|
||||
if (grandprixinfo.gp)
|
||||
{
|
||||
if (grandprixinfo.masterbots)
|
||||
bonustime = 8*TICRATE;
|
||||
else if (grandprixinfo.gamespeed == KARTSPEED_EASY)
|
||||
bonustime = 15*TICRATE;
|
||||
}
|
||||
|
||||
extratimeintics += bonustime;
|
||||
secretextratime = TICRATE/2;
|
||||
}
|
||||
|
||||
|
|
@ -2495,6 +2505,11 @@ static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source,
|
|||
|
||||
P_SetPlayerMobjState(player->mo, player->mo->info->deathstate);
|
||||
|
||||
if (player->sliptideZipIndicator && !P_MobjWasRemoved(player->sliptideZipIndicator))
|
||||
P_RemoveMobj(player->sliptideZipIndicator);
|
||||
if (player->stumbleIndicator && !P_MobjWasRemoved(player->stumbleIndicator))
|
||||
P_RemoveMobj(player->stumbleIndicator);
|
||||
|
||||
if (type == DMG_TIMEOVER)
|
||||
{
|
||||
if (gametyperules & GTR_CIRCUIT)
|
||||
|
|
|
|||
|
|
@ -5747,7 +5747,7 @@ static inline void P_ArchiveMisc(savebuffer_t *save)
|
|||
// Rank information
|
||||
|
||||
{
|
||||
WRITEUINT8(save->p, grandprixinfo.rank.players);
|
||||
WRITEUINT8(save->p, grandprixinfo.rank.numPlayers);
|
||||
WRITEUINT8(save->p, grandprixinfo.rank.totalPlayers);
|
||||
|
||||
WRITEUINT8(save->p, grandprixinfo.rank.position);
|
||||
|
|
@ -5768,6 +5768,19 @@ static inline void P_ArchiveMisc(savebuffer_t *save)
|
|||
WRITEUINT32(save->p, grandprixinfo.rank.totalRings);
|
||||
|
||||
WRITEUINT8(save->p, (UINT8)grandprixinfo.rank.specialWon);
|
||||
|
||||
/*
|
||||
WRITEUINT8(save->p, grandprixinfo.rank.numLevels);
|
||||
|
||||
for (i = 0; i < grandprixinfo.rank.stages; i++)
|
||||
{
|
||||
UINT8 j;
|
||||
for (j = 0; j < grandprixinfo.rank.numPlayers; j++)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// Marathon information
|
||||
|
|
@ -5910,7 +5923,7 @@ static boolean P_UnArchiveSPGame(savebuffer_t *save)
|
|||
// Rank information
|
||||
|
||||
{
|
||||
grandprixinfo.rank.players = READUINT8(save->p);
|
||||
grandprixinfo.rank.numPlayers = READUINT8(save->p);
|
||||
grandprixinfo.rank.totalPlayers = READUINT8(save->p);
|
||||
|
||||
grandprixinfo.rank.position = READUINT8(save->p);
|
||||
|
|
|
|||
11
src/p_user.c
11
src/p_user.c
|
|
@ -2279,6 +2279,17 @@ static void P_UpdatePlayerAngle(player_t *player)
|
|||
// With a full slam on the analog stick, how far could we steer in either direction?
|
||||
INT16 steeringRight = K_UpdateSteeringValue(player->steering, KART_FULLTURN);
|
||||
INT16 steeringLeft = K_UpdateSteeringValue(player->steering, -KART_FULLTURN);
|
||||
|
||||
// When entering/leaving drifts, allow all legal turns with no easing.
|
||||
// This is the hardest case for the turn solver, because your handling properties on
|
||||
// client side are very different than your handling properties on server side—at least,
|
||||
// until your drift status makes the full round-trip and is reflected in your gamestate.
|
||||
if (player->drift && abs(player->drift) < 5)
|
||||
{
|
||||
steeringRight = KART_FULLTURN;
|
||||
steeringLeft = -KART_FULLTURN;
|
||||
}
|
||||
|
||||
angle_t maxTurnRight = K_GetKartTurnValue(player, steeringRight) << TICCMD_REDUCE;
|
||||
angle_t maxTurnLeft = K_GetKartTurnValue(player, steeringLeft) << TICCMD_REDUCE;
|
||||
|
||||
|
|
|
|||
|
|
@ -229,6 +229,8 @@ TYPEDEF (t_floor_t);
|
|||
TYPEDEF (waypoint_t);
|
||||
|
||||
// k_rank.h
|
||||
TYPEDEF (gpRank_level_perplayer_t);
|
||||
TYPEDEF (gpRank_level_t);
|
||||
TYPEDEF (gpRank_t);
|
||||
|
||||
// k_tally.h
|
||||
|
|
|
|||
|
|
@ -283,7 +283,10 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32))
|
|||
{
|
||||
// Okay, player scores have been set now - we can calculate GP-relevant material.
|
||||
{
|
||||
K_UpdateGPRank();
|
||||
if (grandprixinfo.gp == true)
|
||||
{
|
||||
K_UpdateGPRank(&grandprixinfo.rank);
|
||||
}
|
||||
|
||||
// See also G_GetNextMap, M_DrawPause
|
||||
data.showrank = false;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue