Merge branch 'sealed-smooth' into 'master'

Sealed Smooth

See merge request KartKrew/Kart!1154
This commit is contained in:
Oni 2023-04-09 03:07:26 +00:00
commit 485af970e6
9 changed files with 479 additions and 91 deletions

View file

@ -1219,6 +1219,11 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
"S_CHAOSEMERALD2",
"S_CHAOSEMERALD_UNDER",
// Super Emeralds
"S_SUPEREMERALD1",
"S_SUPEREMERALD2",
"S_SUPEREMERALD_UNDER",
"S_EMERALDSPARK1",
"S_EMERALDSPARK2",
"S_EMERALDSPARK3",
@ -4557,6 +4562,8 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
"S_SPECIAL_UFO_POD",
"S_SPECIAL_UFO_OVERLAY",
"S_SPECIAL_UFO_GLASS",
"S_SPECIAL_UFO_GLASS_UNDER",
"S_SPECIAL_UFO_ARM",
"S_SPECIAL_UFO_STEM",

View file

@ -144,6 +144,7 @@ char sprnames[NUMSPRITES + 1][5] =
"NSTR", // NiGHTS star
"EMBM", // Emblem
"EMRC", // Chaos Emeralds
"SEMR", // Super Emeralds
"ESPK",
"SHRD", // Emerald Hunt
@ -794,6 +795,8 @@ char sprnames[NUMSPRITES + 1][5] =
"UFOB",
"UFOA",
"UFOS",
"SSCA",
"SSCB",
"UQMK",
@ -1775,6 +1778,11 @@ state_t states[NUMSTATES] =
{SPR_EMRC, FF_FULLBRIGHT|FF_ADD, 1, {NULL}, 0, 0, S_CHAOSEMERALD1}, // S_CHAOSEMERALD2
{SPR_EMRC, FF_FULLBRIGHT|1, -1, {NULL}, 1, 0, S_NULL}, // S_CHAOSEMERALD_UNDER
// Super Emeralds
{SPR_SEMR, FF_SEMIBRIGHT, 1, {NULL}, 0, 0, S_SUPEREMERALD2}, // S_SUPEREMERALD1
{SPR_SEMR, FF_FULLBRIGHT|FF_ADD, 1, {NULL}, 0, 0, S_SUPEREMERALD1}, // S_SUPEREMERALD2
{SPR_SEMR, FF_FULLBRIGHT|1, -1, {NULL}, 1, 0, S_NULL}, // S_SUPEREMERALD_UNDER
{SPR_ESPK, FF_FULLBRIGHT, 3, {NULL}, 0, 0, S_EMERALDSPARK2}, // S_EMERALDSPARK1
{SPR_ESPK, FF_FULLBRIGHT|1, 3, {NULL}, 0, 0, S_EMERALDSPARK3}, // S_EMERALDSPARK2
{SPR_ESPK, FF_FULLBRIGHT|2, 3, {NULL}, 0, 0, S_EMERALDSPARK4}, // S_EMERALDSPARK3
@ -5184,6 +5192,8 @@ state_t states[NUMSTATES] =
{SPR_UFOB, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SPECIAL_UFO_POD
{SPR_UFOB, 1|FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 1, 1, S_NULL}, // S_SPECIAL_UFO_OVERLAY
{SPR_SSCA, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SPECIAL_UFO_GLASS
{SPR_SSCB, FF_SUBTRACT, -1, {NULL}, 0, 0, S_NULL}, // S_SPECIAL_UFO_GLASS_UNDER
{SPR_UFOA, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_SPECIAL_UFO_ARM
{SPR_UFOS, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SPECIAL_UFO_STEM
@ -22530,7 +22540,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
100, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPTHING|MF_NOCLIPHEIGHT|MF_NOSQUISH, // flags
MF_NOGRAVITY|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPTHING|MF_NOCLIPHEIGHT|MF_NOSQUISH|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -22557,7 +22567,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
100, // mass
0, // damage
sfx_None, // activesound
MF_SCENERY|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPTHING|MF_NOSQUISH, // flags
MF_SCENERY|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPTHING|MF_NOSQUISH|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -22584,7 +22594,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
100, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPTHING|MF_NOCLIPHEIGHT, // flags
MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPTHING|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},
@ -29318,7 +29328,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
{ // MT_SPECIAL_UFO
-1, // doomednum
S_CHAOSEMERALD1, // spawnstate
S_INVISIBLE, // spawnstate
101, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound

View file

@ -695,6 +695,7 @@ typedef enum sprite
SPR_NSTR, // NiGHTS star
SPR_EMBM, // Emblem
SPR_EMRC, // Chaos Emeralds
SPR_SEMR, // Super Emeralds
SPR_ESPK,
SPR_SHRD, // Emerald Hunt
@ -1345,6 +1346,8 @@ typedef enum sprite
SPR_UFOB,
SPR_UFOA,
SPR_UFOS,
SPR_SSCA,
SPR_SSCB,
SPR_UQMK,
@ -2256,6 +2259,11 @@ typedef enum state
S_CHAOSEMERALD2,
S_CHAOSEMERALD_UNDER,
// Super Emeralds
S_SUPEREMERALD1,
S_SUPEREMERALD2,
S_SUPEREMERALD_UNDER,
S_EMERALDSPARK1,
S_EMERALDSPARK2,
S_EMERALDSPARK3,
@ -5610,6 +5618,8 @@ typedef enum state
S_SPECIAL_UFO_POD,
S_SPECIAL_UFO_OVERLAY,
S_SPECIAL_UFO_GLASS,
S_SPECIAL_UFO_GLASS_UNDER,
S_SPECIAL_UFO_ARM,
S_SPECIAL_UFO_STEM,

View file

@ -13,6 +13,8 @@
#include "k_kart.h"
#include "k_battle.h"
#include "k_grandprix.h"
#include "k_specialstage.h"
#include "k_objects.h"
#include "k_boss.h"
#include "k_color.h"
#include "k_director.h"
@ -77,6 +79,9 @@ patch_t *kp_facehighlight[8];
static patch_t *kp_nocontestminimap;
static patch_t *kp_spbminimap;
static patch_t *kp_wouldyoustillcatchmeifiwereaworm;
static patch_t *kp_catcherminimap;
static patch_t *kp_emeraldminimap;
static patch_t *kp_capsuleminimap[3];
static patch_t *kp_ringsticker[2];
@ -348,7 +353,13 @@ void K_LoadKartHUDGraphics(void)
// Special minimap icons
HU_UpdatePatch(&kp_nocontestminimap, "MINIDEAD");
HU_UpdatePatch(&kp_spbminimap, "SPBMMAP");
HU_UpdatePatch(&kp_wouldyoustillcatchmeifiwereaworm, "MINIPROG");
HU_UpdatePatch(&kp_catcherminimap, "UFOMAP");
HU_UpdatePatch(&kp_emeraldminimap, "EMEMAP");
HU_UpdatePatch(&kp_capsuleminimap[0], "MINICAP1");
HU_UpdatePatch(&kp_capsuleminimap[1], "MINICAP2");
HU_UpdatePatch(&kp_capsuleminimap[2], "MINICAP3");
@ -1662,17 +1673,27 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT32 splitflags, U
if (modeattacking & ATTACKING_SPB && stplyr->SPBdistance > 0)
{
UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, stplyr->skincolor, GTC_CACHE);
int ybar = 180;
int widthbar = 120;
INT32 ybar = 180;
INT32 widthbar = 120, xbar = 160 - widthbar/2, currentx;
INT32 barflags = V_SNAPTOBOTTOM|V_SLIDEIN;
V_DrawFill(160 - widthbar / 2, ybar, widthbar, 1, 6);
V_DrawMappedPatch(160 + widthbar/2 - 7, ybar - 7, FRACUNIT, faceprefix[stplyr->skin][FACE_MINIMAP], colormap);
V_DrawScaledPatch(xbar, ybar - 2, barflags, kp_wouldyoustillcatchmeifiwereaworm);
V_DrawMappedPatch(160 + widthbar/2 - 7, ybar - 7, barflags, faceprefix[stplyr->skin][FACE_MINIMAP], colormap);
// vibes-based math
int bombxoff = (stplyr->SPBdistance/mapobjectscale - mobjinfo[MT_SPB].radius/FRACUNIT - mobjinfo[MT_PLAYER].radius/FRACUNIT) * 8;
bombxoff = sqrt(bombxoff) - 5;
bombxoff = max(0, min(bombxoff, widthbar));
V_DrawScaledPatch(160 + widthbar/2 - bombxoff, ybar - 7, FRACUNIT, W_CachePatchName("SPBMMAP", PU_CACHE));
currentx = (stplyr->SPBdistance/mapobjectscale - mobjinfo[MT_SPB].radius/FRACUNIT - mobjinfo[MT_PLAYER].radius/FRACUNIT) * 8;
if (currentx > 0)
{
currentx = sqrt(currentx);
if (currentx > widthbar)
currentx = widthbar;
}
else
{
currentx = 0;
}
V_DrawScaledPatch(xbar - currentx - 5, ybar - 7, barflags, kp_spbminimap);
}
}
@ -3024,7 +3045,7 @@ static void K_drawKartWanted(void)
}
if (battlewanted[0] != -1)
colormap = R_GetTranslationColormap(0, players[battlewanted[0]].skincolor, GTC_CACHE);
colormap = R_GetTranslationColormap(TC_DEFAULT, players[battlewanted[0]].skincolor, GTC_CACHE);
V_DrawFixedPatch(basex<<FRACBITS, basey<<FRACBITS, FRACUNIT, V_HUDTRANS|V_SLIDEIN|(r_splitscreen < 3 ? V_SNAPTORIGHT : 0)|V_SNAPTOBOTTOM, (r_splitscreen > 1 ? kp_wantedsplit : kp_wanted), colormap);
/*if (basey2)
V_DrawFixedPatch(basex<<FRACBITS, basey2<<FRACBITS, FRACUNIT, V_HUDTRANS|V_SLIDEIN|V_SNAPTOTOP, (splitscreen == 3 ? kp_wantedsplit : kp_wanted), colormap); // < used for 4p splits.*/
@ -3552,6 +3573,47 @@ static void K_drawKartNameTags(void)
}
}
#define PROGRESSION_BAR_WIDTH 120
static INT32 K_getKartProgressionMinimapDistance(UINT32 distancetofinish)
{
INT32 dist;
if (specialstageinfo.maxDist == 0U)
{
return 0;
}
dist = specialstageinfo.maxDist/PROGRESSION_BAR_WIDTH;
dist = (specialstageinfo.maxDist-distancetofinish)/dist;
if (dist > PROGRESSION_BAR_WIDTH)
{
return PROGRESSION_BAR_WIDTH;
}
if (dist < 0)
{
return 0;
}
return dist;
}
static void K_drawKartProgressionMinimapIcon(UINT32 distancetofinish, INT32 hudx, INT32 hudy, INT32 flags, patch_t *icon, UINT8 *colormap)
{
if (distancetofinish == UINT32_MAX)
return;
hudx += K_getKartProgressionMinimapDistance(distancetofinish);
hudx = ((hudx - (SHORT(icon->width)/2))<<FRACBITS);
hudy = ((hudy - (SHORT(icon->height)/2))<<FRACBITS);
V_DrawFixedPatch(hudx, hudy, FRACUNIT, flags, icon, colormap);
}
static void K_drawKartMinimapIcon(fixed_t objx, fixed_t objy, INT32 hudx, INT32 hudy, INT32 flags, patch_t *icon, UINT8 *colormap)
{
// amnum xpos & ypos are the icon's speed around the HUD.
@ -3570,8 +3632,8 @@ static void K_drawKartMinimapIcon(fixed_t objx, fixed_t objy, INT32 hudx, INT32
if (encoremode)
amnumxpos = -amnumxpos;
amxpos = amnumxpos + ((hudx + (SHORT(minimapinfo.minimap_pic->width)-SHORT(icon->width))/2)<<FRACBITS);
amypos = amnumypos + ((hudy + (SHORT(minimapinfo.minimap_pic->height)-SHORT(icon->height))/2)<<FRACBITS);
amxpos = amnumxpos + ((hudx - (SHORT(icon->width))/2)<<FRACBITS);
amypos = amnumypos + ((hudy - (SHORT(icon->height))/2)<<FRACBITS);
V_DrawFixedPatch(amxpos, amypos, FRACUNIT, flags, icon, colormap);
}
@ -3587,8 +3649,8 @@ static void K_drawKartMinimapDot(fixed_t objx, fixed_t objy, INT32 hudx, INT32 h
if (encoremode)
amnumxpos = -amnumxpos;
amxpos = (amnumxpos / FRACUNIT) + (SHORT(minimapinfo.minimap_pic->width) / 2);
amypos = (amnumypos / FRACUNIT) + (SHORT(minimapinfo.minimap_pic->height) / 2);
amxpos = (amnumxpos / FRACUNIT);
amypos = (amnumypos / FRACUNIT);
if (flags & V_NOSCALESTART)
{
@ -3634,17 +3696,26 @@ static void K_drawKartMinimapWaypoint(waypoint_t *wp, INT32 hudx, INT32 hudy, IN
static void K_drawKartMinimap(void)
{
patch_t *workingPic;
INT32 i = 0;
INT32 x, y;
INT32 minimaptrans = 4;
INT32 splitflags = 0;
UINT8 skin = 0;
UINT8 *colormap = NULL;
SINT8 localplayers[MAXSPLITSCREENPLAYERS];
SINT8 numlocalplayers = 0;
mobj_t *mobj, *next; // for SPB drawing (or any other item(s) we may wanna draw, I dunno!)
fixed_t interpx, interpy;
boolean doprogressionbar = false;
boolean dofade = false, doencore = false;
// Draw the HUD only when playing in a level.
// hu_stuff needs this, unlike st_stuff.
if (gamestate != GS_LEVEL)
@ -3655,16 +3726,58 @@ static void K_drawKartMinimap(void)
if (stplyr != &players[displayplayers[0]])
return;
if (minimapinfo.minimap_pic == NULL)
if (specialstageinfo.valid == true)
{
return; // no pic, just get outta here
// future work: maybe make this a unique gametype rule?
// I would do this now if it were easier to get the
// distancetofinish for an arbitrary object. ~toast 070423
doprogressionbar = true;
}
if (r_splitscreen < 2) // 1/2P right aligned
if (doprogressionbar == false)
{
splitflags = (V_SLIDEIN|V_SNAPTORIGHT);
if (minimapinfo.minimap_pic == NULL)
{
return; // no pic, just get outta here
}
else if (r_splitscreen < 2) // 1/2P right aligned
{
splitflags = (V_SLIDEIN|V_SNAPTORIGHT);
}
else if (r_splitscreen == 3) // 4P splits
{
dofade = true;
}
// 3P lives in the middle of the bottom right
// viewport and shouldn't fade in OR slide
x = MINI_X;
y = MINI_Y;
workingPic = minimapinfo.minimap_pic;
doencore = encoremode;
}
else if (r_splitscreen == 3) // 4P centered
else
{
x = BASEVIDWIDTH/2;
if (r_splitscreen > 0)
{
y = BASEVIDHEIGHT/2;
dofade = true;
}
else
{
y = 180;
splitflags = (V_SLIDEIN|V_SNAPTOBOTTOM);
}
workingPic = kp_wouldyoustillcatchmeifiwereaworm;
}
if (dofade)
{
const tic_t length = TICRATE/2;
@ -3672,34 +3785,49 @@ static void K_drawKartMinimap(void)
return;
if (lt_exitticker < length)
minimaptrans = (((INT32)lt_exitticker)*minimaptrans)/((INT32)length);
if (!minimaptrans)
return;
}
// 3P lives in the middle of the bottom right player and shouldn't fade in OR slide
if (!minimaptrans)
return;
x = MINI_X - (SHORT(minimapinfo.minimap_pic->width)/2);
y = MINI_Y - (SHORT(minimapinfo.minimap_pic->height)/2);
minimaptrans = ((10-minimaptrans)<<FF_TRANSSHIFT);
if (encoremode)
V_DrawScaledPatch(x+SHORT(minimapinfo.minimap_pic->width), y, splitflags|minimaptrans|V_FLIP, minimapinfo.minimap_pic);
if (doencore)
{
V_DrawScaledPatch(
x + (SHORT(workingPic->width)/2),
y - (SHORT(workingPic->height)/2),
splitflags|minimaptrans|V_FLIP,
workingPic
);
}
else
V_DrawScaledPatch(x, y, splitflags|minimaptrans, minimapinfo.minimap_pic);
{
V_DrawScaledPatch(
x - (SHORT(workingPic->width)/2),
y - (SHORT(workingPic->height)/2),
splitflags|minimaptrans,
workingPic
);
}
// most icons will be rendered semi-ghostly.
splitflags |= V_HUDTRANSHALF;
// let offsets transfer to the heads, too!
if (encoremode)
x += SHORT(minimapinfo.minimap_pic->leftoffset);
if (doencore)
x += SHORT(workingPic->leftoffset);
else
x -= SHORT(minimapinfo.minimap_pic->leftoffset);
y -= SHORT(minimapinfo.minimap_pic->topoffset);
x -= SHORT(workingPic->leftoffset);
y -= SHORT(workingPic->topoffset);
if (doprogressionbar == true)
{
x -= PROGRESSION_BAR_WIDTH/2;
}
// Draw the super item in Battle
if ((gametyperules & GTR_OVERTIME) && battleovertime.enabled)
if (doprogressionbar == false && (gametyperules & GTR_OVERTIME) && battleovertime.enabled)
{
if (battleovertime.enabled >= 10*TICRATE || (battleovertime.enabled & 1))
{
@ -3717,7 +3845,7 @@ static void K_drawKartMinimap(void)
localplayers[i] = -1;
// Player's tiny icons on the Automap. (drawn opposite direction so player 1 is drawn last in splitscreen)
if (ghosts)
if (ghosts && doprogressionbar == true) // future work: show ghosts on progression bar
{
demoghost *g = ghosts;
while (g)
@ -3742,19 +3870,15 @@ static void K_drawKartMinimap(void)
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, faceprefix[skin][FACE_MINIMAP], colormap);
g = g->next;
}
if (!stplyr->mo || stplyr->spectator || stplyr->exiting)
return;
localplayers[numlocalplayers++] = stplyr-players;
}
else
{
for (i = MAXPLAYERS-1; i >= 0; i--)
{
if (!playeringame[i])
continue;
if (!players[i].mo || players[i].spectator || !players[i].mo->skin || players[i].exiting)
if (!players[i].mo || players[i].spectator || !players[i].mo->skin
|| (doprogressionbar == false && players[i].exiting))
continue;
// This player is out of the game!
@ -3781,7 +3905,7 @@ static void K_drawKartMinimap(void)
if (mobj->health <= 0 && (players[i].pflags & PF_NOCONTEST))
{
workingPic = kp_nocontestminimap;
R_GetTranslationColormap(0, mobj->color, GTC_CACHE);
colormap = R_GetTranslationColormap(TC_DEFAULT, mobj->color, GTC_CACHE);
if (mobj->tracer && !P_MobjWasRemoved(mobj->tracer))
mobj = mobj->tracer;
@ -3803,22 +3927,33 @@ static void K_drawKartMinimap(void)
colormap = NULL;
}
interpx = R_InterpolateFixed(mobj->old_x, mobj->x);
interpy = R_InterpolateFixed(mobj->old_y, mobj->y);
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, faceprefix[skin][FACE_MINIMAP], colormap);
// Target reticule
if (((gametyperules & GTR_CIRCUIT) && players[i].position == spbplace)
|| ((gametyperules & (GTR_BOSS|GTR_POINTLIMIT)) == GTR_POINTLIMIT && K_IsPlayerWanted(&players[i])))
if (doprogressionbar == false)
{
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, kp_wantedreticle, NULL);
interpx = R_InterpolateFixed(mobj->old_x, mobj->x);
interpy = R_InterpolateFixed(mobj->old_y, mobj->y);
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, workingPic, colormap);
// Target reticule
if (((gametyperules & GTR_CIRCUIT) && players[i].position == spbplace)
|| ((gametyperules & (GTR_BOSS|GTR_POINTLIMIT)) == GTR_POINTLIMIT && K_IsPlayerWanted(&players[i])))
{
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, kp_wantedreticle, NULL);
}
}
else
{
K_drawKartProgressionMinimapIcon(players[i].distancetofinish, x, y, splitflags, workingPic, colormap);
}
}
}
// draw minimap-pertinent objects
for (mobj = trackercap; mobj; mobj = next)
if (doprogressionbar == true)
{
// future work: support these specific objects on this
}
else for (mobj = trackercap; mobj; mobj = next)
{
next = mobj->itnext;
@ -3872,7 +4007,34 @@ static void K_drawKartMinimap(void)
}
// ...but first, any boss targets.
if (bossinfo.valid == true)
if (doprogressionbar == true)
{
if (specialstageinfo.valid == true)
{
UINT32 distancetofinish = K_GetSpecialUFODistance();
if (distancetofinish > 0 && specialstageinfo.ufo != NULL && P_MobjWasRemoved(specialstageinfo.ufo) == false)
{
colormap = NULL;
if (specialstageinfo.ufo->health > 1)
{
workingPic = kp_catcherminimap;
}
else
{
workingPic = kp_emeraldminimap;
if (specialstageinfo.ufo->color)
{
colormap = R_GetTranslationColormap(TC_DEFAULT, specialstageinfo.ufo->color, GTC_CACHE);
}
}
K_drawKartProgressionMinimapIcon(distancetofinish, x, y, splitflags, workingPic, colormap);
}
}
// future work: support boss minimap icons on the progression bar
}
else if (bossinfo.valid == true)
{
for (i = 0; i < NUMWEAKSPOTS; i++)
{
@ -3912,7 +4074,7 @@ static void K_drawKartMinimap(void)
if (mobj->health <= 0 && (players[localplayers[i]].pflags & PF_NOCONTEST))
{
workingPic = kp_nocontestminimap;
R_GetTranslationColormap(0, mobj->color, GTC_CACHE);
colormap = R_GetTranslationColormap(TC_DEFAULT, mobj->color, GTC_CACHE);
if (mobj->tracer && !P_MobjWasRemoved(mobj->tracer))
mobj = mobj->tracer;
@ -3934,20 +4096,27 @@ static void K_drawKartMinimap(void)
colormap = NULL;
}
interpx = R_InterpolateFixed(mobj->old_x, mobj->x);
interpy = R_InterpolateFixed(mobj->old_y, mobj->y);
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, workingPic, colormap);
// Target reticule
if (((gametyperules & GTR_CIRCUIT) && players[localplayers[i]].position == spbplace)
|| ((gametyperules & (GTR_BOSS|GTR_POINTLIMIT)) == GTR_POINTLIMIT && K_IsPlayerWanted(&players[localplayers[i]])))
if (doprogressionbar == false)
{
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, kp_wantedreticle, NULL);
interpx = R_InterpolateFixed(mobj->old_x, mobj->x);
interpy = R_InterpolateFixed(mobj->old_y, mobj->y);
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, workingPic, colormap);
// Target reticule
if (((gametyperules & GTR_CIRCUIT) && players[localplayers[i]].position == spbplace)
|| ((gametyperules & (GTR_BOSS|GTR_POINTLIMIT)) == GTR_POINTLIMIT && K_IsPlayerWanted(&players[localplayers[i]])))
{
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, kp_wantedreticle, NULL);
}
}
else
{
K_drawKartProgressionMinimapIcon(players[i].distancetofinish, x, y, splitflags, workingPic, colormap);
}
}
if (cv_kartdebugwaypoints.value != 0)
if (doprogressionbar == false && cv_kartdebugwaypoints.value != 0)
{
size_t idx;
@ -3968,6 +4137,8 @@ static void K_drawKartMinimap(void)
}
}
#undef PROGRESSION_BAR_WIDTH
static void K_drawKartFinish(boolean finish)
{
INT32 timer, minsplitstationary, pnum = 0, splitflags = V_SPLITSCREEN;
@ -4579,7 +4750,7 @@ static void K_drawInput(void)
else
{
UINT8 *colormap;
colormap = R_GetTranslationColormap(0, stplyr->skincolor, GTC_CACHE);
colormap = R_GetTranslationColormap(TC_DEFAULT, stplyr->skincolor, GTC_CACHE);
V_DrawFixedPatch(x<<FRACBITS, y<<FRACBITS, FRACUNIT, splitflags, kp_inputwheel[target], colormap);
}
}

View file

@ -411,9 +411,9 @@ void K_drawTargetHUD(const vector3_t* origin, player_t* player)
}
vector3_t pos = {
R_InterpolateFixed(mobj->old_x, mobj->x),
R_InterpolateFixed(mobj->old_y, mobj->y),
R_InterpolateFixed(mobj->old_z, mobj->z) + (mobj->height >> 1),
R_InterpolateFixed(mobj->old_x, mobj->x) + mobj->sprxoff,
R_InterpolateFixed(mobj->old_y, mobj->y) + mobj->spryoff,
R_InterpolateFixed(mobj->old_z, mobj->z) + mobj->sprzoff + (mobj->height >> 1),
};
targetList.push_back({mobj, pos, R_PointToDist2(origin->x, origin->y, pos.x, pos.y)});

View file

@ -8589,11 +8589,16 @@ void K_UpdateDistanceFromFinishLine(player_t *const player)
}
// nextwaypoint is now the waypoint that is in front of us
if (player->exiting || player->spectator)
if ((player->exiting && !(player->pflags & PF_NOCONTEST)) || player->spectator)
{
// Player has finished, we don't need to calculate this
player->distancetofinish = 0U;
}
else if (player->pflags & PF_NOCONTEST)
{
// We also don't need to calculate this, but there's also no need to destroy the data...
;
}
else if ((player->currentwaypoint != NULL) && (player->nextwaypoint != NULL) && (finishline != NULL))
{
const boolean useshortcuts = false;

View file

@ -24,8 +24,10 @@ extern struct specialstageinfo
{
boolean valid; ///< If true, then data in this struct is valid
UINT32 beamDist; ///< Where the exit beam is.
mobj_t *ufo; ///< The Chaos Emerald capsule.
UINT32 maxDist; ///< The distance from one end of the track to another.
UINT32 beamDist; ///< Where the exit beam is.
} specialstageinfo;
/*--------------------------------------------------

View file

@ -54,6 +54,8 @@
enum
{
UFO_PIECE_TYPE_POD,
UFO_PIECE_TYPE_GLASS,
UFO_PIECE_TYPE_GLASS_UNDER,
UFO_PIECE_TYPE_ARM,
UFO_PIECE_TYPE_STEM,
};
@ -345,6 +347,7 @@ static void UFOMove(mobj_t *ufo)
ufo->momx = 0;
ufo->momy = 0;
ufo->momz = ufo_speed(ufo);
ufo_distancetofinish(ufo) = 0;
return;
}
@ -514,6 +517,90 @@ void Obj_SpecialUFOThinker(mobj_t *ufo)
}
}
// The following is adapted from monitor.c for UFO Catcher damage
// I couldn't just exose the relevant things via k_object.h
// because they're *just* too specific to Monitors... ~toast 070423
#define shard_can_roll(o) ((o)->extravalue1)
static inline boolean
can_shard_state_roll (statenum_t state)
{
switch (state)
{
case S_MONITOR_BIG_SHARD:
case S_MONITOR_SMALL_SHARD:
return true;
default:
return false;
}
}
static void
spawn_shard
( mobj_t * part,
statenum_t state)
{
mobj_t *ufo = ufo_piece_owner(part);
// These divisions and multiplications are done on the
// offsets to give bigger increments of randomness.
const fixed_t h = FixedDiv(
ufo->height, ufo->scale);
const UINT16 rad = (ufo->radius / ufo->scale) / 4;
const UINT16 tall = (h / FRACUNIT);
mobj_t *p = P_SpawnMobjFromMobj(ufo,
P_RandomRange(PR_ITEM_DEBRIS, -(rad), rad) * 8 * FRACUNIT,
P_RandomRange(PR_ITEM_DEBRIS, -(rad), rad) * 8 * FRACUNIT,
P_RandomKey(PR_ITEM_DEBRIS, tall + 1) * 4 * FRACUNIT,
MT_MONITOR_SHARD);
P_SetScale(p, (p->destscale = p->destscale * 3));
angle_t th = R_PointToAngle2(ufo->x, ufo->y, p->x, p->y);
th -= P_RandomKey(PR_ITEM_DEBRIS, ANGLE_45) - ANGLE_22h;
p->hitlag = 0;
P_Thrust(p, th, 6 * p->scale);
p->momz = P_RandomRange(PR_ITEM_DEBRIS, 3, 10) * p->scale;
P_SetMobjState(p, state);
shard_can_roll(p) = can_shard_state_roll(state);
if (shard_can_roll(p))
{
p->rollangle = P_Random(PR_ITEM_DEBRIS);
}
if (P_RandomChance(PR_ITEM_DEBRIS, FRACUNIT/2))
{
p->renderflags |= RF_DONTDRAW;
}
}
static void
spawn_debris (mobj_t *part)
{
mobj_t *ufo = ufo_piece_owner(part);
INT32 i;
for (i = ufo->health;
i <= mobjinfo[ufo->type].spawnhealth; i += 5)
{
spawn_shard(part, S_MONITOR_BIG_SHARD);
spawn_shard(part, S_MONITOR_SMALL_SHARD);
spawn_shard(part, S_MONITOR_TWINKLE);
}
}
static void UFOCopyHitlagToPieces(mobj_t *ufo)
{
mobj_t *piece = NULL;
@ -523,6 +610,12 @@ static void UFOCopyHitlagToPieces(mobj_t *ufo)
{
piece->hitlag = ufo->hitlag;
piece->eflags = (piece->eflags & ~MFE_DAMAGEHITLAG) | (ufo->eflags & MFE_DAMAGEHITLAG);
if (ufo_piece_type(piece) == UFO_PIECE_TYPE_GLASS)
{
spawn_debris (piece);
}
piece = ufo_piece_next(piece);
}
}
@ -543,6 +636,8 @@ static void UFOKillPiece(mobj_t *piece)
switch (ufo_piece_type(piece))
{
case UFO_PIECE_TYPE_GLASS:
case UFO_PIECE_TYPE_GLASS_UNDER:
case UFO_PIECE_TYPE_STEM:
{
piece->tics = 1;
@ -686,15 +781,16 @@ boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UIN
// Speed up on damage!
ufo_speed(ufo) += addSpeed;
ufo->health = max(1, ufo->health - damage);
K_SetHitLagForObjects(ufo, inflictor, (damage / 3) + 2, true);
UFOCopyHitlagToPieces(ufo);
if (damage >= ufo->health - 1)
if (ufo->health == 1)
{
// Destroy the UFO parts, and make the emerald collectible!
UFOKillPieces(ufo);
ufo->health = 1;
ufo->flags = (ufo->flags & ~MF_SHOOTABLE) | (MF_SPECIAL|MF_PICKUPFROMBELOW);
ufo->shadowscale = FRACUNIT/3;
@ -711,7 +807,6 @@ boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UIN
S_StartSound(ufo, sfx_clawht);
S_StopSoundByID(ufo, sfx_clawzm);
P_StartQuake(64<<FRACBITS, 10);
ufo->health -= damage;
return true;
}
@ -793,18 +888,25 @@ void Obj_UFOPieceThink(mobj_t *piece)
return;
}
piece->destscale = 3 * ufo->destscale / 2;
piece->scalespeed = ufo->scalespeed;
switch (ufo_piece_type(piece))
{
case UFO_PIECE_TYPE_POD:
{
piece->destscale = 3 * ufo->destscale / 2;
UFOMoveTo(piece, ufo->x, ufo->y, ufo->z + (132 * piece->scale));
if (S_SoundPlaying(ufo, sfx_clawzm) && ufo_speed(ufo) > 70*FRACUNIT)
SpawnUFOSpeedLines(piece);
break;
}
case UFO_PIECE_TYPE_GLASS:
case UFO_PIECE_TYPE_GLASS_UNDER:
{
piece->destscale = 5 * ufo->destscale / 3;
UFOMoveTo(piece, ufo->x, ufo->y, ufo->z);
break;
}
case UFO_PIECE_TYPE_ARM:
{
fixed_t dis = (88 * piece->scale);
@ -812,6 +914,7 @@ void Obj_UFOPieceThink(mobj_t *piece)
fixed_t x = ufo->x - FixedMul(dis, FINECOSINE(piece->angle >> ANGLETOFINESHIFT));
fixed_t y = ufo->y - FixedMul(dis, FINESINE(piece->angle >> ANGLETOFINESHIFT));
piece->destscale = 3 * ufo->destscale / 2;
UFOMoveTo(piece, x, y, ufo->z + (24 * piece->scale));
piece->angle -= FixedMul(ANG2, FixedDiv(ufo_speed(ufo), UFO_BASE_SPEED));
@ -822,6 +925,7 @@ void Obj_UFOPieceThink(mobj_t *piece)
fixed_t stemZ = ufo->z + (294 * piece->scale);
fixed_t sc = FixedDiv(FixedDiv(ufo->ceilingz - stemZ, piece->scale), 15 * FRACUNIT);
piece->destscale = 3 * ufo->destscale / 2;
UFOMoveTo(piece, ufo->x, ufo->y, stemZ);
if (sc > 0)
{
@ -901,19 +1005,51 @@ static mobj_t *InitSpecialUFO(waypoint_t *start)
ufo = P_SpawnMobj(start->mobj->x, start->mobj->y, start->mobj->z, MT_SPECIAL_UFO);
ufo_waypoint(ufo) = (INT32)K_GetWaypointHeapIndex(start);
UFOUpdateDistanceToFinish(ufo);
specialstageinfo.maxDist = ufo_distancetofinish(ufo);
}
ufo_speed(ufo) = FixedMul(UFO_START_SPEED, K_GetKartGameSpeedScalar(gamespeed));
// TODO: Adjustable Special Stage emerald color
ufo->color = SKINCOLOR_CHAOSEMERALD1;
// Adjustable Special Stage emerald color/shape
{
overlay = P_SpawnMobjFromMobj(ufo, 0, 0, 0, MT_OVERLAY);
overlay = P_SpawnMobjFromMobj(ufo, 0, 0, 0, MT_OVERLAY);
P_SetTarget(&overlay->target, ufo);
overlay->color = ufo->color;
ufo->color = SKINCOLOR_CHAOSEMERALD1;
i = P_GetNextEmerald();
if (i > 0)
{
ufo->color += (i - 1) % 7;
if (i > 7)
{
// Super Emeralds
P_SetMobjState(ufo, S_SUPEREMERALD1);
P_SetMobjState(overlay, S_SUPEREMERALD_UNDER);
}
else
{
// Chaos Emerald
P_SetMobjState(ufo, S_CHAOSEMERALD1);
P_SetMobjState(overlay, S_CHAOSEMERALD_UNDER);
}
}
else
{
// Prize -- todo, currently using standard Emerald
P_SetMobjState(ufo, S_CHAOSEMERALD1);
P_SetMobjState(overlay, S_CHAOSEMERALD_UNDER);
}
// TODO: Super Emeralds / Chaos Rings
P_SetMobjState(overlay, S_CHAOSEMERALD_UNDER);
if (P_MobjWasRemoved(ufo)) // uh oh !
{
// Attempted crash prevention with custom SOC
return NULL;
}
overlay->color = ufo->color;
P_SetTarget(&overlay->target, ufo);
ufo->sprzoff = 32 * mapobjectscale;
}
// Create UFO pieces.
// First: UFO center.
@ -930,6 +1066,39 @@ static mobj_t *InitSpecialUFO(waypoint_t *start)
P_SetTarget(&ufo_pieces(ufo), piece);
prevPiece = piece;
// Next, the glass ball.
{
piece = P_SpawnMobjFromMobj(ufo, 0, 0, 0, MT_SPECIAL_UFO_PIECE);
P_SetTarget(&ufo_piece_owner(piece), ufo);
P_SetMobjState(piece, S_SPECIAL_UFO_GLASS);
ufo_piece_type(piece) = UFO_PIECE_TYPE_GLASS;
/*overlay = P_SpawnMobjFromMobj(piece, 0, 0, 0, MT_OVERLAY);
P_SetTarget(&overlay->target, piece);
P_SetMobjState(overlay, S_SPECIAL_UFO_GLASS_UNDER);
overlay->dispoffset = -20;*/
P_SetTarget(&ufo_piece_next(prevPiece), piece);
P_SetTarget(&ufo_piece_prev(piece), prevPiece);
prevPiece = piece;
}
// This SHOULD have been an MT_OVERLAY... but it simply doesn't
// draw-order stack with the Emerald correctly any other way.
{
piece = P_SpawnMobjFromMobj(ufo, 0, 0, 0, MT_SPECIAL_UFO_PIECE);
P_SetTarget(&ufo_piece_owner(piece), ufo);
P_SetMobjState(piece, S_SPECIAL_UFO_GLASS_UNDER);
ufo_piece_type(piece) = UFO_PIECE_TYPE_GLASS_UNDER;
piece->dispoffset = -2;
P_SetTarget(&ufo_piece_next(prevPiece), piece);
P_SetTarget(&ufo_piece_prev(piece), prevPiece);
prevPiece = piece;
}
// Add the catcher arms.
for (i = 0; i < UFO_NUMARMS; i++)
{

View file

@ -313,15 +313,29 @@ boolean P_PlayerMoving(INT32 pnum)
//
UINT8 P_GetNextEmerald(void)
{
INT16 mapnum = gamemap-1;
cupheader_t *cup = NULL;
if (mapnum > nummapheaders || !mapheaderinfo[mapnum])
if (grandprixinfo.gp == true)
{
cup = grandprixinfo.cup;
}
if (cup == NULL)
{
INT16 mapnum = gamemap-1;
if (mapnum < nummapheaders && mapheaderinfo[mapnum])
{
cup = mapheaderinfo[mapnum]->cup;
}
}
if (cup == NULL)
{
return 0;
}
if (!mapheaderinfo[mapnum]->cup || mapheaderinfo[mapnum]->cup->cachedlevels[CUPCACHE_SPECIAL] != mapnum)
return 0;
return mapheaderinfo[mapnum]->cup->emeraldnum;
return cup->emeraldnum;
}
//