Merge branch 'spb-attack' into 'master'

SPB Attack

See merge request KartKrew/Kart!992
This commit is contained in:
James R 2023-03-05 01:26:32 +00:00
commit d45ba09ac0
20 changed files with 184 additions and 12 deletions

View file

@ -923,8 +923,10 @@ boolean CON_Responder(event_t *ev)
// check for console toggle key
if (ev->type != ev_console)
{
#ifndef DEVELOP // I have driven this course 45 times and I just want to give myself rocketsneakers
if (modeattacking || metalrecording || marathonmode)
return false;
#endif
if (ev->data1 >= NUMKEYS) // See also: HUD_Responder
{

View file

@ -671,6 +671,8 @@ struct player_t
UINT8 eggmanTransferDelay;
fixed_t SPBdistance;
UINT8 tripwireReboundDelay; // When failing Tripwire, brieftly lock out speed-based tripwire pass (anti-cheese)
mobj_t *stumbleIndicator;

View file

@ -6402,6 +6402,7 @@ struct int_const_s const INT_CONST[] = {
// Map emblem var flags
{"ME_ENCORE",ME_ENCORE},
{"ME_SPBATTACK",ME_SPBATTACK},
// p_local.h constants
{"FLOATSPEED",FLOATSPEED},

View file

@ -121,11 +121,12 @@ struct recorddata_t
};
// mapvisited is now a set of flags that says what we've done in the map.
#define MV_VISITED (1)
#define MV_BEATEN (1<<1)
#define MV_ENCORE (1<<2)
#define MV_MAX (MV_VISITED|MV_BEATEN|MV_ENCORE)
#define MV_MP ((MV_MAX+1)<<1)
#define MV_VISITED (1)
#define MV_BEATEN (1<<1)
#define MV_ENCORE (1<<2)
#define MV_SPBATTACK (1<<3)
#define MV_MAX (MV_VISITED|MV_BEATEN|MV_ENCORE|MV_SPBATTACK)
#define MV_MP ((MV_MAX+1)<<1)
// Set if homebrew PWAD stuff has been added.
extern boolean modifiedgame;
@ -139,6 +140,7 @@ extern boolean metalrecording;
#define ATTACKING_NONE 0
#define ATTACKING_TIME 1
#define ATTACKING_LAP (1<<1)
#define ATTACKING_SPB (1<<2)
extern UINT8 modeattacking;
// menu demo things

View file

@ -119,7 +119,7 @@ demoghost *ghosts = NULL;
#define DEMOVERSION 0x0007
#define DEMOHEADER "\xF0" "KartReplay" "\x0F"
#define DF_ATTACKMASK (ATTACKING_TIME|ATTACKING_LAP) // This demo contains time/lap data
#define DF_ATTACKMASK (ATTACKING_TIME|ATTACKING_LAP|ATTACKING_SPB) // This demo contains time/lap data
#define DF_GHOST 0x08 // This demo contains ghost data too!

View file

@ -512,10 +512,19 @@ void G_UpdateTimeStickerMedals(UINT16 map, boolean showownrecord)
{
break;
}
case ET_MAP:
{
if (emblem->flags & ME_SPBATTACK && cv_dummyspbattack.value)
break;
goto bademblem;
}
default:
goto bademblem;
}
if (cv_dummyspbattack.value && !(emblem->flags & ME_SPBATTACK))
return;
if (!gamedata->collected[(emblem-emblemlocations)] && gonnadrawtime)
break;
@ -2442,7 +2451,18 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
itemamount = 0;
growshrinktimer = 0;
bumper = ((gametyperules & GTR_BUMPERS) ? K_StartingBumperCount() : 0);
rings = ((gametyperules & GTR_SPHERES) ? 0 : 5);
if (gametyperules & GTR_SPHERES)
{
rings = 0;
}
else if (modeattacking & ATTACKING_SPB)
{
rings = 20;
}
else
{
rings = 5;
}
spheres = 0;
kickstartaccel = 0;
khudfault = 0;
@ -3697,6 +3717,11 @@ static void G_UpdateVisited(void)
mapheaderinfo[prevmap]->mapvisited |= MV_ENCORE;
}
if (modeattacking & ATTACKING_SPB)
{
mapheaderinfo[prevmap]->mapvisited |= MV_SPBATTACK;
}
if (modeattacking)
G_UpdateRecordReplays();

View file

@ -1654,6 +1654,22 @@ void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT32 splitflags, U
workx += 6;
}
}
if (modeattacking & ATTACKING_SPB && stplyr->SPBdistance > 0)
{
UINT8 *colormap = R_GetTranslationColormap(stplyr->skin, stplyr->skincolor, GTC_CACHE);
int ybar = 180;
int widthbar = 120;
V_DrawFill(160 - widthbar / 2, ybar, widthbar, 1, 6);
V_DrawMappedPatch(160 + widthbar/2 - 7, ybar - 7, FRACUNIT, 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));
}
}
static fixed_t K_DrawKartPositionNumPatch(UINT8 num, UINT8 *color, fixed_t x, fixed_t y, fixed_t scale, INT32 flags)

View file

@ -4095,6 +4095,13 @@ INT32 K_ExplodePlayer(player_t *player, mobj_t *inflictor, mobj_t *source) // A
{
if (inflictor->type == MT_SPBEXPLOSION && inflictor->movefactor)
{
if (modeattacking & ATTACKING_SPB)
{
P_DamageMobj(player->mo, inflictor, source, 1, DMG_INSTAKILL);
player->SPBdistance = 0;
S_StopMusic();
}
spbMultiplier = inflictor->movefactor;
if (spbMultiplier <= 0)

View file

@ -232,6 +232,7 @@ typedef enum
ta_replay = 0,
ta_guest,
ta_ghosts,
ta_spb,
ta_spacer,
ta_start,
} ta_e;
@ -761,6 +762,8 @@ extern consvar_t cv_dummykartspeed;
extern consvar_t cv_dummygpencore;
extern consvar_t cv_dummymatchbots;
extern consvar_t cv_dummyspbattack;
void M_SetupDifficultyOptions(INT32 choice);
void M_SetupDifficultySelect(INT32 choice);
void M_DifficultySelectInputs(INT32 choice);
@ -796,6 +799,8 @@ void M_StartTimeAttack(INT32 choice);
void M_ReplayTimeAttack(INT32 choice);
void M_HandleStaffReplay(INT32 choice);
void M_SetGuestReplay(INT32 choice);
void M_TimeAttackTick(void);
boolean M_TimeAttackInputs (INT32 choice);
// MP selection
void M_MPOptSelect(INT32 choice);
@ -1140,6 +1145,14 @@ void M_DrawAddons(void);
#define TILEFLIP_MAX 16
extern struct timeattackmenu_s {
tic_t ticker; // How long the menu's been open for
tic_t spbflicker; // used for SPB flicker-in
} timeattackmenu;
// Keep track of some pause menu data for visual goodness.
extern struct challengesmenu_s {

View file

@ -2371,6 +2371,28 @@ void M_DrawTimeAttack(void)
V_DrawRightAlignedString(rightedge-12, timeheight, highlightflags, "BEST TIME:");
K_drawKartTimestamp(timerec, 162+t, timeheight+6, 0, 1);
// SPB Attack control hint + menu overlay
if (levellist.newgametype == GT_RACE && levellist.levelsearch.timeattack == true)
{
const UINT8 anim_duration = 16;
const UINT8 anim = (timeattackmenu.ticker % (anim_duration * 2)) < anim_duration;
INT32 buttonx = 162 + t;
INT32 buttony = timeheight;
if (anim)
V_DrawScaledPatch(buttonx + 35, buttony - 3, V_SNAPTOLEFT, W_CachePatchName("TLB_I", PU_CACHE));
else
V_DrawScaledPatch(buttonx + 35, buttony - 3, V_SNAPTOLEFT, W_CachePatchName("TLB_IB", PU_CACHE));
if (timeattackmenu.ticker > (timeattackmenu.spbflicker + TICRATE/6) || timeattackmenu.ticker % 2)
{
if (cv_dummyspbattack.value)
V_DrawMappedPatch(buttonx + 7, buttony - 1, 0, W_CachePatchName("K_SPBATK", PU_CACHE), R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_RED, GTC_MENUCACHE));
}
}
}
else
opty = 80;

View file

@ -1138,6 +1138,8 @@ void M_Init(void)
CV_RegisterVar(&cv_dummygpencore);
CV_RegisterVar(&cv_dummymatchbots);
CV_RegisterVar(&cv_dummyspbattack);
CV_RegisterVar(&cv_dummyaddonsearch);
M_UpdateMenuBGImage(true);

View file

@ -189,6 +189,13 @@ static kartitems_t K_KartItemReelTimeAttack[] =
KITEM_NONE
};
static kartitems_t K_KartItemReelSPBAttack[] =
{
KITEM_GACHABOM,
KITEM_SUPERRING,
KITEM_NONE
};
static kartitems_t K_KartItemReelBreakTheCapsules[] =
{
KITEM_GACHABOM,
@ -1237,6 +1244,10 @@ void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulet
{
presetlist = K_KartItemReelBreakTheCapsules;
}
else if (modeattacking & ATTACKING_SPB)
{
presetlist = K_KartItemReelSPBAttack;
}
for (i = 0; presetlist[i] != KITEM_NONE; i++)
{

View file

@ -1029,6 +1029,9 @@ UINT8 M_CompletionEmblems(void) // Bah! Duplication sucks, but it's for a separa
if (embtype & ME_ENCORE)
flags |= MV_ENCORE;
if (embtype & ME_SPBATTACK)
flags |= MV_SPBATTACK;
res = ((mapheaderinfo[levelnum]->mapvisited & flags) == flags);
gamedata->collected[i] = res;

View file

@ -74,6 +74,7 @@ struct conditionset_t
// Map emblem flags
#define ME_ENCORE 1 // Achieve in Encore
#define ME_SPBATTACK 2 // Achieve in SPB Attack
struct emblem_t
{

View file

@ -10,6 +10,47 @@
#include "../m_misc.h" // M_MkdirEach
#include "../z_zone.h" // Z_StrDup/Z_Free
static void CV_SPBAttackChanged(void)
{
G_UpdateTimeStickerMedals(levellist.choosemap, false);
}
consvar_t cv_dummyspbattack = CVAR_INIT ("dummyspbattack", "Off", CV_HIDDEN|CV_CALL, CV_OnOff, CV_SPBAttackChanged);
struct timeattackmenu_s timeattackmenu;
void M_TimeAttackTick(void)
{
timeattackmenu.ticker++;
}
boolean M_TimeAttackInputs(INT32 ch)
{
const UINT8 pid = 0;
const boolean buttonR = M_MenuButtonPressed(pid, MBT_R);
(void) ch;
if (buttonR && levellist.newgametype == GT_RACE)
{
CV_AddValue(&cv_dummyspbattack, 1);
timeattackmenu.spbflicker = timeattackmenu.ticker;
if (cv_dummyspbattack.value)
{
S_StartSound(NULL, sfx_s3k9f);
S_StopSoundByID(NULL, sfx_s3k92);
}
else
{
S_StartSound(NULL, sfx_s3k92);
S_StopSoundByID(NULL, sfx_s3k9f);
}
return true;
}
return false;
}
// see ta_e
menuitem_t PLAY_TimeAttack[] =
{
@ -30,10 +71,10 @@ menu_t PLAY_TimeAttackDef = {
NULL,
2, 5,
M_DrawTimeAttack,
M_TimeAttackTick,
NULL,
NULL,
NULL,
NULL
M_TimeAttackInputs
};
@ -426,6 +467,11 @@ void M_StartTimeAttack(INT32 choice)
modeattacking |= ATTACKING_LAP;
}
if (cv_dummyspbattack.value)
{
modeattacking |= ATTACKING_SPB;
}
// Still need to reset devmode
cht_debug = 0;
emeralds = 0;

View file

@ -230,6 +230,9 @@ boolean M_LevelListFromGametype(INT16 gt)
first = false;
}
if (levellist.levelsearch.timeattack == false || levellist.newgametype != GT_RACE)
CV_SetValue(&cv_dummyspbattack, 0);
// Obviously go to Cup Select in gametypes that have cups.
// Use a really long level select in gametypes that don't use cups.

View file

@ -83,6 +83,9 @@ static void SPBMantaRings(mobj_t *spb)
const fixed_t floatHeight = 24 * spb->scale;
fixed_t floorDist = INT32_MAX;
if (modeattacking & ATTACKING_SPB)
return; // no one else to use 'em
if (leveltime % SPB_MANTA_VRATE == 0)
{
spb_manta_vscale(spb) = max(spb_manta_vscale(spb) - 1, SPB_MANTA_VMAX);
@ -730,6 +733,8 @@ static void SPBChase(mobj_t *spb, mobj_t *bestMobj)
dist = P_AproxDistance(P_AproxDistance(spb->x - chase->x, spb->y - chase->y), spb->z - chase->z);
chasePlayer->SPBdistance = dist;
desiredSpeed = FixedMul(baseSpeed, FRACUNIT + FixedDiv(dist - range, range));
if (desiredSpeed < baseSpeed)

View file

@ -1921,7 +1921,7 @@ static boolean P_KillPlayer(player_t *player, mobj_t *inflictor, mobj_t *source,
return false;
}
if (!player->exiting && specialstageinfo.valid == true)
if (!player->exiting && (specialstageinfo.valid == true || modeattacking & ATTACKING_SPB))
{
player->pflags |= PF_NOCONTEST;
P_DoPlayerExit(player);

View file

@ -12175,7 +12175,7 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i)
boolean isRingCapsule = (mthing->args[0] < 1 || mthing->args[0] == KITEM_SUPERRING || mthing->args[0] >= NUMKARTITEMS);
// don't spawn ring capsules in GTR_SPHERES gametypes
if (isRingCapsule && (gametyperules & GTR_SPHERES))
if (isRingCapsule && ((gametyperules & GTR_SPHERES) || (modeattacking & ATTACKING_SPB)))
return false;
// in record attack, only spawn ring capsules
@ -12185,6 +12185,10 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i)
return false;
}
break;
case MT_RING:
if (modeattacking & ATTACKING_SPB)
return false;
break;
default:
break;
}
@ -12224,7 +12228,7 @@ static mobjtype_t P_GetMobjtypeSubstitute(mapthing_t *mthing, mobjtype_t i)
if ((i == MT_RANDOMITEM) && (gametyperules & (GTR_PAPERITEMS|GTR_CIRCUIT)) == (GTR_PAPERITEMS|GTR_CIRCUIT))
return MT_PAPERITEMSPOT;
return i;
}

View file

@ -1973,6 +1973,13 @@ static void K_HandleLapIncrement(player_t *player)
rainbowstartavailable = false;
}
if (player->laps == 1 && modeattacking & ATTACKING_SPB)
{
P_SpawnMobj(player->mo->x - FixedMul(1000*mapobjectscale, FINECOSINE(player->mo->angle >> ANGLETOFINESHIFT)),
player->mo->y - FixedMul(1000*mapobjectscale, FINESINE(player->mo->angle >> ANGLETOFINESHIFT)),
player->mo->z, MT_SPB);
}
if (netgame && player->laps > numlaps)
CON_LogMessage(va(M_GetText("%s has finished the race.\n"), player_names[player-players]));