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 unlockables-undefeatable
# Conflicts: # src/k_menudraw.c # src/k_menufunc.c
This commit is contained in:
commit
8e88a840bb
17 changed files with 456 additions and 200 deletions
|
|
@ -132,9 +132,12 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
|
|||
k_roulette.c
|
||||
)
|
||||
|
||||
if("${CMAKE_COMPILER_IS_GNUCC}" AND "${CMAKE_SYSTEM_NAME}" MATCHES "Windows" AND NOT "${SRB2_CONFIG_SYSTEM_LIBRARIES}" AND NOT "${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}")
|
||||
if("${CMAKE_COMPILER_IS_GNUCC}" AND "${CMAKE_SYSTEM_NAME}" MATCHES "Windows")
|
||||
target_link_options(SRB2SDL2 PRIVATE "-Wl,--disable-dynamicbase")
|
||||
if(NOT "${SRB2_CONFIG_SYSTEM_LIBRARIES}" AND NOT "${SRB2_CONFIG_SHARED_INTERNAL_LIBRARIES}")
|
||||
# On MinGW with internal libraries, link the standard library statically
|
||||
target_link_options(SRB2SDL2 PRIVATE "-static")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_compile_features(SRB2SDL2 PRIVATE c_std_11 cxx_std_17)
|
||||
|
|
|
|||
|
|
@ -1124,14 +1124,14 @@ static void IdentifyVersion(void)
|
|||
////
|
||||
#define TEXTURESNAME "MISC_TEXTURES.pk3"
|
||||
#define MAPSNAME "MISC_MAPS.pk3"
|
||||
#define PATCHNAME "MISC_PATCH.pk3"
|
||||
#define PATCHNAME "MISC_SCRIPTS.pk3"
|
||||
#define MUSICNAME "MISC_MUSIC.PK3"
|
||||
////
|
||||
#else
|
||||
////
|
||||
#define TEXTURESNAME "textures.pk3"
|
||||
#define MAPSNAME "maps.pk3"
|
||||
#define PATCHNAME "patch.pk3"
|
||||
#define PATCHNAME "scripts.pk3"
|
||||
#define MUSICNAME "music.pk3"
|
||||
////
|
||||
#endif
|
||||
|
|
@ -1455,7 +1455,7 @@ void D_SRB2Main(void)
|
|||
mainwads++; // maps.pk3
|
||||
mainwads++; // followers.pk3
|
||||
#ifdef USE_PATCH_FILE
|
||||
mainwads++; // patch.pk3
|
||||
mainwads++; // scripts.pk3
|
||||
#endif
|
||||
#ifdef UNLOCKTESTING
|
||||
mainwads++; // unlocks.pk3
|
||||
|
|
|
|||
|
|
@ -1416,6 +1416,7 @@ void PT_FileFragment(void)
|
|||
|| !strcmp(filename, "chars.pk3")
|
||||
|| !strcmp(filename, "maps.pk3")
|
||||
|| !strcmp(filename, "patch.pk3")
|
||||
|| !strcmp(filename, "scripts.pk3")
|
||||
|| !strcmp(filename, "sounds.pk3")
|
||||
|| !strcmp(filename, "music.pk3")
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2981,6 +2981,28 @@ void readwipes(MYFILE *f)
|
|||
// SRB2KART
|
||||
//
|
||||
|
||||
static void invalidateacrosscups(UINT16 map)
|
||||
{
|
||||
cupheader_t *cup = kartcupheaders;
|
||||
UINT8 i;
|
||||
|
||||
if (map >= nummapheaders)
|
||||
return;
|
||||
|
||||
while (cup)
|
||||
{
|
||||
for (i = 0; i < CUPCACHE_MAX; i++)
|
||||
{
|
||||
if (cup->cachedlevels[i] != map)
|
||||
continue;
|
||||
cup->cachedlevels[i] = NEXTMAP_INVALID;
|
||||
}
|
||||
cup = cup->next;
|
||||
}
|
||||
|
||||
mapheaderinfo[map]->cup = NULL;
|
||||
}
|
||||
|
||||
void readcupheader(MYFILE *f, cupheader_t *cup)
|
||||
{
|
||||
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
|
||||
|
|
@ -3037,7 +3059,7 @@ void readcupheader(MYFILE *f, cupheader_t *cup)
|
|||
cup->levellist[cup->numlevels] = NULL;
|
||||
if (cup->cachedlevels[cup->numlevels] == NEXTMAP_INVALID)
|
||||
continue;
|
||||
mapheaderinfo[cup->cachedlevels[cup->numlevels]]->cup = NULL;
|
||||
invalidateacrosscups(cup->cachedlevels[cup->numlevels]);
|
||||
}
|
||||
|
||||
tmp = strtok(word2,",");
|
||||
|
|
@ -3060,6 +3082,9 @@ void readcupheader(MYFILE *f, cupheader_t *cup)
|
|||
cup->numbonus--;
|
||||
Z_Free(cup->levellist[CUPCACHE_BONUS + cup->numbonus]);
|
||||
cup->levellist[CUPCACHE_BONUS + cup->numbonus] = NULL;
|
||||
if (cup->cachedlevels[CUPCACHE_BONUS + cup->numbonus] == NEXTMAP_INVALID)
|
||||
continue;
|
||||
invalidateacrosscups(cup->cachedlevels[CUPCACHE_BONUS + cup->numbonus]);
|
||||
}
|
||||
|
||||
tmp = strtok(word2,",");
|
||||
|
|
@ -3077,6 +3102,7 @@ void readcupheader(MYFILE *f, cupheader_t *cup)
|
|||
}
|
||||
else if (fastcmp(word, "SPECIALSTAGE"))
|
||||
{
|
||||
invalidateacrosscups(cup->cachedlevels[CUPCACHE_SPECIAL]);
|
||||
Z_Free(cup->levellist[CUPCACHE_SPECIAL]);
|
||||
cup->levellist[CUPCACHE_SPECIAL] = Z_StrDup(word2);
|
||||
cup->cachedlevels[CUPCACHE_SPECIAL] = NEXTMAP_INVALID;
|
||||
|
|
|
|||
|
|
@ -498,6 +498,8 @@ enum GameTypeRules
|
|||
GTR_LIVES = 1<<18, // Lives system, players are forced to spectate during Game Over.
|
||||
GTR_SPECIALBOTS = 1<<19, // Bot difficulty gets stronger between rounds, and the rival system is enabled.
|
||||
|
||||
GTR_NOCUPSELECT = 1<<20, // Your maps are not selected via cup. ...mutually exclusive with GTR_CAMPAIGN.
|
||||
|
||||
// free: to and including 1<<31
|
||||
};
|
||||
|
||||
|
|
|
|||
37
src/g_game.c
37
src/g_game.c
|
|
@ -3402,29 +3402,26 @@ UINT32 G_TOLFlag(INT32 pgametype)
|
|||
|
||||
INT16 G_GetFirstMapOfGametype(UINT8 pgametype)
|
||||
{
|
||||
UINT8 i = 0;
|
||||
INT16 mapnum = NEXTMAP_INVALID;
|
||||
UINT32 tol = G_TOLFlag(pgametype);
|
||||
|
||||
if ((gametypedefaultrules[pgametype] & GTR_CAMPAIGN) && kartcupheaders)
|
||||
{
|
||||
mapnum = kartcupheaders->cachedlevels[0];
|
||||
}
|
||||
levellist.cupmode = (!(gametypedefaultrules[pgametype] & GTR_NOCUPSELECT));
|
||||
levellist.timeattack = false;
|
||||
|
||||
if (mapnum >= nummapheaders)
|
||||
if (levellist.cupmode)
|
||||
{
|
||||
UINT32 tolflag = G_TOLFlag(pgametype);
|
||||
for (mapnum = 0; mapnum < nummapheaders; mapnum++)
|
||||
cupheader_t *cup = kartcupheaders;
|
||||
while (cup && mapnum >= nummapheaders)
|
||||
{
|
||||
if (!mapheaderinfo[mapnum])
|
||||
continue;
|
||||
if (mapheaderinfo[mapnum]->lumpnum == LUMPERROR)
|
||||
continue;
|
||||
if (!(mapheaderinfo[mapnum]->typeoflevel & tolflag))
|
||||
continue;
|
||||
if (mapheaderinfo[mapnum]->menuflags & LF2_HIDEINMENU)
|
||||
continue;
|
||||
break;
|
||||
mapnum = M_GetFirstLevelInList(&i, tol, cup);
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mapnum = M_GetFirstLevelInList(&i, tol, NULL);
|
||||
}
|
||||
|
||||
return mapnum;
|
||||
}
|
||||
|
|
@ -3853,7 +3850,7 @@ static void G_GetNextMap(void)
|
|||
UINT32 tolflag = G_TOLFlag(gametype);
|
||||
register INT16 cm;
|
||||
|
||||
if (gametyperules & GTR_CAMPAIGN)
|
||||
if (!(gametyperules & GTR_NOCUPSELECT))
|
||||
{
|
||||
cupheader_t *cup = mapheaderinfo[gamemap-1]->cup;
|
||||
UINT8 gettingresult = 0;
|
||||
|
|
@ -3880,6 +3877,12 @@ static void G_GetNextMap(void)
|
|||
|| (!marathonmode && M_MapLocked(cm+1)))
|
||||
continue;
|
||||
|
||||
// If the map is in multiple cups, only consider the first one valid.
|
||||
if (mapheaderinfo[cm]->cup != cup)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Grab the first valid after the map you're on
|
||||
if (gettingresult)
|
||||
{
|
||||
|
|
|
|||
20
src/k_kart.c
20
src/k_kart.c
|
|
@ -2824,16 +2824,16 @@ static fixed_t K_FlameShieldDashVar(INT32 val)
|
|||
INT16 K_GetSpindashChargeTime(player_t *player)
|
||||
{
|
||||
// more charge time for higher speed
|
||||
// Tails = 2s, Knuckles = 2.6s, Metal = 3.2s
|
||||
return (player->kartspeed + 8) * (TICRATE/5);
|
||||
// Tails = 1.7s, Knuckles = 2.2s, Metal = 2.7s
|
||||
return ((player->kartspeed + 8) * TICRATE) / 6;
|
||||
}
|
||||
|
||||
fixed_t K_GetSpindashChargeSpeed(player_t *player)
|
||||
{
|
||||
// more speed for higher weight & speed
|
||||
// Tails = +18.75%, Fang = +46.88%, Mighty = +46.88%, Metal = +56.25%
|
||||
// Tails = +16.94%, Fang = +34.94%, Mighty = +34.94%, Metal = +43.61%
|
||||
// (can be higher than this value when overcharged)
|
||||
const fixed_t val = ((player->kartspeed + player->kartweight) + 2) * (FRACUNIT/32);
|
||||
const fixed_t val = (10*FRACUNIT/277) + (((player->kartspeed + player->kartweight) + 2) * FRACUNIT) / 45;
|
||||
|
||||
// TODO: gametyperules
|
||||
return (gametype == GT_BATTLE) ? (4 * val) : val;
|
||||
|
|
@ -3099,9 +3099,9 @@ fixed_t K_GetKartAccel(player_t *player)
|
|||
if (gametype == GT_BATTLE && player->bumpers <= 0)
|
||||
k_accel *= 2;
|
||||
|
||||
// Marble Garden Top gets 800% accel
|
||||
// Marble Garden Top gets 1200% accel
|
||||
if (player->curshield == KSHIELD_TOP)
|
||||
k_accel *= 8;
|
||||
k_accel *= 12;
|
||||
|
||||
return FixedMul(k_accel, (FRACUNIT + player->accelboost) / 4);
|
||||
}
|
||||
|
|
@ -7732,7 +7732,10 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
player->tripwireState = TRIPSTATE_NONE;
|
||||
}
|
||||
|
||||
if (player->spectator == false)
|
||||
{
|
||||
K_KartEbrakeVisuals(player);
|
||||
}
|
||||
|
||||
if (K_GetKartButtons(player) & BT_BRAKE &&
|
||||
P_IsObjectOnGround(player->mo) &&
|
||||
|
|
@ -10277,10 +10280,13 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
{
|
||||
if (player->throwdir == -1)
|
||||
{
|
||||
const angle_t angle = P_IsObjectOnGround(player->mo) ?
|
||||
player->mo->angle : K_MomentumAngle(player->mo);
|
||||
|
||||
mobj_t *top = Obj_GardenTopDestroy(player);
|
||||
|
||||
// Fly off the Top at high speed
|
||||
P_Thrust(player->mo, K_MomentumAngle(player->mo), 80 * mapobjectscale);
|
||||
P_InstaThrust(player->mo, angle, player->speed + (80 * mapobjectscale));
|
||||
P_SetObjectMomZ(player->mo, player->mo->info->height / 8, true);
|
||||
|
||||
top->momx = player->mo->momx;
|
||||
|
|
|
|||
15
src/k_menu.h
15
src/k_menu.h
|
|
@ -686,8 +686,10 @@ void M_SetupRaceMenu(INT32 choice);
|
|||
|
||||
extern struct cupgrid_s {
|
||||
SINT8 x, y;
|
||||
SINT8 pageno;
|
||||
UINT8 numpages;
|
||||
size_t pageno;
|
||||
cupheader_t **builtgrid;
|
||||
size_t numpages;
|
||||
size_t cappages;
|
||||
tic_t previewanim;
|
||||
boolean grandprix; // Setup grand prix server after picking
|
||||
boolean netgame; // Start the game in an actual server
|
||||
|
|
@ -700,13 +702,16 @@ extern struct levellist_s {
|
|||
cupheader_t *selectedcup;
|
||||
INT16 choosemap;
|
||||
UINT8 newgametype;
|
||||
UINT32 typeoflevel;
|
||||
boolean cupmode;
|
||||
boolean timeattack; // Setup time attack menu after picking
|
||||
boolean netgame; // Start the game in an actual server
|
||||
} levellist;
|
||||
|
||||
boolean M_CanShowLevelInList(INT16 mapnum, UINT8 gt);
|
||||
INT16 M_CountLevelsToShowInList(UINT8 gt);
|
||||
INT16 M_GetFirstLevelInList(UINT8 gt);
|
||||
boolean M_CanShowLevelInList(INT16 mapnum, UINT32 tol, cupheader_t *cup);
|
||||
UINT16 M_CountLevelsToShowInList(UINT32 tol, cupheader_t *cup);
|
||||
UINT16 M_GetFirstLevelInList(UINT8 *i, UINT32 tol, cupheader_t *cup);
|
||||
UINT16 M_GetNextLevelInList(UINT16 map, UINT8 *i, UINT32 tol, cupheader_t *cup);
|
||||
|
||||
void M_LevelSelectInit(INT32 choice);
|
||||
void M_CupSelectHandler(INT32 choice);
|
||||
|
|
|
|||
|
|
@ -1924,27 +1924,48 @@ void M_DrawRaceDifficulty(void)
|
|||
|
||||
static void M_DrawCupPreview(INT16 y, cupheader_t *cup)
|
||||
{
|
||||
UINT8 i;
|
||||
UINT8 i = 0;
|
||||
INT16 maxlevels = M_CountLevelsToShowInList(levellist.typeoflevel, cup);
|
||||
INT16 x = -(cupgrid.previewanim % 82);
|
||||
INT16 add;
|
||||
INT16 map, start = M_GetFirstLevelInList(&i, levellist.typeoflevel, cup);
|
||||
UINT8 starti = i;
|
||||
|
||||
V_DrawFill(0, y, BASEVIDWIDTH, 54, 31);
|
||||
|
||||
if (cup && !M_CupLocked(cup))
|
||||
{
|
||||
i = (cupgrid.previewanim / 82) % cup->numlevels;
|
||||
add = (cupgrid.previewanim / 82) % maxlevels;
|
||||
map = start;
|
||||
while (add > 0)
|
||||
{
|
||||
map = M_GetNextLevelInList(map, &i, levellist.typeoflevel, cup);
|
||||
|
||||
if (map >= nummapheaders)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
add--;
|
||||
}
|
||||
while (x < BASEVIDWIDTH)
|
||||
{
|
||||
INT32 cupLevelNum = cup->cachedlevels[i];
|
||||
if (map >= nummapheaders)
|
||||
{
|
||||
map = start;
|
||||
i = starti;
|
||||
}
|
||||
|
||||
K_DrawMapThumbnail(
|
||||
(x+1)<<FRACBITS, (y+2)<<FRACBITS,
|
||||
80<<FRACBITS,
|
||||
0,
|
||||
cupLevelNum,
|
||||
map,
|
||||
NULL);
|
||||
|
||||
i = (i+1) % cup->numlevels;
|
||||
x += 82;
|
||||
|
||||
map = M_GetNextLevelInList(map, &i, levellist.typeoflevel, cup);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -1988,32 +2009,18 @@ static void M_DrawCupTitle(INT16 y, cupheader_t *cup)
|
|||
void M_DrawCupSelect(void)
|
||||
{
|
||||
UINT8 i, j;
|
||||
cupheader_t *cup = kartcupheaders;
|
||||
|
||||
while (cup)
|
||||
{
|
||||
if (cup->id == CUPMENU_CURSORID)
|
||||
break;
|
||||
cup = cup->next;
|
||||
}
|
||||
cupheader_t *cup = cupgrid.builtgrid[CUPMENU_CURSORID];
|
||||
|
||||
for (i = 0; i < CUPMENU_COLUMNS; i++)
|
||||
{
|
||||
for (j = 0; j < CUPMENU_ROWS; j++)
|
||||
{
|
||||
UINT8 id = (i + (j * CUPMENU_COLUMNS)) + (cupgrid.pageno * (CUPMENU_COLUMNS * CUPMENU_ROWS));
|
||||
cupheader_t *iconcup = kartcupheaders;
|
||||
size_t id = (i + (j * CUPMENU_COLUMNS)) + (cupgrid.pageno * (CUPMENU_COLUMNS * CUPMENU_ROWS));
|
||||
cupheader_t *iconcup = cupgrid.builtgrid[id];
|
||||
patch_t *patch = NULL;
|
||||
INT16 x, y;
|
||||
INT16 icony = 7;
|
||||
|
||||
while (iconcup)
|
||||
{
|
||||
if (iconcup->id == id)
|
||||
break;
|
||||
iconcup = iconcup->next;
|
||||
}
|
||||
|
||||
if (!iconcup)
|
||||
break;
|
||||
|
||||
|
|
@ -2181,9 +2188,9 @@ static void M_DrawLevelSelectBlock(INT16 x, INT16 y, INT16 map, boolean redblink
|
|||
|
||||
void M_DrawLevelSelect(void)
|
||||
{
|
||||
INT16 i;
|
||||
INT16 start = M_GetFirstLevelInList(levellist.newgametype);
|
||||
INT16 map = start;
|
||||
INT16 i = 0;
|
||||
UINT8 j = 0;
|
||||
INT16 map = M_GetFirstLevelInList(&j, levellist.typeoflevel, levellist.selectedcup);
|
||||
INT16 t = (64*menutransition.tics), tay = 0;
|
||||
INT16 y = 80 - (12 * levellist.y);
|
||||
boolean tatransition = ((menutransition.startmenu == &PLAY_TimeAttackDef || menutransition.endmenu == &PLAY_TimeAttackDef) && menutransition.tics);
|
||||
|
|
@ -2194,13 +2201,10 @@ void M_DrawLevelSelect(void)
|
|||
tay = t/2;
|
||||
}
|
||||
|
||||
for (i = 0; i < M_CountLevelsToShowInList(levellist.newgametype); i++)
|
||||
while (true)
|
||||
{
|
||||
INT16 lvlx = t, lvly = y;
|
||||
|
||||
while (!M_CanShowLevelInList(map, levellist.newgametype) && map < nummapheaders)
|
||||
map++;
|
||||
|
||||
if (map >= nummapheaders)
|
||||
break;
|
||||
|
||||
|
|
@ -2216,7 +2220,8 @@ void M_DrawLevelSelect(void)
|
|||
);
|
||||
|
||||
y += 72;
|
||||
map++;
|
||||
i++;
|
||||
map = M_GetNextLevelInList(map, &j, levellist.typeoflevel, levellist.selectedcup);
|
||||
}
|
||||
|
||||
M_DrawCupTitle(tay, levellist.selectedcup);
|
||||
|
|
|
|||
184
src/k_menufunc.c
184
src/k_menufunc.c
|
|
@ -3385,11 +3385,11 @@ void M_SetupDifficultySelect(INT32 choice)
|
|||
// M_CanShowLevelInList
|
||||
//
|
||||
// Determines whether to show a given map in the various level-select lists.
|
||||
// Set gt = -1 to ignore gametype.
|
||||
//
|
||||
boolean M_CanShowLevelInList(INT16 mapnum, UINT8 gt)
|
||||
boolean M_CanShowLevelInList(INT16 mapnum, UINT32 tol, cupheader_t *cup)
|
||||
{
|
||||
UINT32 tolflag = G_TOLFlag(gt);
|
||||
if (mapnum >= nummapheaders)
|
||||
return false;
|
||||
|
||||
// Does the map exist?
|
||||
if (!mapheaderinfo[mapnum])
|
||||
|
|
@ -3407,7 +3407,7 @@ boolean M_CanShowLevelInList(INT16 mapnum, UINT8 gt)
|
|||
return false; // not unlocked
|
||||
|
||||
// Check for TOL
|
||||
if (!(mapheaderinfo[mapnum]->typeoflevel & tolflag))
|
||||
if (!(mapheaderinfo[mapnum]->typeoflevel & tol))
|
||||
return false;
|
||||
|
||||
// Should the map be hidden?
|
||||
|
|
@ -3418,36 +3418,85 @@ boolean M_CanShowLevelInList(INT16 mapnum, UINT8 gt)
|
|||
if (levellist.timeattack && (mapheaderinfo[mapnum]->menuflags & LF2_NOTIMEATTACK))
|
||||
return false;
|
||||
|
||||
if (gametypedefaultrules[gt] & GTR_CAMPAIGN && levellist.selectedcup)
|
||||
{
|
||||
if (mapheaderinfo[mapnum]->cup != levellist.selectedcup)
|
||||
// Don't permit cup when no cup requested (also no dupes in time attack)
|
||||
if (levellist.cupmode && (levellist.timeattack || !cup) && mapheaderinfo[mapnum]->cup != cup)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Survived our checks.
|
||||
return true;
|
||||
}
|
||||
|
||||
INT16 M_CountLevelsToShowInList(UINT8 gt)
|
||||
UINT16 M_CountLevelsToShowInList(UINT32 tol, cupheader_t *cup)
|
||||
{
|
||||
INT16 mapnum, count = 0;
|
||||
INT16 i, count = 0;
|
||||
|
||||
for (mapnum = 0; mapnum < nummapheaders; mapnum++)
|
||||
if (M_CanShowLevelInList(mapnum, gt))
|
||||
if (cup)
|
||||
{
|
||||
for (i = 0; i < CUPCACHE_MAX; i++)
|
||||
{
|
||||
if (!M_CanShowLevelInList(cup->cachedlevels[i], tol, cup))
|
||||
continue;
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
for (i = 0; i < nummapheaders; i++)
|
||||
if (M_CanShowLevelInList(i, tol, NULL))
|
||||
count++;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
INT16 M_GetFirstLevelInList(UINT8 gt)
|
||||
UINT16 M_GetFirstLevelInList(UINT8 *i, UINT32 tol, cupheader_t *cup)
|
||||
{
|
||||
INT16 mapnum;
|
||||
INT16 mapnum = NEXTMAP_INVALID;
|
||||
|
||||
if (cup)
|
||||
{
|
||||
*i = 0;
|
||||
mapnum = NEXTMAP_INVALID;
|
||||
for (; *i < CUPCACHE_MAX; (*i)++)
|
||||
{
|
||||
if (!M_CanShowLevelInList(cup->cachedlevels[*i], tol, cup))
|
||||
continue;
|
||||
mapnum = cup->cachedlevels[*i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (mapnum = 0; mapnum < nummapheaders; mapnum++)
|
||||
if (M_CanShowLevelInList(mapnum, gt))
|
||||
return mapnum;
|
||||
if (M_CanShowLevelInList(mapnum, tol, NULL))
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return mapnum;
|
||||
}
|
||||
|
||||
UINT16 M_GetNextLevelInList(UINT16 map, UINT8 *i, UINT32 tol, cupheader_t *cup)
|
||||
{
|
||||
if (cup)
|
||||
{
|
||||
map = NEXTMAP_INVALID;
|
||||
(*i)++;
|
||||
for (; *i < CUPCACHE_MAX; (*i)++)
|
||||
{
|
||||
if (!M_CanShowLevelInList(cup->cachedlevels[*i], tol, cup))
|
||||
continue;
|
||||
map = cup->cachedlevels[*i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
map++;
|
||||
while (!M_CanShowLevelInList(map, tol, NULL) && map < nummapheaders)
|
||||
map++;
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
struct cupgrid_s cupgrid;
|
||||
|
|
@ -3455,7 +3504,7 @@ struct levellist_s levellist;
|
|||
|
||||
static void M_LevelSelectScrollDest(void)
|
||||
{
|
||||
UINT16 m = M_CountLevelsToShowInList(levellist.newgametype)-1;
|
||||
UINT16 m = M_CountLevelsToShowInList(levellist.typeoflevel, levellist.selectedcup)-1;
|
||||
|
||||
levellist.dest = (6*levellist.cursor);
|
||||
|
||||
|
|
@ -3469,26 +3518,77 @@ static void M_LevelSelectScrollDest(void)
|
|||
// Builds the level list we'll be using from the gametype we're choosing and send us to the apropriate menu.
|
||||
static void M_LevelListFromGametype(INT16 gt)
|
||||
{
|
||||
static boolean first = true;
|
||||
if (first || gt != levellist.newgametype)
|
||||
{
|
||||
levellist.newgametype = gt;
|
||||
levellist.typeoflevel = G_TOLFlag(gt);
|
||||
levellist.cupmode = (!(gametypedefaultrules[gt] & GTR_NOCUPSELECT));
|
||||
levellist.selectedcup = NULL;
|
||||
first = false;
|
||||
}
|
||||
|
||||
PLAY_CupSelectDef.prevMenu = currentMenu;
|
||||
|
||||
// Obviously go to Cup Select in gametypes that have cups.
|
||||
// Use a really long level select in gametypes that don't use cups.
|
||||
|
||||
if (levellist.newgametype == GT_RACE)
|
||||
if (levellist.cupmode)
|
||||
{
|
||||
cupheader_t *cup = kartcupheaders;
|
||||
UINT8 highestid = 0;
|
||||
size_t currentid = 0, highestunlockedid = 0;
|
||||
const size_t unitlen = sizeof(cupheader_t*) * (CUPMENU_COLUMNS * CUPMENU_ROWS);
|
||||
|
||||
// Make sure there's valid cups before going to this menu.
|
||||
if (cup == NULL)
|
||||
I_Error("Can you really call this a racing game, I didn't recieve any Cups on my pillow or anything");
|
||||
|
||||
if (!cupgrid.builtgrid)
|
||||
{
|
||||
cupgrid.cappages = 2;
|
||||
cupgrid.builtgrid = Z_Calloc(
|
||||
cupgrid.cappages * unitlen,
|
||||
PU_STATIC,
|
||||
cupgrid.builtgrid);
|
||||
|
||||
if (!cupgrid.builtgrid)
|
||||
{
|
||||
I_Error("M_LevelListFromGametype: Not enough memory to allocate builtgrid");
|
||||
}
|
||||
}
|
||||
memset(cupgrid.builtgrid, 0, cupgrid.cappages * unitlen);
|
||||
|
||||
while (cup)
|
||||
{
|
||||
if (!M_CountLevelsToShowInList(levellist.typeoflevel, cup))
|
||||
{
|
||||
// No valid maps, skip.
|
||||
cup = cup->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((currentid * sizeof(cupheader_t*)) >= cupgrid.cappages * unitlen)
|
||||
{
|
||||
// Double the size of the buffer, and clear the other stuff.
|
||||
const size_t firstlen = cupgrid.cappages * unitlen;
|
||||
cupgrid.builtgrid = Z_Realloc(cupgrid.builtgrid,
|
||||
firstlen * 2,
|
||||
PU_STATIC, NULL);
|
||||
|
||||
if (!cupgrid.builtgrid)
|
||||
{
|
||||
I_Error("M_LevelListFromGametype: Not enough memory to reallocate builtgrid");
|
||||
}
|
||||
|
||||
memset(cupgrid.builtgrid + firstlen, 0, firstlen);
|
||||
cupgrid.cappages *= 2;
|
||||
}
|
||||
|
||||
cupgrid.builtgrid[currentid] = cup;
|
||||
|
||||
if (!M_CupLocked(cup))
|
||||
{
|
||||
highestid = cup->id;
|
||||
highestunlockedid = currentid;
|
||||
if (Playing() && mapheaderinfo[gamemap-1] && mapheaderinfo[gamemap-1]->cup == cup)
|
||||
{
|
||||
cupgrid.x = cup->id % CUPMENU_COLUMNS;
|
||||
|
|
@ -3496,10 +3596,16 @@ static void M_LevelListFromGametype(INT16 gt)
|
|||
cupgrid.pageno = cup->id / (CUPMENU_COLUMNS * CUPMENU_ROWS);
|
||||
}
|
||||
}
|
||||
|
||||
currentid++;
|
||||
cup = cup->next;
|
||||
}
|
||||
|
||||
cupgrid.numpages = (highestid / (CUPMENU_COLUMNS * CUPMENU_ROWS)) + 1;
|
||||
cupgrid.numpages = (highestunlockedid / (CUPMENU_COLUMNS * CUPMENU_ROWS)) + 1;
|
||||
if (cupgrid.pageno >= cupgrid.numpages)
|
||||
{
|
||||
cupgrid.pageno = 0;
|
||||
}
|
||||
|
||||
PLAY_LevelSelectDef.prevMenu = &PLAY_CupSelectDef;
|
||||
M_SetupNextMenu(&PLAY_CupSelectDef, false);
|
||||
|
|
@ -3552,25 +3658,15 @@ void M_LevelSelectInit(INT32 choice)
|
|||
return;
|
||||
}
|
||||
|
||||
levellist.newgametype = currentMenu->menuitems[itemOn].mvar2;
|
||||
|
||||
M_LevelListFromGametype(levellist.newgametype);
|
||||
M_LevelListFromGametype(currentMenu->menuitems[itemOn].mvar2);
|
||||
}
|
||||
|
||||
void M_CupSelectHandler(INT32 choice)
|
||||
{
|
||||
cupheader_t *newcup = kartcupheaders;
|
||||
const UINT8 pid = 0;
|
||||
|
||||
(void)choice;
|
||||
|
||||
while (newcup)
|
||||
{
|
||||
if (newcup->id == CUPMENU_CURSORID)
|
||||
break;
|
||||
newcup = newcup->next;
|
||||
}
|
||||
|
||||
if (menucmd[pid].dpad_lr > 0)
|
||||
{
|
||||
cupgrid.x++;
|
||||
|
|
@ -3590,9 +3686,10 @@ void M_CupSelectHandler(INT32 choice)
|
|||
if (cupgrid.x < 0)
|
||||
{
|
||||
cupgrid.x = CUPMENU_COLUMNS-1;
|
||||
cupgrid.pageno--;
|
||||
if (cupgrid.pageno < 0)
|
||||
if (cupgrid.pageno == 0)
|
||||
cupgrid.pageno = cupgrid.numpages-1;
|
||||
else
|
||||
cupgrid.pageno--;
|
||||
}
|
||||
S_StartSound(NULL, sfx_s3k5b);
|
||||
M_SetMenuDelay(pid);
|
||||
|
|
@ -3617,6 +3714,8 @@ void M_CupSelectHandler(INT32 choice)
|
|||
|
||||
if (M_MenuConfirmPressed(pid) /*|| M_MenuButtonPressed(pid, MBT_START)*/)
|
||||
{
|
||||
cupheader_t *newcup = cupgrid.builtgrid[CUPMENU_CURSORID];
|
||||
|
||||
M_SetMenuDelay(pid);
|
||||
|
||||
if ((!newcup)
|
||||
|
|
@ -3688,7 +3787,7 @@ void M_CupSelectHandler(INT32 choice)
|
|||
else
|
||||
{
|
||||
// Keep cursor position if you select the same cup again, reset if it's a different cup
|
||||
if (!levellist.selectedcup || newcup->id != levellist.selectedcup->id)
|
||||
if (levellist.selectedcup != newcup)
|
||||
{
|
||||
levellist.cursor = 0;
|
||||
levellist.selectedcup = newcup;
|
||||
|
|
@ -3719,8 +3818,7 @@ void M_CupSelectTick(void)
|
|||
|
||||
void M_LevelSelectHandler(INT32 choice)
|
||||
{
|
||||
INT16 start = M_GetFirstLevelInList(levellist.newgametype);
|
||||
INT16 maxlevels = M_CountLevelsToShowInList(levellist.newgametype);
|
||||
INT16 maxlevels = M_CountLevelsToShowInList(levellist.typeoflevel, levellist.selectedcup);
|
||||
const UINT8 pid = 0;
|
||||
|
||||
(void)choice;
|
||||
|
|
@ -3751,20 +3849,20 @@ void M_LevelSelectHandler(INT32 choice)
|
|||
|
||||
if (M_MenuConfirmPressed(pid) /*|| M_MenuButtonPressed(pid, MBT_START)*/)
|
||||
{
|
||||
INT16 map = start;
|
||||
UINT8 i = 0;
|
||||
INT16 map = M_GetFirstLevelInList(&i, levellist.typeoflevel, levellist.selectedcup);
|
||||
INT16 add = levellist.cursor;
|
||||
|
||||
M_SetMenuDelay(pid);
|
||||
|
||||
while (add > 0)
|
||||
{
|
||||
map++;
|
||||
|
||||
while (!M_CanShowLevelInList(map, levellist.newgametype) && map < nummapheaders)
|
||||
map++;
|
||||
map = M_GetNextLevelInList(map, &i, levellist.typeoflevel, levellist.selectedcup);
|
||||
|
||||
if (map >= nummapheaders)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
add--;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -821,7 +821,7 @@ static void K_InitRoulette(itemroulette_t *const roulette)
|
|||
roulette->secondToFirst = 0;
|
||||
|
||||
roulette->elapsed = 0;
|
||||
roulette->tics = roulette->speed = ROULETTE_SPEED_FASTEST; // Some default speed
|
||||
roulette->tics = roulette->speed = ROULETTE_SPEED_TIMEATTACK; // Some default speed
|
||||
|
||||
roulette->active = true;
|
||||
roulette->eggman = false;
|
||||
|
|
@ -981,7 +981,7 @@ static void K_CalculateRouletteSpeed(itemroulette_t *const roulette)
|
|||
// Combine our two factors together.
|
||||
total = min(FRACUNIT, (frontRun / 2) + (progress / 2));
|
||||
|
||||
if (leveltime < starttime + 20*TICRATE)
|
||||
if (leveltime < starttime + 30*TICRATE)
|
||||
{
|
||||
// Don't impact as much at the start.
|
||||
// This makes it so that everyone gets to enjoy the lowest speed at the start.
|
||||
|
|
@ -991,7 +991,7 @@ static void K_CalculateRouletteSpeed(itemroulette_t *const roulette)
|
|||
}
|
||||
else
|
||||
{
|
||||
const fixed_t lerp = FixedDiv(leveltime - starttime, 20*TICRATE);
|
||||
const fixed_t lerp = FixedDiv(leveltime - starttime, 30*TICRATE);
|
||||
total = FRACUNIT + FixedMul(lerp, total - FRACUNIT);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -554,6 +554,63 @@ void K_ProcessTerrainEffect(mobj_t *mo)
|
|||
}
|
||||
}
|
||||
|
||||
// Spring
|
||||
if (terrain->springStrength)
|
||||
{
|
||||
sector_t *sector = player->mo->subsector->sector;
|
||||
|
||||
const pslope_t *slope;
|
||||
angle_t angle = 0;
|
||||
|
||||
fixed_t co = FRACUNIT;
|
||||
fixed_t si = 0;
|
||||
|
||||
// FIXME: come up with a better way to get the touched
|
||||
// texture's slope to this function. At least this
|
||||
// will work for 90% of scenarios...
|
||||
|
||||
if (player->mo->eflags & MFE_VERTICALFLIP)
|
||||
{
|
||||
if (player->mo->ceilingrover != NULL)
|
||||
{
|
||||
slope = *player->mo->ceilingrover->b_slope;
|
||||
}
|
||||
else
|
||||
{
|
||||
slope = sector->c_slope;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (player->mo->floorrover != NULL)
|
||||
{
|
||||
slope = *player->mo->ceilingrover->t_slope;
|
||||
}
|
||||
else
|
||||
{
|
||||
slope = sector->f_slope;
|
||||
}
|
||||
}
|
||||
|
||||
if (slope)
|
||||
{
|
||||
const angle_t fa = (slope->zangle >> ANGLETOFINESHIFT);
|
||||
|
||||
co = FINECOSINE(fa) * P_MobjFlip(player->mo);
|
||||
si = -(FINESINE(fa));
|
||||
|
||||
angle = slope->xydirection;
|
||||
}
|
||||
|
||||
P_DoSpringEx(player->mo, mapobjectscale,
|
||||
FixedMul(terrain->springStrength, co),
|
||||
FixedMul(terrain->springStrength, si),
|
||||
angle, terrain->springStarColor);
|
||||
|
||||
sector->soundorg.z = player->mo->z;
|
||||
S_StartSound(§or->soundorg, sfx_s3kb1);
|
||||
}
|
||||
|
||||
// Bumpy floor
|
||||
if (terrain->flags & TRF_STAIRJANK)
|
||||
{
|
||||
|
|
@ -1487,6 +1544,8 @@ static void K_TerrainDefaults(terrain_t *terrain)
|
|||
terrain->trickPanel = 0;
|
||||
terrain->speedPad = 0;
|
||||
terrain->speedPadAngle = 0;
|
||||
terrain->springStrength = 0;
|
||||
terrain->springStarColor = SKINCOLOR_NONE;
|
||||
terrain->flags = 0;
|
||||
}
|
||||
|
||||
|
|
@ -1565,6 +1624,27 @@ static void K_ParseTerrainParameter(size_t i, char *param, char *val)
|
|||
{
|
||||
terrain->speedPadAngle = FixedAngle(FLOAT_TO_FIXED(atof(val)));
|
||||
}
|
||||
else if (stricmp(param, "springStrength") == 0)
|
||||
{
|
||||
const double fval = atof(val);
|
||||
|
||||
if (fpclassify(fval) == FP_ZERO)
|
||||
{
|
||||
terrain->springStrength = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Springs increase in stength by 1.6 times the
|
||||
// previous strength. Grey spring is 25 and
|
||||
// 25/1.6 = 15.625
|
||||
terrain->springStrength =
|
||||
FLOAT_TO_FIXED(15.625 * pow(1.6, fval));
|
||||
}
|
||||
}
|
||||
else if (stricmp(param, "springStarColor") == 0)
|
||||
{
|
||||
terrain->springStarColor = get_number(val);
|
||||
}
|
||||
else if (stricmp(param, "floorClip") == 0)
|
||||
{
|
||||
terrain->floorClip = FLOAT_TO_FIXED(atof(val));
|
||||
|
|
|
|||
|
|
@ -116,6 +116,8 @@ struct terrain_t
|
|||
fixed_t trickPanel; // Trick panel strength
|
||||
fixed_t speedPad; // Speed pad strength
|
||||
angle_t speedPadAngle; // Speed pad angle
|
||||
fixed_t springStrength; // Spring strength
|
||||
UINT16 springStarColor; // Spring star color
|
||||
fixed_t floorClip; // Offset for sprites on this ground
|
||||
UINT32 flags; // Flag values (see: terrain_flags_t)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ boolean P_IsObjectInGoop(mobj_t *mo);
|
|||
boolean P_IsObjectOnGround(mobj_t *mo);
|
||||
boolean P_IsObjectOnGroundIn(mobj_t *mo, sector_t *sec);
|
||||
boolean P_IsObjectOnRealGround(mobj_t *mo, sector_t *sec); // SRB2Kart
|
||||
#define P_IsObjectFlipped(o) ((o)->eflags & MFE_VERTICALFLIP)
|
||||
#define P_IsObjectFlipped(o) (((o)->eflags & MFE_VERTICALFLIP) == MFE_VERTICALFLIP)
|
||||
boolean P_InQuicksand(mobj_t *mo);
|
||||
boolean P_PlayerHitFloor(player_t *player, boolean fromAir, angle_t oldPitch, angle_t oldRoll);
|
||||
|
||||
|
|
@ -473,6 +473,7 @@ fixed_t P_FloorzAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height);
|
|||
fixed_t P_CeilingzAtPos(fixed_t x, fixed_t y, fixed_t z, fixed_t height);
|
||||
BlockItReturn_t PIT_PushableMoved(mobj_t *thing);
|
||||
|
||||
void P_DoSpringEx(mobj_t *object, fixed_t scaleVal, fixed_t vertispeed, fixed_t horizspeed, angle_t finalAngle, UINT16 starcolor);
|
||||
boolean P_DoSpring(mobj_t *spring, mobj_t *object);
|
||||
|
||||
fixed_t P_GetFOFTopZAt (ffloor_t *rover, fixed_t x, fixed_t y);
|
||||
|
|
|
|||
167
src/p_map.c
167
src/p_map.c
|
|
@ -268,6 +268,96 @@ static boolean P_SpecialIsLinedefCrossType(line_t *ld)
|
|||
return linedefcrossspecial;
|
||||
}
|
||||
|
||||
void
|
||||
P_DoSpringEx
|
||||
( mobj_t * object,
|
||||
fixed_t scaleVal,
|
||||
fixed_t vertispeed,
|
||||
fixed_t horizspeed,
|
||||
angle_t finalAngle,
|
||||
UINT16 starcolor)
|
||||
{
|
||||
if (horizspeed < 0)
|
||||
{
|
||||
horizspeed = -(horizspeed);
|
||||
finalAngle += ANGLE_180;
|
||||
}
|
||||
|
||||
object->standingslope = NULL; // Okay, now we know it's not going to be relevant - no launching off at silly angles for you.
|
||||
object->terrain = NULL;
|
||||
|
||||
object->eflags |= MFE_SPRUNG; // apply this flag asap!
|
||||
|
||||
if ((vertispeed < 0) ^ P_IsObjectFlipped(object))
|
||||
vertispeed *= 2;
|
||||
|
||||
if (vertispeed)
|
||||
{
|
||||
object->momz = FixedMul(vertispeed, scaleVal);
|
||||
}
|
||||
|
||||
if (horizspeed)
|
||||
{
|
||||
fixed_t finalSpeed = FixedMul(horizspeed, scaleVal);
|
||||
fixed_t objectSpeed;
|
||||
|
||||
if (object->player)
|
||||
objectSpeed = object->player->speed;
|
||||
else
|
||||
objectSpeed = R_PointToDist2(0, 0, object->momx, object->momy);
|
||||
|
||||
if (!vertispeed)
|
||||
{
|
||||
// Scale to gamespeed
|
||||
finalSpeed = FixedMul(finalSpeed, K_GetKartGameSpeedScalar(gamespeed));
|
||||
|
||||
// Reflect your momentum angle against the surface of horizontal springs.
|
||||
// This makes it a bit more interesting & unique than just being a speed boost in a pre-defined direction
|
||||
if (object->momx || object->momy)
|
||||
{
|
||||
finalAngle = K_ReflectAngle(
|
||||
R_PointToAngle2(0, 0, object->momx, object->momy), finalAngle,
|
||||
objectSpeed, finalSpeed
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Horizontal speed is used as a minimum thrust, not a direct replacement
|
||||
finalSpeed = max(objectSpeed, finalSpeed);
|
||||
|
||||
P_InstaThrust(object, finalAngle, finalSpeed);
|
||||
}
|
||||
|
||||
if (object->player)
|
||||
{
|
||||
K_TumbleInterrupt(object->player);
|
||||
P_ResetPlayer(object->player);
|
||||
|
||||
object->player->springstars = max(abs(vertispeed), horizspeed) / FRACUNIT / 2;
|
||||
object->player->springcolor = starcolor;
|
||||
|
||||
// Less friction when hitting springs
|
||||
if (!object->player->tiregrease)
|
||||
{
|
||||
UINT8 i;
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
mobj_t *grease;
|
||||
grease = P_SpawnMobj(object->x, object->y, object->z, MT_TIREGREASE);
|
||||
P_SetTarget(&grease->target, object);
|
||||
grease->angle = K_MomentumAngle(object);
|
||||
grease->extravalue1 = i;
|
||||
K_ReduceVFX(grease, object->player);
|
||||
}
|
||||
}
|
||||
|
||||
if (object->player->tiregrease < greasetics)
|
||||
{
|
||||
object->player->tiregrease = greasetics;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// P_DoSpring
|
||||
//
|
||||
|
|
@ -282,8 +372,8 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
|
|||
fixed_t vertispeed = spring->info->mass;
|
||||
fixed_t horizspeed = spring->info->damage;
|
||||
UINT16 starcolor = (spring->info->painchance % numskincolors);
|
||||
fixed_t savemomx = 0;
|
||||
fixed_t savemomy = 0;
|
||||
fixed_t savemomx = object->momx;
|
||||
fixed_t savemomy = object->momy;
|
||||
statenum_t raisestate = spring->info->raisestate;
|
||||
|
||||
// Object was already sprung this tic
|
||||
|
|
@ -312,18 +402,11 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
|
|||
return false;
|
||||
}
|
||||
|
||||
object->standingslope = NULL; // Okay, now we know it's not going to be relevant - no launching off at silly angles for you.
|
||||
object->terrain = NULL;
|
||||
|
||||
object->eflags |= MFE_SPRUNG; // apply this flag asap!
|
||||
spring->flags &= ~(MF_SOLID|MF_SPECIAL); // De-solidify
|
||||
|
||||
if (spring->eflags & MFE_VERTICALFLIP)
|
||||
vertispeed *= -1;
|
||||
|
||||
if ((spring->eflags ^ object->eflags) & MFE_VERTICALFLIP)
|
||||
vertispeed *= 2;
|
||||
|
||||
// Vertical springs teleport you on TOP of them.
|
||||
if (vertispeed > 0)
|
||||
{
|
||||
|
|
@ -355,43 +438,11 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
|
|||
P_TryMove(object, spring->x + offx, spring->y + offy, true, NULL);
|
||||
}
|
||||
|
||||
if (vertispeed)
|
||||
{
|
||||
object->momz = FixedMul(vertispeed, scaleVal);
|
||||
}
|
||||
object->momx = savemomx;
|
||||
object->momy = savemomy;
|
||||
|
||||
if (horizspeed)
|
||||
{
|
||||
angle_t finalAngle = spring->angle;
|
||||
fixed_t finalSpeed = FixedMul(horizspeed, scaleVal);
|
||||
fixed_t objectSpeed;
|
||||
|
||||
if (object->player)
|
||||
objectSpeed = object->player->speed;
|
||||
else
|
||||
objectSpeed = R_PointToDist2(0, 0, savemomx, savemomy);
|
||||
|
||||
if (!vertispeed)
|
||||
{
|
||||
// Scale to gamespeed
|
||||
finalSpeed = FixedMul(finalSpeed, K_GetKartGameSpeedScalar(gamespeed));
|
||||
|
||||
// Reflect your momentum angle against the surface of horizontal springs.
|
||||
// This makes it a bit more interesting & unique than just being a speed boost in a pre-defined direction
|
||||
if (savemomx || savemomy)
|
||||
{
|
||||
finalAngle = K_ReflectAngle(
|
||||
R_PointToAngle2(0, 0, savemomx, savemomy), finalAngle,
|
||||
objectSpeed, finalSpeed
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Horizontal speed is used as a minimum thrust, not a direct replacement
|
||||
finalSpeed = max(objectSpeed, finalSpeed);
|
||||
|
||||
P_InstaThrust(object, finalAngle, finalSpeed);
|
||||
}
|
||||
P_DoSpringEx(object, scaleVal, vertispeed, horizspeed,
|
||||
spring->angle, starcolor);
|
||||
|
||||
// Re-solidify
|
||||
spring->flags |= (spring->info->flags & (MF_SPRING|MF_SPECIAL));
|
||||
|
|
@ -403,32 +454,6 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
|
|||
P_SetTarget(&spring->target, object);
|
||||
}
|
||||
|
||||
K_TumbleInterrupt(object->player);
|
||||
P_ResetPlayer(object->player);
|
||||
|
||||
object->player->springstars = max(vertispeed, horizspeed) / FRACUNIT / 2;
|
||||
object->player->springcolor = starcolor;
|
||||
|
||||
// Less friction when hitting springs
|
||||
if (!object->player->tiregrease)
|
||||
{
|
||||
UINT8 i;
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
mobj_t *grease;
|
||||
grease = P_SpawnMobj(object->x, object->y, object->z, MT_TIREGREASE);
|
||||
P_SetTarget(&grease->target, object);
|
||||
grease->angle = K_MomentumAngle(object);
|
||||
grease->extravalue1 = i;
|
||||
K_ReduceVFX(grease, object->player);
|
||||
}
|
||||
}
|
||||
|
||||
if (object->player->tiregrease < greasetics)
|
||||
{
|
||||
object->player->tiregrease = greasetics;
|
||||
}
|
||||
|
||||
if (spring->type == MT_POGOSPRING)
|
||||
{
|
||||
if (spring->reactiontime == 0)
|
||||
|
|
|
|||
15
src/p_mobj.h
15
src/p_mobj.h
|
|
@ -275,14 +275,17 @@ struct mobj_t
|
|||
// List: thinker links.
|
||||
thinker_t thinker;
|
||||
|
||||
mobjtype_t type;
|
||||
const mobjinfo_t *info; // &mobjinfo[mobj->type]
|
||||
|
||||
// Info for drawing: position.
|
||||
fixed_t x, y, z;
|
||||
// --- Please make sure you keep the fields up to this
|
||||
// --- point in sync with degenmobj_t.
|
||||
|
||||
fixed_t old_x, old_y, old_z; // position interpolation
|
||||
fixed_t old_x2, old_y2, old_z2;
|
||||
|
||||
mobjtype_t type;
|
||||
const mobjinfo_t *info; // &mobjinfo[mobj->type]
|
||||
|
||||
// More list: links in sector (if needed)
|
||||
mobj_t *snext;
|
||||
mobj_t **sprev; // killough 8/11/98: change to ptr-to-ptr
|
||||
|
|
@ -428,14 +431,14 @@ struct precipmobj_t
|
|||
// List: thinker links.
|
||||
thinker_t thinker;
|
||||
|
||||
mobjtype_t type;
|
||||
const mobjinfo_t *info; // &mobjinfo[mobj->type]
|
||||
|
||||
// Info for drawing: position.
|
||||
fixed_t x, y, z;
|
||||
fixed_t old_x, old_y, old_z; // position interpolation
|
||||
fixed_t old_x2, old_y2, old_z2;
|
||||
|
||||
mobjtype_t type;
|
||||
const mobjinfo_t *info; // &mobjinfo[mobj->type]
|
||||
|
||||
// More list: links in sector (if needed)
|
||||
precipmobj_t *snext;
|
||||
precipmobj_t **sprev; // killough 8/11/98: change to ptr-to-ptr
|
||||
|
|
|
|||
|
|
@ -7796,13 +7796,9 @@ UINT8 P_InitMapData(boolean existingmapheaders)
|
|||
if (strcasecmp(cup->levellist[j], name) != 0)
|
||||
continue;
|
||||
|
||||
// Only panic about back-reference for non-bonus material.
|
||||
if (j < MAXLEVELLIST)
|
||||
{
|
||||
if (mapheaderinfo[i]->cup)
|
||||
I_Error("P_InitMapData: Map %s cannot appear in cups multiple times! (First in %s, now in %s)", name, mapheaderinfo[i]->cup->name, cup->name);
|
||||
// Have a map recognise the first cup it's a part of.
|
||||
if (!mapheaderinfo[i]->cup)
|
||||
mapheaderinfo[i]->cup = cup;
|
||||
}
|
||||
|
||||
cup->cachedlevels[j] = i;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue